public static void TraverseGenCustomType(TraversStrategy strategy, Type type, string funcPrefix)
        {
            var sink = MakeGenMethod(type, strategy.flag, funcPrefix + strategy.funcName, strategy.funcReturnType ?? Void, strategy.funcArgs ?? "");

            if (type.IsList() || type.IsArray)
            {
                var elemType = type.FirstGenericArg();
                RequestGen(elemType, strategy.flag);
                TraversGenList(strategy, sink, elemType, type.AccessPrefixInGeneratedFunction(), type.IsArray);
            }
            else if (type.IsDictionary())
            {
                var elemType = type.FirstGenericArg();
                var keyType  = type.SecondGenericArg();
                RequestGen(elemType, strategy.flag);
                RequestGen(keyType, strategy.flag);
                TraverseGenDict(strategy, sink, elemType, keyType, type.AccessPrefixInGeneratedFunction());
            }
            else
            {
                if (strategy.interfaceType != null && type.IsControllable())
                {
                    sink.classBuilder.inheritance(strategy.interfaceType.Name);
                }

                strategy.start?.Invoke(sink, type.NeedBaseCallForFlag(strategy.flag));
                type.ProcessMembers(strategy.flag, strategy.needMembersGenRequest, member =>
                {
                    if (strategy.memberPredicate == null || strategy.memberPredicate(member))
                    {
                        strategy.elemProcess(sink, member);
                    }
                });
                strategy.finish?.Invoke(sink);
            }
        }
Пример #2
0
        static bool ProcessMembers(this Type type, GenTaskFlags currFlag, bool needMembersGen, Action <DataInfo> strategy)
        {
            bool hasMembers = false;

            foreach (var member in type.GetMembersForCodeGen(currFlag))
            {
                member.carrierType = type;
                if (needMembersGen && !member.type.IsLoadableConfig())
                {
                    RequestGen(member.type, currFlag);
                }
                member.accessPrefix = type.AccessPrefixInGeneratedFunction();
                strategy(member);
                hasMembers = true;
            }
            return(hasMembers);
        }
        static void GenerateSerialize(Type type, string funcPrefix = "")
        {
            GenClassSink(type).usingSink("System.IO");

            const string writerName = "writer";
            var          sinkWriter = MakeGenMethod(type, GenTaskFlags.Serialize, funcPrefix + WriteFuncName, Void, $"BinaryWriter {writerName}");

            var accessPrefix = type.AccessPrefixInGeneratedFunction();

            if (type.IsList())
            {
                var elemType = type.GenericTypeArguments[0];
                RequestGen(elemType, GenTaskFlags.Serialize);
                SinkListWriterCode(type, sinkWriter, DataInfo.WithTypeAndName(elemType, accessPrefix), writerName);
            }
            else if (type.IsArray)
            {
                var elemType = type.GetElementType();
                RequestGen(elemType, GenTaskFlags.Serialize);
                SinkArrayWriterCode(sinkWriter, DataInfo.WithTypeAndName(elemType, accessPrefix), writerName);
            }
            else if (type.IsDictionary())
            {
                var keyType = type.FirstGenericArg();
                var valType = type.SecondGenericArg();
                RequestGen(keyType, GenTaskFlags.Serialize);
                RequestGen(valType, GenTaskFlags.Serialize);
                SinkDictWriterCode(sinkWriter, keyType, valType, accessPrefix, writerName, type.IsConfigStorage());
            }
            else
            {
                type.ProcessMembers(GenTaskFlags.Serialize, true, info =>
                {
                    GenWriteValueToStream(sinkWriter, info, writerName);
                });
            }
        }
        static void GenerateDeserialize(Type type, bool pooled, string funcPrefix = "")
        {
            GenClassSink(type).usingSink("System.IO");

            const string readerName = "reader";

            var flag = pooled ? GenTaskFlags.PooledDeserialize : GenTaskFlags.Deserialize;

            MethodBuilder sinkReader = null;

            if (type.GenMode() == Mode.ExtensionMethod && type.IsStruct() || type.IsArray)
            {
                sinkReader = MakeGenMethod(type, flag, $"Read{type.UniqueName()}", type,
                                           $"this BinaryReader {readerName}{type.OptPoolSecondArgDecl(pooled)}", disablebleFirstArg: true);
            }
            else
            {
                sinkReader = MakeGenMethod(type, flag, funcPrefix + ReadFuncName, Void,
                                           $"BinaryReader {readerName}{type.OptPoolSecondArgDecl(pooled)}");
            }


            var accessPrefix = type.AccessPrefixInGeneratedFunction();

            if (type.IsList())
            {
                var elemType = type.GenericTypeArguments[0];
                RequestGen(elemType, flag);
                SinkListReaderCode(type, sinkReader, elemType, accessPrefix, readerName, pooled);
            }
            else if (type.IsArray)
            {
                var elemType = type.GetElementType();
                RequestGen(elemType, flag);
                SinkArrayReaderCode(sinkReader, elemType, accessPrefix, readerName, pooled);
            }
            else if (type.IsDictionary())
            {
                var keyType = type.FirstGenericArg();
                var valType = type.SecondGenericArg();
                RequestGen(keyType, flag);
                RequestGen(valType, flag);
                SinkDictReaderCode(sinkReader, keyType, valType, accessPrefix, readerName, pooled,
                                   type.IsConfigStorage());
            }
            else
            {
                bool immutableMode = type.IsStruct() && !type.IsControllable();
                if (immutableMode)
                {
                    sinkReader.content($"var self = new {type.RealName(true)}();");
                }
                type.ProcessMembers(flag, true, info =>
                {
                    GenReadValueFromStream(sinkReader, info, readerName, pooled);
                });
                if (immutableMode)
                {
                    sinkReader.content("return self;");
                }
            }
        }
