Ejemplo n.º 1
0
        private void ImplementMemoryVectorReadMethod(VectorTypeModel typeModel)
        {
            string invocation;

            if (typeModel.ItemTypeModel.ClrType == typeof(byte))
            {
                invocation = nameof(InputBuffer.ReadByteMemoryBlock);
                if (typeModel.IsReadOnly)
                {
                    invocation = nameof(InputBuffer.ReadByteReadOnlyMemoryBlock);
                }
            }
            else
            {
                string methodName = nameof(InputBuffer.ReadMemoryBlock);
                if (typeModel.IsReadOnly)
                {
                    methodName = nameof(InputBuffer.ReadReadOnlyMemoryBlock);
                }

                invocation = $"{methodName}<{CSharpHelpers.GetCompilableTypeName(typeModel.ItemTypeModel.ClrType)}>";
            }

            string body = $"memory.{invocation}(offset, {typeModel.ItemTypeModel.InlineSize})";

            // Greedy deserialize has the invariant that we no longer touch the
            // original buffer. This means a memory copy here.
            if (this.options.GreedyDeserialize)
            {
                body = $"{body}.ToArray().AsMemory()";
            }

            this.GenerateMethodDefinition(typeModel.ClrType, $"return {body};");
        }
Ejemplo n.º 2
0
        public override string ToString()
        {
            List <string> lines = new List <string>();

            if (this.MemberModel.IsVirtual)
            {
                if (!string.IsNullOrEmpty(this.BackingFieldName))
                {
                    lines.Add($"private {CSharpHelpers.GetCompilableTypeName(this.propertyInfo.PropertyType)} {this.BackingFieldName};");
                }

                if (!string.IsNullOrEmpty(this.HasValueFieldName))
                {
                    lines.Add($"private bool {this.HasValueFieldName};");
                }

                var accessModifiers = CSharpHelpers.GetPropertyAccessModifiers(this.propertyInfo);

                lines.Add($@"{accessModifiers.propertyModifier} override {CSharpHelpers.GetCompilableTypeName(this.propertyInfo.PropertyType)} {this.propertyInfo.Name} {{");
                lines.Add($"{accessModifiers.getModifer} get {{ {this.GetterBody} }}");

                MethodInfo methodInfo = this.propertyInfo.SetMethod;
                if (methodInfo != null)
                {
                    lines.Add($"{accessModifiers.setModifier} set {{ {this.SetterBody} }}");
                }

                lines.Add("}");
            }

            lines.Add(this.ReadValueMethodDefinition);

            return(string.Join("\r\n", lines));
        }
Ejemplo n.º 3
0
        internal static string GetDefaultValueToken(TableMemberModel memberModel)
        {
            var itemTypeModel = memberModel.ItemTypeModel;
            var clrType       = itemTypeModel.ClrType;

            string defaultValue = $"default({GetCompilableTypeName(memberModel.ItemTypeModel.ClrType)})";

            if (memberModel.HasDefaultValue)
            {
                if (BuiltInType.BuiltInScalars.TryGetValue(clrType, out IBuiltInScalarType builtInType))
                {
                    return(builtInType.FormatObject(memberModel.DefaultValue));
                }
                else if (clrType.IsEnum)
                {
                    return($"{CSharpHelpers.GetCompilableTypeName(clrType)}.{memberModel.DefaultValue}");
                }
                else
                {
                    throw new InvalidOperationException("Unexpected default value type: " + clrType.FullName);
                }
            }

            return(defaultValue);
        }
Ejemplo n.º 4
0
        /// <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 ImplementEnumInlineWriteMethod(EnumTypeModel enumModel)
        {
            var    type           = enumModel.ClrType;
            var    underlyingType = Enum.GetUnderlyingType(type);
            string body           = this.GetSerializeInvocation(underlyingType, $"({CSharpHelpers.GetCompilableTypeName(underlyingType)})item", "originalOffset");

            this.GenerateSerializeMethod(type, body);
        }
Ejemplo n.º 6
0
        private void ImplementArrayVectorReadMethod(VectorTypeModel typeModel)
        {
            var itemTypeModel = typeModel.ItemTypeModel;

            string statement;

            if (itemTypeModel is ScalarTypeModel scalarModel && scalarModel.NativelyReadableFromMemory)
            {
                // Memory is faster in situations where we can get away with it.
                statement = $"memory.{nameof(InputBuffer.ReadMemoryBlock)}<{CSharpHelpers.GetCompilableTypeName(itemTypeModel.ClrType)}>(offset, {itemTypeModel.InlineSize}).ToArray()";
            }
Ejemplo n.º 7
0
        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());
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Gets a method to serialize the given type with the given body.
        /// </summary>
        private void GenerateGetMaxSizeMethod(Type type, string body, bool inline = true)
        {
            string inlineDeclaration = "[MethodImpl(MethodImplOptions.AggressiveInlining)]";

            if (!inline)
            {
                inlineDeclaration = string.Empty;
            }

            string declaration =
                $@"
            {inlineDeclaration}
            private static int {this.MethodNames[type]}({CSharpHelpers.GetCompilableTypeName(type)} item)
            {{
                {body}
            }}";

            var node = CSharpSyntaxTree.ParseText(declaration, ParseOptions);

            this.methodDeclarations.Add(node.GetRoot());
        }
