void GenStructure()

in TssCodeGen/src/CGenDotNet.cs [260:504]


        void GenStructure(TpmStruct s)
        {
            bool hasBase = s.DerivedFrom != null;   // Has a non-trivial base class?
            string className = s.Name;
            string classBases = hasBase ? s.DerivedFrom.Name : "TpmStructureBase";

            // Here "implements" is as opposed to "inherits and overrides"
            bool implementsUnionInterfaces = !s.IsCmdStruct() && !hasBase && s.ContainingUnions.Count > 0;
            Debug.Assert(s.DerivedFrom == null || s.DerivedFrom.ContainingUnions.Count >= s.ContainingUnions.Count);
            if (implementsUnionInterfaces)
            {
                foreach(TpmUnion u in s.ContainingUnions)
                    classBases += ", " + u.Name;
            }

            WriteComment(s);
            Write("[DataContract]");
            var knownTypes = GetKnownTypes(s);
            foreach (TpmType kt in knownTypes)
                Write($"[KnownType(typeof({kt.Name}))]");

            string specName = s.Info.IsRequest() ? s.SpecName.Substring(5).Replace("_REQUEST", "_In")
                            : s.Info.IsResponse() ? s.SpecName.Replace("Response", "_Out")
                            : s.SpecName;
            Write($"[SpecTypeName(\"{specName}\")]");

            Write($"public partial class {className}: {classBases}");
            TabIn("{");

            if (s.DerivedFrom != null)
            {
                Debug.Assert(!s.IsCmdStruct());
                //---------------------------------------
                // Constructors
                var fields = new List<StructField>();
                TpmStruct b = s;
                do {
                    fields.AddRange(b.NonTagFields);
                    b = b.DerivedFrom;
                } while (b != null);

                // Default constructor
                Write($"public {className}() {{}}");
                Write("");

                if (fields.Count != 0)
                {
                    // Copy-constructor
                    WriteLine("public {0}({0} _{0}) : base(_{0}) {{}}", className);
                    Write("");

                    // Member-wise constructor
                    GenMemeberwiseCtorPrototype(className, fields);
                    if (fields.Count == 1)
                    {
                        Write($" : base(_{fields.First().Name}) {{}}");
                    }
                    else
                    {
                        string baseInitList = string.Join(", ", fields.ConvertAll(f => "_" + f.Name));
                        Write("");
                        Write($"    : base({baseInitList})");
                        Write("{}");
                    }
                    Write("");
                }

                GenGetUnionSelector(s, implementsUnionInterfaces);
                GenCloningMethods(s.Name);

                // end of class
                TabOut("}");
                return;
            } // if (s.DerivedFrom != null)

            //
            // Member fields
            //

            bool onlyStaticFields = true;
            int idx = 0;
            foreach (StructField f in s.Fields)
            {
                var tag = f.SizeTagField;
                if (f.SizedField == null)
                {
                    WriteComment(f);
                    WriteConstraints(f);
                }
                onlyStaticFields = false;

                switch(f.MarshalType)
                {
                    case MarshalType.ArrayCount: 
                    case MarshalType.LengthOfStruct:
                        --idx;
                        break;
                    case MarshalType.UnionSelector:
                    {
                        Debug.Assert(f.RelatedUnion.MarshalType == MarshalType.UnionObject); 
                        Debug.Assert(f.RelatedUnion.UnionSelector == f);
                        var unionField = f.RelatedUnion;
                        var u = (TpmUnion)unionField.Type;
                        Write($"[MarshalAs({idx}, MarshalType.UnionSelector)]");
                        TabIn($"public {f.TypeName} {f.Name} {{");
                        if (u.NullSelector == null)
                            Write($"get {{ return {unionField.Name}.GetUnionSelector(); }}");
                        else
                            Write($"get {{ return {unionField.Name} != null ? {unionField.Name}.GetUnionSelector() : {u.NullSelector.QualifiedName}; }}");
                        TabOut("}"); // property
                        break;
                    }
                    case MarshalType.Normal:
                    case MarshalType.SizedStruct:
                    {
                        if (tag == null)
                            Write($"[MarshalAs({idx})]");
                        else
                            Write($"[MarshalAs({idx}, MarshalType.SizedStruct, \"{tag.Name}\", {tag.Type.GetSize()})]");
                        WriteFieldDef(f, " { get; set; }");
                        break;
                    }
                    case MarshalType.UnionObject:
                    {
                        UnionField fx = (UnionField) f;
                        Write($"[MarshalAs({idx}, MarshalType.Union, \"{fx.UnionSelector.Name}\")]");
                        WriteFieldDef(f, " { get; set; }");
                        break;
                    }
                    case MarshalType.VariableLengthArray:
                    case MarshalType.SpecialVariableLengthArray:
                    {
                        string marshalType = Enum.GetName(typeof(MarshalType), f.MarshalType);
                        Write($"[MarshalAs({idx}, MarshalType.{marshalType}, \"{tag.Name}\", {tag.Type.GetSize()})]");
                        WriteFieldDef(f);
                        break;
                    }
                    case MarshalType.EncryptedVariableLengthArray:
                    {
                        Write($"[MarshalAs({idx}, MarshalType.EncryptedVariableLengthArray)]");
                        WriteFieldDef(f);
                        break;
                    }
                    case MarshalType.ConstantValue:
                    {
                        string val = TargetLang.TranslateConstExpr(f.Domain[0, Constraint.Type.Single]);
                        Write($"[MarshalAs({idx})]");
                        WriteFieldDef(f, $" = {val};");
                        break;
                    }
                    default:
                        throw new Exception();
                }
                ++idx;
            } // foreach field

            if (onlyStaticFields && s.Fields.Count > 0)
            {
                // end of class
                TabOut("}");
                return;
            }

            // Default constructor
            var fieldsToInit = s.NonDefaultInitFields;
            Write("");
            Write($"public {className}()", false);
            if (fieldsToInit.Count() == 0)
            {
                Write(" {}");
            }
            else if (fieldsToInit.Count() == 1)
            {
                var f = fieldsToInit[0];
                Write($" {{ {f.Name} = {f.GetInitVal()}; }}");
            }
            else
            {
                TabIn("{");
                foreach (StructField f in fieldsToInit)
                {
                    Write($"{f.Name} = {f.GetInitVal()};");
                }
                TabOut("}");
            }

            // Copy constructor
            if (!s.Info.IsRequest())
            {
                var fields = s.NonTagFields;
                if (fields.Count() != 0)
                {
                    Write("");
                    Write($"public {className}({className} src)", false);
                    if (fields.Count() == 1 && s.SpecName != "TPM_HANDLE")
                    {
                        string field = fields.First().Name;
                        Write($" {{ {field} = src.{field}; }}");
                    }
                    else
                    {
                        Write("");
                        TabIn("{");
                        foreach (StructField f in fields)
                            Write($"{f.Name} = src.{f.Name};");

                        // special case
                        if (s.SpecName == "TPM_HANDLE")
                        {
                            Write("Auth = src.Auth;");
                            TabIn("if (src.Name != null)");
                            Write("Name = Globs.CopyData(src.Name);");
                            TabOut();
                        }
                        TabOut("}");
                    }
                }
            }

            // Member-wise constructor
            if (!s.Info.IsResponse())
            {
                var fields = s.NonTagFields;
                if (fields.Count() != 0)
                {
                    GenMemeberwiseCtorPrototype(className, fields);
                    if (fields.Count() == 1)
                    {
                        string fName = fields.First().Name;
                        Write($" {{ {fName} = _{fName}; }}");
                    }
                    else
                    {
                        TabIn("{");
                        foreach (StructField f in fields)
                            Write($"{f.Name} = _{f.Name};");
                        TabOut("}");
                    }
                }
            }

            GenGetUnionSelector(s);
            GenCloningMethods(s.Name);
            TabOut("}"); // end of class
        } // GenStructure()