Пример #5
0
        static void GenerateJsonSerialization(Type type, string funcPrefix)
        {
            var classSink = GenClassSink(type);

            classSink.usingSink("System.IO");
            classSink.usingSink("Newtonsoft.Json");

            const string writerName = "writer";
            const string readerName = "reader";


            var accessPrefix = type.AccessPrefixInGeneratedFunction();

            if (type.IsList() || type.IsArray)
            {
                var returnTypeForReadMethod = type.IsArray ? type : Void;
                var sinkReader = MakeGenMethod(type, GenTaskFlags.JsonSerialization, funcPrefix + JsonReadFuncName, returnTypeForReadMethod, $"JsonTextReader {readerName}");
                var sinkWriter = MakeGenMethod(type, GenTaskFlags.JsonSerialization, funcPrefix + JsonWriteFuncName, Void, $"JsonTextWriter {writerName}");

                var elemType = type.FirstGenericArg();
                if (elemType.IsConfig() == false)
                {
                    RequestGen(elemType, GenTaskFlags.JsonSerialization);
                }
                var    info  = DataInfo.WithTypeAndName(elemType, accessPrefix);
                string count = type.IsList() ? "Count" : "Length";

                // Writer
                sinkWriter.content($"writer.WriteStartArray();");
                sinkWriter.content($"for (int i = 0; i < {info.access}.{count}; i++)");
                sinkWriter.content($"{{");
                sinkWriter.indent++;
                WriteJsonValueStatement(sinkWriter,
                                        new DataInfo {
                    type = info.type, baseAccess = $"{info.access}[i]", insideConfigStorage = type.IsConfigStorage()
                },
                                        true);
                sinkWriter.indent--;
                sinkWriter.content($"}}");
                sinkWriter.content($"writer.WriteEndArray();");

                // Reader
                JsonAssertReadStartStatement(sinkReader, $"reader.TokenType != JsonToken.StartArray");
                if (type.IsArray)
                {
                    sinkReader.content($"if(self == null || self.Length > 0) self = Array.Empty<{elemType.RealName(true)}>();");
                }
                sinkReader.content($"while (reader.Read())");
                sinkReader.content($"{{");
                sinkReader.indent++;
                sinkReader.content("if (reader.TokenType == JsonToken.EndArray) { break; }");
                Action initArray = () =>
                {
                    sinkReader.content($"Array.Resize(ref self, self.Length + 1);");
                };
                if (elemType.IsDataNode())
                {
                    if (type.IsArray)
                    {
                        initArray();
                    }
                    else
                    {
                        sinkReader.content($"self.Add(null);");
                    }
                    ReadJsonValueStatement(sinkReader,
                                           new DataInfo {
                        type       = elemType, baseAccess = $"self[self.{count} - 1]", insideConfigStorage = type.IsConfigStorage(),
                        sureIsNull = true
                    }, false);
                }
                else
                {
                    ReadJsonValueStatement(sinkReader, new DataInfo {
                        type = info.type, baseAccess = $"val",
                        insideConfigStorage = type.IsConfigStorage(), sureIsNull = true
                    }, true);
                    if (type.IsArray)
                    {
                        initArray();
                        sinkReader.content($"self[self.Length - 1] = val;");
                    }
                    else
                    {
                        sinkReader.content($"{info.access}.Add(val);");
                    }
                }
                sinkReader.indent--;
                sinkReader.content($"}}");

                if (type.IsArray)
                {
                    sinkReader.content($"return self;");
                }
            }
            else if (type.IsDictionary())
            {
                var sinkReader = MakeGenMethod(type, GenTaskFlags.JsonSerialization, funcPrefix + JsonReadFuncName, Void, $"JsonTextReader {readerName}");
                var sinkWriter = MakeGenMethod(type, GenTaskFlags.JsonSerialization, funcPrefix + JsonWriteFuncName, Void, $"JsonTextWriter {writerName}");
                var keyType    = type.FirstGenericArg();
                var valType    = type.SecondGenericArg();
                RequestGen(keyType, GenTaskFlags.JsonSerialization);
                RequestGen(valType, GenTaskFlags.JsonSerialization);

                var infoKey = DataInfo.WithTypeAndName(keyType, "key");
                var infoVal = DataInfo.WithTypeAndName(valType, "val");

                // Writer

                sinkWriter.content($"writer.WriteStartArray();");
                sinkWriter.content($"foreach (var item in {accessPrefix})");
                sinkWriter.openBrace();
                sinkWriter.content($"writer.WriteStartObject();");
                sinkWriter.content($"writer.WritePropertyName(\"key\");");
                WriteJsonValueStatement(sinkWriter, new DataInfo {
                    type = keyType, baseAccess = $"item.Key", insideConfigStorage = type.IsConfigStorage()
                }, true);
                sinkWriter.content($"writer.WritePropertyName(\"value\");");
                WriteJsonValueStatement(sinkWriter, new DataInfo {
                    type = valType, baseAccess = $"item.Value", insideConfigStorage = type.IsConfigStorage()
                }, true);
                sinkWriter.content($"writer.WriteEndObject();");
                sinkWriter.closeBrace();
                sinkWriter.content($"writer.WriteEndArray();");

                // Reader
                JsonAssertReadStartStatement(sinkReader, $"reader.TokenType != JsonToken.StartArray");
                sinkReader.content($"while (reader.Read())");
                sinkReader.openBrace();
                sinkReader.content("if (reader.TokenType == JsonToken.EndArray) { break; }");
                JsonAssertReadStartStatement(sinkReader, $"reader.TokenType != JsonToken.StartObject");
                sinkReader.content($"reader.Read();");     // key prop name
                sinkReader.content($"reader.Read();");     // key content
                ReadJsonValueStatement(sinkReader, new DataInfo {
                    type = keyType, baseAccess = $"key", insideConfigStorage = type.IsConfigStorage(), sureIsNull = true
                }, true);
                sinkReader.content($"reader.Read();");     // val prop name
                sinkReader.content($"reader.Read();");     // val content
                ReadJsonValueStatement(sinkReader, new DataInfo {
                    type = valType, baseAccess = $"val", insideConfigStorage = type.IsConfigStorage(), sureIsNull = true
                }, true);
                sinkReader.content($"reader.Read();");     // end keyval obj
                sinkReader.content($"{accessPrefix}.Add(key, val);");
                sinkReader.closeBrace();
            }
            else
            {
                bool externalMode  = !type.IsControllable() || type.IsStruct();
                bool immutableMode = type.IsStruct() && !type.IsControllable();

                string readerFuncName = funcPrefix + JsonReadFuncName + (!externalMode ? "Field" : "") +
                                        (immutableMode ? type.UniqueName() : "");
                var sinkReader = MakeGenMethod(type, GenTaskFlags.JsonSerialization, readerFuncName, immutableMode ? type : Void,
                                               $"{(immutableMode ? "this " : "")}JsonTextReader {readerName}{(!externalMode ? ", string name" : "")}", immutableMode);
                var sinkWriter = MakeGenMethod(type, GenTaskFlags.JsonSerialization, funcPrefix + JsonWriteFuncName + (!externalMode ? "Fields" : ""), Void, $"JsonTextWriter {writerName}");

                if (immutableMode)
                {
                    sinkReader.content($"var self = new {type.RealName(true)}();");
                }

                if (externalMode)
                {
                    sinkReader.content($"while (reader.Read())");
                    sinkReader.openBrace();
                    sinkReader.content($"if (reader.TokenType == JsonToken.PropertyName)");
                    sinkReader.openBrace();
                    sinkReader.content($"var name = (string) reader.Value;");
                    sinkReader.content($"reader.Read();");

                    sinkWriter.content($"writer.WriteStartObject();");
                }

                type.ProcessMembers(GenTaskFlags.JsonSerialization, true, info =>
                {
                    WriteJsonValueStatement(sinkWriter, info, false);
                });

                if (type.IsControllable() && type.IsValueType == false)
                {
                    sinkReader.classBuilder.inheritance("IJsonSerializable");
                }
                sinkReader.content($"switch(name)");
                sinkReader.openBrace();
                type.ProcessMembers(GenTaskFlags.JsonSerialization, true, info =>
                {
                    sinkReader.content($"case \"{info.name}\":");
                    ReadJsonValueStatement(sinkReader, info, false);
                    sinkReader.content($"break;");
                });
                sinkReader.closeBrace();

                if (externalMode)
                {
                    sinkReader.closeBrace();
                    sinkReader.content("else if (reader.TokenType == JsonToken.EndObject) { break; }");
                    sinkReader.closeBrace();
                    sinkWriter.content($"writer.WriteEndObject();");
                }

                if (immutableMode)
                {
                    sinkReader.content("return self;");
                }
            }
        }
