static int GetValueTypeSize(Type type, List <Type> fieldTypes, bool is_64_bits, Generator generator) { int size = 0; int maxElementSize = 1; if (type.IsExplicitLayout) { // Find the maximum of "field size + field offset" for each field. foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { #if BGENERATOR var fieldOffset = generator.AttributeManager.GetCustomAttribute <FieldOffsetAttribute> (field); #else var fieldOffset = (FieldOffsetAttribute)Attribute.GetCustomAttribute(field, typeof(FieldOffsetAttribute)); #endif var elementSize = 0; GetValueTypeSize(type, field.FieldType, fieldTypes, is_64_bits, ref elementSize, ref maxElementSize, generator); size = Math.Max(size, elementSize + fieldOffset.Value); } } else { GetValueTypeSize(type, type, fieldTypes, is_64_bits, ref size, ref maxElementSize, generator); } if (size % maxElementSize != 0) { size += (maxElementSize - size % maxElementSize); } return(size); }
internal static MemberInfo[] GetInstanceFieldsAndProperties(Type type, bool publicOnly) { #if WINRT System.Collections.Generic.List<MemberInfo> members = new System.Collections.Generic.List<MemberInfo>(); foreach(FieldInfo field in type.GetRuntimeFields()) { if(field.IsStatic) continue; if(field.IsPublic || !publicOnly) members.Add(field); } foreach(PropertyInfo prop in type.GetRuntimeProperties()) { MethodInfo getter = Helpers.GetGetMethod(prop, true, true); if(getter == null || getter.IsStatic) continue; if(getter.IsPublic || !publicOnly) members.Add(prop); } return members.ToArray(); #else BindingFlags flags = publicOnly ? BindingFlags.Public | BindingFlags.Instance : BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic; PropertyInfo[] props = type.GetProperties(flags); FieldInfo[] fields = type.GetFields(flags); MemberInfo[] members = new MemberInfo[fields.Length + props.Length]; props.CopyTo(members, 0); fields.CopyTo(members, props.Length); return members; #endif }
internal static object ParseEnum(Type type, string value) { #if FEAT_IKVM FieldInfo[] fields = type.GetFields(); foreach (FieldInfo field in fields) { if (string.Equals(field.Name, value, StringComparison.OrdinalIgnoreCase)) return field.GetRawConstantValue(); } throw new ArgumentException("Enum value could not be parsed: " + value + ", " + type.FullName); #else return Enum.Parse(type, value, true); #endif }
protected IEnumerable <FieldInfo> GetFields(Type t) { foreach (var fi in t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) { if (!fi.IsPublic) { continue; } var ft = fi.FieldType; if (!IsSupported(ft)) { Delayed.Add(ErrorHelper.CreateWarning(1050, $"Field `{fi}` is not generated because of field type `{ft}` is not supported.")); continue; } yield return(fi); } }
public void OutlineType() { bool first; OutlineAttributes(); o.Write(GetTypeVisibility(t)); if (t.IsClass && !t.IsSubclassOf(type_multicast_delegate)) { if (t.IsSealed) { o.Write(t.IsAbstract ? " static" : " sealed"); } else if (t.IsAbstract) { o.Write(" abstract"); } } o.Write(" "); o.Write(GetTypeKind(t)); o.Write(" "); Type [] interfaces = (Type [])Comparer.Sort(TypeGetInterfaces(t, declared_only)); Type parent = t.BaseType; if (t.IsSubclassOf(type_multicast_delegate)) { MethodInfo method; method = t.GetMethod("Invoke"); o.Write(FormatType(method.ReturnType)); o.Write(" "); o.Write(GetTypeName(t)); o.Write(" ("); OutlineParams(method.GetParameters()); o.Write(")"); WriteGenericConstraints(t.GetGenericArguments()); o.WriteLine(";"); return; } o.Write(GetTypeName(t)); if (((parent != null && parent != type_object && parent != type_value_type) || interfaces.Length != 0) && !t.IsEnum) { first = true; o.Write(" : "); if (parent != null && parent != type_object && parent != type_value_type) { o.Write(FormatType(parent)); first = false; } foreach (Type intf in interfaces) { if (!first) { o.Write(", "); } first = false; o.Write(FormatType(intf)); } } if (t.IsEnum) { Type underlyingType = t.GetEnumUnderlyingType(); if (underlyingType != type_int) { o.Write(" : {0}", FormatType(underlyingType)); } } WriteGenericConstraints(t.GetGenericArguments()); o.WriteLine(" {"); o.Indent++; if (t.IsEnum) { bool is_first = true; foreach (FieldInfo fi in t.GetFields(BindingFlags.Public | BindingFlags.Static)) { if (!is_first) { o.WriteLine(","); } is_first = false; o.Write(fi.Name); } o.WriteLine(); o.Indent--; o.WriteLine("}"); return; } first = true; foreach (ConstructorInfo ci in t.GetConstructors(DefaultFlags)) { if (!ShowMember(ci)) { continue; } if (first) { o.WriteLine(); } first = false; OutlineMemberAttribute(ci); OutlineConstructor(ci); o.WriteLine(); } first = true; foreach (MethodInfo m in Comparer.Sort(t.GetMethods(DefaultFlags))) { if (!ShowMember(m)) { continue; } if ((m.Attributes & MethodAttributes.SpecialName) != 0) { continue; } if (first) { o.WriteLine(); } first = false; OutlineMemberAttribute(m); OutlineMethod(m); o.WriteLine(); } first = true; foreach (MethodInfo m in t.GetMethods(DefaultFlags)) { if (!ShowMember(m)) { continue; } if ((m.Attributes & MethodAttributes.SpecialName) == 0) { continue; } if (!(m.Name.StartsWith("op_"))) { continue; } if (first) { o.WriteLine(); } first = false; OutlineMemberAttribute(m); OutlineOperator(m); o.WriteLine(); } first = true; foreach (PropertyInfo pi in Comparer.Sort(t.GetProperties(DefaultFlags))) { if (!((pi.CanRead && ShowMember(pi.GetGetMethod(true))) || (pi.CanWrite && ShowMember(pi.GetSetMethod(true))))) { continue; } if (first) { o.WriteLine(); } first = false; OutlineMemberAttribute(pi); OutlineProperty(pi); o.WriteLine(); } first = true; foreach (FieldInfo fi in t.GetFields(DefaultFlags)) { if (!ShowMember(fi)) { continue; } if (first) { o.WriteLine(); } first = false; OutlineMemberAttribute(fi); OutlineField(fi); o.WriteLine(); } first = true; foreach (EventInfo ei in Comparer.Sort(t.GetEvents(DefaultFlags))) { if (!ShowMember(ei.GetAddMethod(true))) { continue; } if (first) { o.WriteLine(); } first = false; OutlineMemberAttribute(ei); OutlineEvent(ei); o.WriteLine(); } first = true; foreach (Type ntype in Comparer.Sort(t.GetNestedTypes(DefaultFlags))) { if (!ShowMember(ntype)) { continue; } if (first) { o.WriteLine(); } first = false; #if STATIC new Outline(universe, mscorlib, ntype, o, declared_only, show_private, filter_obsolete).OutlineType(); #else new Outline(ntype, o, declared_only, show_private, filter_obsolete).OutlineType(); #endif } o.Indent--; o.WriteLine("}"); }
// caller already: // - setup the header and namespace // - call/emit PrintPlatformAttributes on the type void GenerateEnum(Type type) { if (AttributeManager.HasAttribute <FlagsAttribute> (type)) { print("[Flags]"); } var native = AttributeManager.GetCustomAttribute <NativeAttribute> (type); if (native != null) { if (String.IsNullOrEmpty(native.NativeName)) { print("[Native]"); } else { print("[Native (\"{0}\")]", native.NativeName); } } CopyObsolete(type); var unique_constants = new HashSet <string> (); var fields = new Dictionary <FieldInfo, FieldAttribute> (); Tuple <FieldInfo, FieldAttribute> null_field = null; Tuple <FieldInfo, FieldAttribute> default_symbol = null; var underlying_type = GetCSharpTypeName(TypeManager.GetUnderlyingEnumType(type)); print("public enum {0} : {1} {{", type.Name, underlying_type); indent++; foreach (var f in type.GetFields()) { // skip value__ field if (f.IsSpecialName) { continue; } PrintPlatformAttributes(f); CopyObsolete(f); print("{0} = {1},", f.Name, f.GetRawConstantValue()); var fa = AttributeManager.GetCustomAttribute <FieldAttribute> (f); if (fa == null) { continue; } if (f.IsUnavailable()) { continue; } if (fa.SymbolName == null) { null_field = new Tuple <FieldInfo, FieldAttribute> (f, fa); } else if (unique_constants.Contains(fa.SymbolName)) { throw new BindingException(1046, true, $"The [Field] constant {fa.SymbolName} cannot only be used once inside enum {type.Name}."); } else { fields.Add(f, fa); unique_constants.Add(fa.SymbolName); } if (AttributeManager.GetCustomAttribute <DefaultEnumValueAttribute> (f) != null) { if (default_symbol != null) { throw new BindingException(1045, true, $"Only a single [DefaultEnumValue] attribute can be used inside enum {type.Name}."); } default_symbol = new Tuple <FieldInfo, FieldAttribute> (f, fa); } } indent--; print("}"); unique_constants.Clear(); var library_name = type.Namespace; var error = AttributeManager.GetCustomAttribute <ErrorDomainAttribute> (type); if ((fields.Count > 0) || (error != null)) { print(""); // the *Extensions has the same version requirement as the enum itself PrintPlatformAttributes(type); print("[CompilerGenerated]"); print("static public partial class {0}Extensions {{", type.Name); indent++; var field = fields.FirstOrDefault(); var fieldAttr = field.Value; ComputeLibraryName(fieldAttr, type, field.Key?.Name, out library_name, out string library_path); } if (error != null) { // this attribute is important for our tests print("[Field (\"{0}\", \"{1}\")]", error.ErrorDomain, library_name); print("static NSString _domain;"); print(""); print("public static NSString GetDomain (this {0} self)", type.Name); print("{"); indent++; print("if (_domain == null)"); indent++; print("_domain = Dlfcn.GetStringConstant (Libraries.{0}.Handle, \"{1}\");", library_name, error.ErrorDomain); indent--; print("return _domain;"); indent--; print("}"); } if (fields.Count > 0) { print("static IntPtr[] values = new IntPtr [{0}];", fields.Count); print(""); int n = 0; foreach (var kvp in fields) { var f = kvp.Key; var fa = kvp.Value; // the attributes (availability and field) are important for our tests PrintPlatformAttributes(f); libraries.TryGetValue(library_name, out var libPath); var libname = fa.LibraryName?.Replace("+", string.Empty); // We need to check for special cases inside FieldAttributes // fa.LibraryName could contain a different framework i.e UITrackingRunLoopMode (UIKit) inside NSRunLoopMode enum (Foundation). // libPath could have a custom path i.e. CoreImage which in macOS is inside Quartz // library_name contains the Framework constant name the Field is inside of, used as fallback. bool useFieldAttrLibName = libname != null && !string.Equals(libname, library_name, StringComparison.OrdinalIgnoreCase); print("[Field (\"{0}\", \"{1}\")]", fa.SymbolName, useFieldAttrLibName ? libname : libPath ?? library_name); print("internal unsafe static IntPtr {0} {{", fa.SymbolName); indent++; print("get {"); indent++; print("fixed (IntPtr *storage = &values [{0}])", n++); indent++; print("return Dlfcn.CachePointer (Libraries.{0}.Handle, \"{1}\", storage);", useFieldAttrLibName ? libname : library_name, fa.SymbolName); indent--; indent--; print("}"); indent--; print("}"); print(""); } print("public static NSString GetConstant (this {0} self)", type.Name); print("{"); indent++; print("IntPtr ptr = IntPtr.Zero;"); print("switch (({0}) self) {{", underlying_type); var default_symbol_name = default_symbol?.Item2.SymbolName; // more than one enum member can share the same numeric value - ref: #46285 foreach (var kvp in fields) { print("case {0}: // {1}.{2}", Convert.ToInt64(kvp.Key.GetRawConstantValue()), type.Name, kvp.Key.Name); var sn = kvp.Value.SymbolName; if (sn == default_symbol_name) { print("default:"); } indent++; print("ptr = {0};", sn); print("break;"); indent--; } print("}"); print("return (NSString) Runtime.GetNSObject (ptr);"); indent--; print("}"); print(""); print("public static {0} GetValue (NSString constant)", type.Name); print("{"); indent++; print("if (constant == null)"); indent++; // if we do not have a enum value that maps to a null field then we throw if (null_field == null) { print("throw new ArgumentNullException (nameof (constant));"); } else { print("return {0}.{1};", type.Name, null_field.Item1.Name); } indent--; foreach (var kvp in fields) { print("if (constant.IsEqualTo ({0}))", kvp.Value.SymbolName); indent++; print("return {0}.{1};", type.Name, kvp.Key.Name); indent--; } // if there's no default then we throw on unknown constants if (default_symbol == null) { print("throw new NotSupportedException (constant + \" has no associated enum value in \" + nameof ({0}) + \" on this platform.\");", type.Name); } else { print("return {0}.{1};", type.Name, default_symbol.Item1.Name); } indent--; print("}"); } if ((fields.Count > 0) || (error != null)) { indent--; print("}"); } // namespace closing (it's optional to use namespaces even if it's a bad practice, ref #35283) if (indent > 0) { indent--; print("}"); } }
TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType) { TypeSpec spec; if (import_cache.TryGetValue (type, out spec)) { if (spec.BuiltinType == BuiltinTypeSpec.Type.Object) { if (dtype.IsDynamicObject (this)) return module.Compiler.BuiltinTypes.Dynamic; return spec; } if (!spec.IsGeneric || type.IsGenericTypeDefinition) return spec; if (!dtype.HasDynamicAttribute (this)) return spec; // We've found same object in the cache but this one has a dynamic custom attribute // and it's most likely dynamic version of same type IFoo<object> agains IFoo<dynamic> // Do type resolve process again in that case // TODO: Handle cases where they still unify } if (IsMissingType (type)) { spec = new TypeSpec (MemberKind.MissingType, declaringType, new ImportedTypeDefinition (type, this), type, Modifiers.PUBLIC); spec.MemberCache = MemberCache.Empty; import_cache.Add (type, spec); return spec; } if (type.IsGenericType && !type.IsGenericTypeDefinition) { var type_def = type.GetGenericTypeDefinition (); // Generic type definition can also be forwarded if (compiled_types.TryGetValue (type_def, out spec)) return spec; var targs = CreateGenericArguments (0, type.GetGenericArguments (), dtype); if (declaringType == null) { // Simple case, no nesting spec = CreateType (type_def, null, new DynamicTypeReader (), canImportBaseType); spec = spec.MakeGenericType (module, targs); } else { // // Nested type case, converting .NET types like // A`1.B`1.C`1<int, long, string> to typespec like // A<int>.B<long>.C<string> // var nested_hierarchy = new List<TypeSpec> (); while (declaringType.IsNested) { nested_hierarchy.Add (declaringType); declaringType = declaringType.DeclaringType; } int targs_pos = 0; if (declaringType.Arity > 0) { spec = declaringType.MakeGenericType (module, targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ()); targs_pos = spec.Arity; } else { spec = declaringType; } for (int i = nested_hierarchy.Count; i != 0; --i) { var t = nested_hierarchy [i - 1]; spec = MemberCache.FindNestedType (spec, t.Name, t.Arity); if (t.Arity > 0) { spec = spec.MakeGenericType (module, targs.Skip (targs_pos).Take (spec.Arity).ToArray ()); targs_pos += t.Arity; } } string name = type.Name; int index = name.IndexOf ('`'); if (index > 0) name = name.Substring (0, index); spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos); if (spec == null) return null; if (spec.Arity > 0) { spec = spec.MakeGenericType (module, targs.Skip (targs_pos).ToArray ()); } } // Don't add generic type with dynamic arguments, they can interfere with same type // using object type arguments if (!spec.HasDynamicElement) { // Add to reading cache to speed up reading if (!import_cache.ContainsKey (type)) import_cache.Add (type, spec); } return spec; } Modifiers mod; MemberKind kind; var ma = type.Attributes; switch (ma & TypeAttributes.VisibilityMask) { case TypeAttributes.Public: case TypeAttributes.NestedPublic: mod = Modifiers.PUBLIC; break; case TypeAttributes.NestedPrivate: mod = Modifiers.PRIVATE; break; case TypeAttributes.NestedFamily: mod = Modifiers.PROTECTED; break; case TypeAttributes.NestedFamORAssem: mod = Modifiers.PROTECTED | Modifiers.INTERNAL; break; default: mod = Modifiers.INTERNAL; break; } if ((ma & TypeAttributes.Interface) != 0) { kind = MemberKind.Interface; } else if (type.IsGenericParameter) { kind = MemberKind.TypeParameter; } else { var base_type = type.BaseType; if (base_type == null || (ma & TypeAttributes.Abstract) != 0) { kind = MemberKind.Class; } else { kind = DetermineKindFromBaseType (base_type); if (kind == MemberKind.Struct || kind == MemberKind.Delegate) { mod |= Modifiers.SEALED; } } if (kind == MemberKind.Class) { if ((ma & TypeAttributes.Sealed) != 0) { mod |= Modifiers.SEALED; if ((ma & TypeAttributes.Abstract) != 0) mod |= Modifiers.STATIC; } else if ((ma & TypeAttributes.Abstract) != 0) { mod |= Modifiers.ABSTRACT; } } } var definition = new ImportedTypeDefinition (type, this); TypeSpec pt; if (kind == MemberKind.Enum) { const BindingFlags underlying_member = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var type_members = type.GetFields (underlying_member); foreach (var type_member in type_members) { spec = new EnumSpec (declaringType, definition, CreateType (type_member.FieldType), type, mod); break; } if (spec == null) kind = MemberKind.Class; } else if (kind == MemberKind.TypeParameter) { spec = CreateTypeParameter (type, declaringType); } else if (type.IsGenericTypeDefinition) { definition.TypeParameters = CreateGenericParameters (type, declaringType); } else if (compiled_types.TryGetValue (type, out pt)) { // // Same type was found in inside compiled types. It's // either build-in type or forward referenced typed // which point into just compiled assembly. // spec = pt; BuiltinTypeSpec bts = pt as BuiltinTypeSpec; if (bts != null) bts.SetDefinition (definition, type, mod); } if (spec == null) spec = new TypeSpec (kind, declaringType, definition, type, mod); import_cache.Add (type, spec); if (kind == MemberKind.TypeParameter) { if (canImportBaseType) ImportTypeParameterTypeConstraints ((TypeParameterSpec) spec, type); return spec; } // // Two stage setup as the base type can be inflated declaring type or // another nested type inside same declaring type which has not been // loaded, therefore we can import a base type of nested types once // the types have been imported // if (canImportBaseType) ImportTypeBase (spec, type); return spec; }
internal void WriteSchema(System.Text.StringBuilder builder, int indent, ref bool requiresBclImport) { Serializer.GetHashCode(); if (_surrogate != null) { return; // nothing to write } ValueMember[] fieldsArr = new ValueMember[_fields.Count]; _fields.CopyTo(fieldsArr, 0); Array.Sort(fieldsArr, ValueMember.Comparer.Default); if (IsList) { string itemTypeName = _model.GetSchemaTypeName(TypeModel.GetListItemType(_model, Type), BinaryDataFormat.Default, false, false, ref requiresBclImport); NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {"); NewLine(builder, indent + 1).Append("repeated ").Append(itemTypeName).Append(" items = 1;"); NewLine(builder, indent).Append('}'); } else if (_settingsValueFinal.IsAutoTuple) { // key-value-pair etc MemberInfo[] mapping; if (ResolveTupleConstructor(Type, out mapping) != null) { NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {"); for (int i = 0; i < mapping.Length; i++) { Type effectiveType; if (mapping[i] is PropertyInfo) { effectiveType = ((PropertyInfo)mapping[i]).PropertyType; } else if (mapping[i] is FieldInfo) { effectiveType = ((FieldInfo)mapping[i]).FieldType; } else { throw new NotSupportedException("Unknown member type: " + mapping[i].GetType().Name); } NewLine(builder, indent + 1) .Append("optional ") .Append(_model.GetSchemaTypeName(effectiveType, BinaryDataFormat.Default, false, false, ref requiresBclImport).Replace('.', '_')) .Append(' ').Append(mapping[i].Name).Append(" = ").Append(i + 1).Append(';'); } NewLine(builder, indent).Append('}'); } } else if (Helpers.IsEnum(Type)) { NewLine(builder, indent).Append("enum ").Append(GetSchemaTypeName()).Append(" {"); if (_settingsValueFinal.EnumPassthru.GetValueOrDefault()) { if (Type #if WINRT .GetTypeInfo() #endif .IsDefined(_model.MapType(typeof(FlagsAttribute)), false)) { NewLine(builder, indent + 1).Append("// this is a composite/flags enumeration"); } else { NewLine(builder, indent + 1).Append("// this enumeration will be passed as a raw value"); } foreach (FieldInfo field in #if WINRT Type.GetRuntimeFields() #else Type.GetFields() #endif ) { if (field.IsStatic && field.IsLiteral) { object enumVal; #if WINRT || PORTABLE || CF || FX11 enumVal = field.GetValue(null); #else enumVal = field.GetRawConstantValue(); #endif NewLine(builder, indent + 1).Append(field.Name).Append(" = ").Append(enumVal).Append(";"); } } } else { foreach (ValueMember member in fieldsArr) { NewLine(builder, indent + 1).Append(member.Name).Append(" = ").Append(member.FieldNumber).Append(';'); } } NewLine(builder, indent).Append('}'); } else { NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {"); foreach (ValueMember member in fieldsArr) { member.Serializer.GetHashCode(); MemberLevelSettingsValue s = member.GetFinalSettingsCopy(0); string ordinality = s.Collection.IsCollection ? "repeated" : member.IsRequired ? "required" : "optional"; NewLine(builder, indent + 1).Append(ordinality).Append(' '); if (s.ContentBinaryFormatHint.GetValueOrDefault() == BinaryDataFormat.Group) { builder.Append("group "); } string schemaTypeName = member.GetSchemaTypeName(true, ref requiresBclImport); builder.Append(schemaTypeName).Append(" ") .Append(member.Name).Append(" = ").Append(member.FieldNumber); object defaultValue = member.GetFinalDefaultValue(); if (defaultValue != null && member.IsRequired == false) { if (defaultValue is string) { builder.Append(" [default = \"").Append(defaultValue).Append("\"]"); } else if (defaultValue is bool) { // need to be lower case (issue 304) builder.Append((bool)defaultValue ? " [default = true]" : " [default = false]"); } else { builder.Append(" [default = ").Append(defaultValue).Append(']'); } } if (s.Collection.IsCollection && s.Collection.Format == CollectionFormat.Protobuf && ListDecorator.CanPack(HelpersInternal.GetWireType(Helpers.GetTypeCode(member.MemberType), s.ContentBinaryFormatHint.GetValueOrDefault()))) { builder.Append(" [packed=true]"); } builder.Append(';'); if (schemaTypeName == "bcl.NetObjectProxy" && (s.Format == ValueFormat.Reference || s.Format == ValueFormat.LateReference) && !s.WriteAsDynamicType.GetValueOrDefault()) // we know what it is; tell the user { builder.Append(" // reference-tracked ").Append(member.GetSchemaTypeName(false, ref requiresBclImport)); } } if (_subTypes != null && _subTypes.Count != 0) { NewLine(builder, indent + 1).Append("// the following represent sub-types; at most 1 should have a value"); SubType[] subTypeArr = new SubType[_subTypes.Count]; _subTypes.CopyTo(subTypeArr, 0); Array.Sort(subTypeArr, SubType.Comparer.Default); foreach (SubType subType in subTypeArr) { string subTypeName = subType.DerivedType.GetSchemaTypeName(); NewLine(builder, indent + 1).Append("optional ").Append(subTypeName) .Append(" ").Append(subTypeName).Append(" = ").Append(subType.FieldNumber).Append(';'); } } NewLine(builder, indent).Append('}'); } }
static void GetValueTypeSize(Type original_type, Type type, List <Type> field_types, bool is_64_bits, ref int size, ref int max_element_size, Generator generator) { // FIXME: // SIMD types are not handled correctly here (they need 16-bit alignment). // However we don't annotate those types in any way currently, so first we'd need to // add the proper attributes so that the generator can distinguish those types from other types. var type_size = 0; switch (type.FullName) { case "System.Char": case "System.Boolean": case "System.SByte": case "System.Byte": type_size = 1; break; case "System.Int16": case "System.UInt16": type_size = 2; break; case "System.Single": case "System.Int32": case "System.UInt32": type_size = 4; break; case "System.Double": case "System.Int64": case "System.UInt64": type_size = 8; break; case "System.IntPtr": case "System.nfloat": case "System.nuint": case "System.nint": type_size = is_64_bits ? 8 : 4; break; } if (type_size != 0) { field_types.Add(type); size = AlignAndAdd(original_type, size, type_size, ref max_element_size); return; } // composite struct foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { #if BGENERATOR var marshalAs = generator.AttributeManager.GetCustomAttribute <MarshalAsAttribute> (field); #else var marshalAs = (MarshalAsAttribute)Attribute.GetCustomAttribute(field, typeof(MarshalAsAttribute)); #endif if (marshalAs == null) { GetValueTypeSize(original_type, field.FieldType, field_types, is_64_bits, ref size, ref max_element_size, generator); continue; } var multiplier = 1; switch (marshalAs.Value) { case UnmanagedType.ByValArray: var types = new List <Type> (); GetValueTypeSize(original_type, field.FieldType.GetElementType(), types, is_64_bits, ref type_size, ref max_element_size, generator); multiplier = marshalAs.SizeConst; break; case UnmanagedType.U1: case UnmanagedType.I1: type_size = 1; break; case UnmanagedType.U2: case UnmanagedType.I2: type_size = 2; break; case UnmanagedType.U4: case UnmanagedType.I4: case UnmanagedType.R4: type_size = 4; break; case UnmanagedType.U8: case UnmanagedType.I8: case UnmanagedType.R8: type_size = 8; break; default: throw new Exception($"Unhandled MarshalAs attribute: {marshalAs.Value} on field {field.DeclaringType.FullName}.{field.Name}"); } field_types.Add(field.FieldType); size = AlignAndAdd(original_type, size, type_size, ref max_element_size); size += (multiplier - 1) * size; } }