/// <summary> /// Generates a special property getter for union types. This stems from /// the fact that unions occupy two spots in the table's vtable to deserialize one /// logical field. This means that the logic to read them must also be special. /// </summary> private GeneratedProperty CreateUnionTableGetter(TableMemberModel memberModel, int index) { Type propertyType = memberModel.ItemTypeModel.ClrType; string defaultValue = CSharpHelpers.GetDefaultValueToken(memberModel); UnionTypeModel unionModel = (UnionTypeModel)memberModel.ItemTypeModel; GeneratedProperty generatedProperty = new GeneratedProperty(this.options, index, memberModel.PropertyInfo); // Start by generating switch cases. The codegen'ed union types have // well-defined constructors for each constituent type, so this .ctor // will always be available. List <string> switchCases = new List <string>(); for (int i = 0; i < unionModel.UnionElementTypeModel.Length; ++i) { var unionMember = unionModel.UnionElementTypeModel[i]; int unionIndex = i + 1; string structOffsetAdjustment = string.Empty; if (unionMember.SchemaType == FlatBufferSchemaType.Struct) { structOffsetAdjustment = $"offsetLocation += buffer.{nameof(InputBuffer.ReadUOffset)}(offsetLocation);"; } string @case = $@" case {unionIndex}: {structOffsetAdjustment} return new {CSharpHelpers.GetCompilableTypeName(unionModel.ClrType)}({this.GetReadInvocation(unionMember.ClrType, "buffer", "offsetLocation")}); "; switchCases.Add(@case); } generatedProperty.ReadValueMethodDefinition = $@" [MethodImpl(MethodImplOptions.AggressiveInlining)] private static {CSharpHelpers.GetCompilableTypeName(propertyType)} {generatedProperty.ReadValueMethodName}(InputBuffer buffer, int offset) {{ int discriminatorLocation = buffer.{nameof(InputBuffer.GetAbsoluteTableFieldLocation)}(offset, {index}); int offsetLocation = buffer.{nameof(InputBuffer.GetAbsoluteTableFieldLocation)}(offset, {index + 1}); if (discriminatorLocation == 0) {{ return {defaultValue}; }} else {{ byte discriminator = buffer.{nameof(InputBuffer.ReadByte)}(discriminatorLocation); if (discriminator == 0 && offsetLocation != 0) throw new System.IO.InvalidDataException(""FlatBuffer union had discriminator set but no offset.""); switch (discriminator) {{ {string.Join("\r\n", switchCases)} default: return {defaultValue}; }} }} }} "; return(generatedProperty); }
private void ImplementStructReadMethod(StructTypeModel typeModel) { // We have to implement two items: The table class and the overall "read" method. // Let's start with the read method. string className = "structReader_" + Guid.NewGuid().ToString("n"); // Static factory method. this.GenerateMethodDefinition(typeModel.ClrType, $"return new {className}(memory, offset);"); // Implement the class { // Build up a list of property overrides. var propertyOverrides = new List <GeneratedProperty>(); for (int index = 0; index < typeModel.Members.Count; ++index) { var value = typeModel.Members[index]; PropertyInfo propertyInfo = value.PropertyInfo; Type propertyType = propertyInfo.PropertyType; string compilableTypeName = CSharpHelpers.GetCompilableTypeName(propertyType); GeneratedProperty generatedProperty = new GeneratedProperty(this.options, index, propertyInfo); generatedProperty.ReadValueMethodDefinition = $@" [MethodImpl(MethodImplOptions.AggressiveInlining)] private static {CSharpHelpers.GetCompilableTypeName(propertyType)} {generatedProperty.ReadValueMethodName}(InputBuffer buffer, int offset) {{ return {this.GetReadInvocation(propertyType, "buffer", $"offset + {value.Offset}")}; }} "; propertyOverrides.Add(generatedProperty); } string classDefinition = this.CreateClass( className, typeModel.ClrType, typeModel.Members.Select(x => x.PropertyInfo.Name), propertyOverrides); var node = CSharpSyntaxTree.ParseText(classDefinition, ParseOptions); this.methodDeclarations.Add(node.GetRoot()); } }
/// <summary> /// Generates a standard getter for a normal vtable entry. /// </summary> private GeneratedProperty CreateStandardTableProperty(TableMemberModel memberModel, int index) { Type propertyType = memberModel.ItemTypeModel.ClrType; string defaultValue = CSharpHelpers.GetDefaultValueToken(memberModel); GeneratedProperty property = new GeneratedProperty(this.options, index, memberModel.PropertyInfo); property.ReadValueMethodDefinition = $@" [MethodImpl(MethodImplOptions.AggressiveInlining)] private static {CSharpHelpers.GetCompilableTypeName(propertyType)} {property.ReadValueMethodName}(InputBuffer buffer, int offset) {{ int absoluteLocation = buffer.{nameof(InputBuffer.GetAbsoluteTableFieldLocation)}(offset, {index}); if (absoluteLocation == 0) {{ return {defaultValue}; }} else {{ return {this.GetReadInvocation(propertyType, "buffer", "absoluteLocation")}; }} }} "; return(property); }