Пример #6
0
        public static void GenUpdateFrom(Type type, bool pooled, string funcPrefix = "")
        {
            const string instanceCastedName = "otherConcrete";
            const string instanceName       = "other";

            string otherName = instanceName;
            var    flag      = pooled ? GenTaskFlags.PooledUpdateFrom : GenTaskFlags.UpdateFrom;

            var updateFromType = type.TopParentImplementingFlag(flag) ?? type;

            MethodBuilder sink = MakeGenMethod(type, flag, funcPrefix + UpdateFuncName, typeof(void),
                                               $"{updateFromType.RealName(true)} {instanceName}{(pooled ? ", ObjectPool pool" : "")}");


            if (type.IsList())
            {
                // For livable list that we do not need to generate in not constructed form
                if (type.IsConstructedGenericType == false)
                {
                    return;
                }
                var elemType = type.GenericTypeArguments[0];
                SinkUpdateFromList(sink, elemType, type.AccessPrefixInGeneratedFunction(), otherName, pooled,
                                   updateWhenAssigned: type.IsDataList());
            }
            else if (type.IsArray)
            {
                var elemType = type.GetElementType();
                SinkArrayUpdateFromWithFixedSize(sink, elemType, type.AccessPrefixInGeneratedFunction(), otherName,
                                                 pooled);
            }
            else if (type.IsDictionary())
            {
                Error($"Update from for dictionary ({type}) is not supported");
            }
            else
            {
                if (type != updateFromType)
                {
                    otherName = instanceCastedName;
                    sink.content($"var {instanceCastedName} = ({type.RealName(true)}){instanceName};");

                    var directUpdateSink = GenClassSink(type).Method(funcPrefix + UpdateFuncName, type, MethodType.Instance, typeof(void),
                                                                     $"{type.RealName(true)} {instanceName}{(pooled ? ", ObjectPool pool" : "")}");

                    directUpdateSink.content($"this.UpdateFrom(({updateFromType.RealName(true)})other{(pooled ? ", pool" : "")});");
                    directUpdateSink.classBuilder.inheritance($"I{(pooled ? "Pooled" : "")}UpdatableFrom<{type.RealName(true)}>");
                }
                if (type.IsControllable())
                {
                    GenClassSink(type)
                    .inheritance($"I{(pooled ? "Pooled" : "")}UpdatableFrom<{updateFromType.RealName(true)}>");
                }

                type.ProcessMembers(flag, true,
                                    memberInfo =>
                {
                    GenUpdateValueFromInstance(sink, memberInfo,
                                               memberInfo.valueTransformer($"{otherName}.{memberInfo.baseAccess}"), pooled);
                });
            }
        }