Ejemplo n.º 9
0
        private string CreateClass(
            string className,
            Type baseType,
            IEnumerable <string> propertyNames,
            IEnumerable <GeneratedProperty> propertyOverrides)
        {
            string inputBufferFieldDef = "private readonly InputBuffer buffer;";
            string offsetFieldDef      = "private readonly int offset;";

            string ctorBody =
                $@"
                this.buffer = buffer;
                this.offset = offset;
";

            if (this.options.GreedyDeserialize)
            {
                inputBufferFieldDef = string.Empty;
                offsetFieldDef      = string.Empty;
                ctorBody            = string.Join("\r\n", propertyOverrides.Select(x => $"this.{x.BackingFieldName} = {x.ReadValueMethodName}(buffer, offset);"));
            }

            return
                ($@"
                private sealed class {className} : {CSharpHelpers.GetCompilableTypeName(baseType)}
                {{
                    {inputBufferFieldDef}
                    {offsetFieldDef}
        
                    public {className}(InputBuffer buffer, int offset)
                    {{
                        {ctorBody}
                    }}

                    {string.Join("\r\n", propertyOverrides)}
                }}
");
        }
Ejemplo n.º 10
0
        /// <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);
        }
        private void ImplementStructInlineWriteMethod(StructTypeModel structModel)
        {
            var type = structModel.ClrType;

            List <string> body = new List <string>();

            for (int i = 0; i < structModel.Members.Count; ++i)
            {
                var memberInfo = structModel.Members[i];

                string propertyAccessor = $"item.{memberInfo.PropertyInfo.Name}";
                if (memberInfo.ItemTypeModel.SchemaType == FlatBufferSchemaType.Struct)
                {
                    // Force structs to be non-null. FlatSharp doesn't declare structs as structs,
                    // so we need to be careful that structs-within-structs are not null.
                    propertyAccessor += $" ?? new {CSharpHelpers.GetCompilableTypeName(memberInfo.ItemTypeModel.ClrType)}()";
                }

                string invocation = this.GetSerializeInvocation(memberInfo.ItemTypeModel.ClrType, propertyAccessor, $"{memberInfo.Offset} + originalOffset");
                body.Add(invocation);
            }

            this.GenerateSerializeMethod(type, string.Join("\r\n", body));
        }
        /// <summary>
        /// Gets a method to serialize the given type with the given body.
        /// </summary>
        private void GenerateSerializeMethod(Type type, string body, bool inline = true)
        {
            string inlineDeclaration = inline ? string.Empty : "[MethodImpl(MethodImplOptions.AggressiveInlining)]";
            string declaration       = $@"
            {inlineDeclaration}
            private static void {this.MethodNames[type]} (SpanWriter writer, Span<byte> span, {CSharpHelpers.GetCompilableTypeName(type)} item, int originalOffset, SerializationContext context)
            {{
                {body}
            }}";

            var node = CSharpSyntaxTree.ParseText(declaration, ParseOptions);

            this.methodDeclarations.Add(node.GetRoot());
        }
        private void ImplementMemoryVectorInlineWriteMethod(VectorTypeModel vectorModel)
        {
            var type          = vectorModel.ClrType;
            var itemTypeModel = vectorModel.ItemTypeModel;

            string writerMethodName = $"{nameof(SpanWriter.WriteReadOnlyMemoryBlock)}<{CSharpHelpers.GetCompilableTypeName(itemTypeModel.ClrType)}>";

            if (itemTypeModel.ClrType == typeof(byte))
            {
                // Optimization: when we're writing bytes we don't have to change types.
                writerMethodName = nameof(SpanWriter.WriteReadOnlyByteMemoryBlock);
            }

            string body = $"writer.{writerMethodName}(span, item, originalOffset, {itemTypeModel.Alignment}, {itemTypeModel.InlineSize}, context);";

            this.GenerateSerializeMethod(type, body);
        }
