Ejemplo n.º 1
0
        private void ImplementUnionGetMaxSizeMethod(UnionTypeModel unionModel)
        {
            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 @case       =
                    $@"
                    case {unionIndex}:
                        return {this.InvokeGetMaxSizeMethod(unionMember, $"item.Item{unionIndex}")};";

                switchCases.Add(@case);
            }
            string discriminatorPropertyName = nameof(FlatBufferUnion <int, int> .Discriminator);

            string body =
                $@"
            switch (item.{discriminatorPropertyName})
            {{
                {string.Join("\r\n", switchCases)}
                default:
                    throw new System.InvalidOperationException(""Exception determining type of union. Discriminator = "" + item.{discriminatorPropertyName});
            }}
";

            this.GenerateGetMaxSizeMethod(unionModel.ClrType, body);
        }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
0
        static public TSType NewType(XElement elem, TypeScriptDefContext context)
        {
            if (elem == null)
                return null;

            TSType T = null;
            UnionTypeModel TypeList = new UnionTypeModel();
            HashSet<string> typesAlreadyInTheList = new HashSet<string>();

            foreach (XElement e in elem.Elements())
            {
                switch (e.Name.LocalName)
                {
                    case "dotident":
                        T = new BasicType(e);
                        if (!Tool.IsBasicType(T))
                            T = (TSType)TypeDeclaration.New(e, null, context) ?? T;
                        break;
                    case "anonymoustype":
                        T = new AnonymousType(e, context);
                        break;
                    case "functiontype":
                        T = new FunctionType(e, context);
                        break;
                    case "generic":
                        T = new Generic(e, context);
                        break;
                    case "arraylevel":
                        T = new Model.Array(T);
                        TypeList.Types.RemoveAt(TypeList.Types.Count - 1);
                        break;
                    default:
                        continue;
                }
                if (!typesAlreadyInTheList.Contains(T.ToString())) // Avoids adding the same type multiple times
                {
                    TypeList.Types.Add(T);
                    typesAlreadyInTheList.Add(T.ToString());
                }
            }

            if (TypeList.Count < 2)
                return T;
            else
                return TypeList;
        }
    /// <summary>
    /// Tries to create a type model based on the given type.
    /// </summary>
    public bool TryCreateTypeModel(TypeModelContainer container, Type type, [NotNullWhen(true)] out ITypeModel?typeModel)
    {
        if (type == typeof(string))
        {
            typeModel = new StringTypeModel(container);
            return(true);
        }

        if (type.IsArray)
        {
            if (typeof(IFlatBufferUnion).IsAssignableFrom(type.GetElementType()))
            {
                typeModel = new ArrayVectorOfUnionTypeModel(type, container);
            }
            else
            {
                typeModel = new ArrayVectorTypeModel(type, container);
            }

            return(true);
        }

        if (type.IsGenericType)
        {
            var genericDef = type.GetGenericTypeDefinition();
            if (genericDef == typeof(IList <>) || genericDef == typeof(IReadOnlyList <>))
            {
                if (typeof(IFlatBufferUnion).IsAssignableFrom(type.GetGenericArguments()[0]))
                {
                    typeModel = new ListVectorOfUnionTypeModel(type, container);
                }
                else
                {
                    typeModel = new ListVectorTypeModel(type, container);
                }

                return(true);
            }

            if (genericDef == typeof(Memory <>) || genericDef == typeof(ReadOnlyMemory <>))
            {
                typeModel = new MemoryVectorTypeModel(type, container);
                return(true);
            }

            if (genericDef == typeof(IIndexedVector <,>))
            {
                typeModel = new IndexedVectorTypeModel(type, container);
                return(true);
            }
        }

        if (typeof(IFlatBufferUnion).IsAssignableFrom(type))
        {
            typeModel = new UnionTypeModel(type, container);
            return(true);
        }

        if (type.IsEnum)
        {
            typeModel = new EnumTypeModel(type, container);
            return(true);
        }

        var underlyingType = Nullable.GetUnderlyingType(type);

        if (underlyingType is not null)
        {
            typeModel = new NullableTypeModel(container, type);
            return(true);
        }

        var tableAttribute  = type.GetCustomAttribute <FlatBufferTableAttribute>();
        var structAttribute = type.GetCustomAttribute <FlatBufferStructAttribute>();

        if (tableAttribute is not null && structAttribute is not null)
        {
            throw new InvalidFlatBufferDefinitionException($"Type '{CSharpHelpers.GetCompilableTypeName(type)}' is declared as both [FlatBufferTable] and [FlatBufferStruct].");
        }
        private (string prepareBlock, string serializeBlock) GetUnionSerializeBlocks(int index, TableMemberModel memberModel)
        {
            UnionTypeModel unionModel = (UnionTypeModel)memberModel.ItemTypeModel;

            string valueVariableName = $"index{index}Value";
            string discriminatorOffsetVariableName = $"index{index}DiscriminatorOffset";
            string valueOffsetVariableName         = $"index{index}ValueOffset";
            string discriminatorValueVariableName  = $"index{index}Discriminator";

            string prepareBlock =
                $@"
                    var {valueVariableName} = item.{memberModel.PropertyInfo.Name};
                    int {discriminatorOffsetVariableName} = 0;
                    int {valueOffsetVariableName} = 0;
                    byte {discriminatorValueVariableName} = 0;

                    if ({valueVariableName} != null && {valueVariableName}.Discriminator != 0)
                    {{
                            {discriminatorValueVariableName} = {valueVariableName}.Discriminator;
                            {discriminatorOffsetVariableName} = currentOffset;
                            vtable.{nameof(VTableBuilder.SetOffset)}({index}, currentOffset - tableStart);
                            currentOffset++;

                            currentOffset += {CSharpHelpers.GetFullMethodName(ReflectedMethods.SerializationHelpers_GetAlignmentErrorMethod)}(currentOffset, sizeof(uint));
                            {valueOffsetVariableName} = currentOffset;
                            vtable.{nameof(VTableBuilder.SetOffset)}({index + 1}, currentOffset - tableStart);
                            currentOffset += sizeof(uint);
                    }}";

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

            for (int i = 0; i < unionModel.UnionElementTypeModel.Length; ++i)
            {
                var elementModel = unionModel.UnionElementTypeModel[i];
                var unionIndex   = i + 1;

                string structAdjustment = string.Empty;
                if (elementModel.SchemaType == FlatBufferSchemaType.Struct)
                {
                    // Structs are generally written in-line, with the exception of unions.
                    // So, we need to do the normal allocate space dance here, since we're writing
                    // a pointer to a struct.
                    structAdjustment =
                        $@"
                        var writeOffset = context.{nameof(SerializationContext.AllocateSpace)}({elementModel.InlineSize}, {elementModel.Alignment});
                        writer.{nameof(SpanWriter.WriteUOffset)}(span, {valueOffsetVariableName}, writeOffset, context);
                        {valueOffsetVariableName} = writeOffset;";
                }

                string @case =
                    $@"
                    case {unionIndex}:
                    {{
                        {structAdjustment}
                        {this.GetSerializeInvocation(elementModel.ClrType, $"{valueVariableName}.Item{unionIndex}", valueOffsetVariableName)}
                    }}
                        break;";

                switchCases.Add(@case);
            }

            string serializeBlock =
                $@"
                    if ({discriminatorOffsetVariableName} != 0)
                    {{
                        {this.GetSerializeInvocation(typeof(byte), discriminatorValueVariableName, discriminatorOffsetVariableName)}
                        switch ({discriminatorValueVariableName})
                        {{
                            {string.Join("\r\n", switchCases)}
                            default: throw new InvalidOperationException(""Unexpected"");
                        }}
                    }}";

            return(prepareBlock, serializeBlock);
        }