Ejemplo n.º 14
0
        internal static string GetDefaultValueToken(TableMemberModel memberModel)
        {
            var itemTypeModel = memberModel.ItemTypeModel;
            var clrType       = itemTypeModel.ClrType;

            string defaultValue = $"default({GetCompilableTypeName(memberModel.ItemTypeModel.ClrType)})";

            if (memberModel.HasDefaultValue)
            {
                string literalSpecifier    = string.Empty;
                string cast                = string.Empty;
                string defaultValueLiteral = memberModel.DefaultValue.ToString();

                if (clrType == typeof(bool))
                {
                    // Bool.ToString() returns 'True', which is not the right keyword.
                    defaultValueLiteral = defaultValueLiteral.ToLower();
                }
                else if (clrType == typeof(sbyte))
                {
                    cast = "(sbyte)";
                }
                else if (clrType == typeof(byte))
                {
                    cast = "(byte)";
                }
                else if (clrType == typeof(short))
                {
                    cast = "(short)";
                }
                else if (clrType == typeof(ushort))
                {
                    cast = "(ushort)";
                }
                else if (clrType == typeof(float))
                {
                    literalSpecifier = "f";
                }
                else if (clrType == typeof(uint))
                {
                    literalSpecifier = "u";
                }
                else if (clrType == typeof(int))
                {
                    // shouldn't need this one, but let's be thorough.
                    cast = "(int)";
                }
                else if (clrType == typeof(double))
                {
                    literalSpecifier = "d";
                }
                else if (clrType == typeof(long))
                {
                    literalSpecifier = "L";
                }
                else if (clrType == typeof(ulong))
                {
                    literalSpecifier = "ul";
                }
                else if (clrType.IsEnum)
                {
                    defaultValueLiteral = $"{CSharpHelpers.GetCompilableTypeName(clrType)}.{defaultValueLiteral}";
                }
                else
                {
                    throw new InvalidOperationException("Unexpected default value type: " + clrType.FullName);
                }

                defaultValue = $"{cast}{defaultValueLiteral}{literalSpecifier}";
            }

            return(defaultValue);
        }
Ejemplo n.º 15
0
        private (string prepareBlock, string serializeBlock) GetStandardSerializeBlocks(int index, TableMemberModel memberModel)
        {
            string valueVariableName  = $"index{index}Value";
            string offsetVariableName = $"index{index}Offset";

            string condition = $"if ({valueVariableName} != {CSharpHelpers.GetDefaultValueToken(memberModel)})";

            if ((memberModel.ItemTypeModel is VectorTypeModel vector && vector.IsMemoryVector) || memberModel.IsKey)
            {
                // 1) Memory is a struct and can't be null, and 0-length vectors are valid.
                //    Therefore, we just need to omit the conditional check entirely.

                // 2) For sorted vector keys, we must include the value since some other
                //    libraries cannot do binary search with omitted keys.
                condition = string.Empty;
            }

            string keyCheckMethodCall = string.Empty;

            if (memberModel.IsKey)
            {
                keyCheckMethodCall = $"{nameof(SortedVectorHelpers)}.{nameof(SortedVectorHelpers.EnsureKeyNonNull)}({valueVariableName});";
            }

            string prepareBlock =
                $@"
                    var {valueVariableName} = item.{memberModel.PropertyInfo.Name};
                    int {offsetVariableName} = 0;
                    {keyCheckMethodCall}
                    {condition} 
                    {{
                            currentOffset += {CSharpHelpers.GetFullMethodName(ReflectedMethods.SerializationHelpers_GetAlignmentErrorMethod)}(currentOffset, {memberModel.ItemTypeModel.Alignment});
                            {offsetVariableName} = currentOffset;
                            vtable.{nameof(VTableBuilder.SetOffset)}({index}, currentOffset - tableStart);
                            currentOffset += {memberModel.ItemTypeModel.InlineSize};
                    }}";

            string sortInvocation = string.Empty;

            if (memberModel.IsSortedVector)
            {
                VectorTypeModel  vectorModel = (VectorTypeModel)memberModel.ItemTypeModel;
                TableTypeModel   tableModel  = (TableTypeModel)vectorModel.ItemTypeModel;
                TableMemberModel keyMember   = tableModel.IndexToMemberMap.Single(x => x.Value.PropertyInfo == tableModel.KeyProperty).Value;

                var    builtInType = BuiltInType.BuiltInTypes[keyMember.ItemTypeModel.ClrType];
                string inlineSize  = builtInType.TypeModel.SchemaType == FlatBufferSchemaType.Scalar ? builtInType.TypeModel.InlineSize.ToString() : "null";

                sortInvocation = $"{nameof(SortedVectorHelpers)}.{nameof(SortedVectorHelpers.SortVector)}(" +
                                 $"span, {offsetVariableName}, {keyMember.Index}, {inlineSize}, {CSharpHelpers.GetCompilableTypeName(builtInType.SpanComparerType)}.Instance);";
            }

            string serializeBlock =
                $@"
                    if ({offsetVariableName} != 0)
                    {{
                        {this.GetSerializeInvocation(memberModel.ItemTypeModel.ClrType, valueVariableName, offsetVariableName)}
                        {sortInvocation}
                    }}";

            return(prepareBlock, serializeBlock);
        }