static void PrintGenericSwitch(this Type genericDef, MethodBuilder sink,
                                       Action <Type, MethodBuilder> codeForType)
        {
            //TODO implement for multiple generic args
            var T = genericDef.GetGenericArguments()[0];

            if (genericDef.IsConstructedGenericType)
            {
                genericDef = genericDef.GetGenericTypeDefinition();
            }

            if (genericInstances.ContainsKey(genericDef))
            {
                bool first = true;
                foreach (var type in genericInstances[genericDef])
                {
                    sink.content(
                        $"{(first ? "" : "else ")} if (typeof({T.Name}) == typeof({type.FirstGenericArg()})) {{");
                    sink.indent++;
                    codeForType(type, sink);
                    sink.indent--;
                    sink.content($"}}");
                    first = false;
                }
            }
        }
 public static void GenWriteNullableToStream(MethodBuilder sink, DataInfo info, string stream, bool writeDataNodeAsId = false)
 {
     sink.content($"if ({info.access} == null) {stream}.Write(false);");
     sink.content($"else {{");
     sink.indent++;
     sink.content($"{stream}.Write(true);");
     WriteToStreamStatement(sink, info, stream, writeDataNodeAsId);
     sink.indent--;
     sink.content($"}}");
 }
 public static void SinkArrayWriterCode(MethodBuilder sink, DataInfo info, string stream)
 {
     sink.content($"{stream}.Write({info.access}.Length);");
     sink.content($"for (int i = 0; i < {info.access}.Length; i++)");
     sink.content($"{{");
     sink.indent++;
     WriteToStreamStatement(sink, new DataInfo {
         type = info.type, baseAccess = $"{info.access}[i]"
     }, stream);
     sink.indent--;
     sink.content($"}}");
 }
 public static void SinkListWriterCode(Type listType, MethodBuilder sink, DataInfo info, string stream)
 {
     sink.content($"{stream}.Write({info.access}.Count);");
     sink.content($"for (int i = 0; i < {info.access}.Count; i++)");
     sink.content($"{{");
     sink.indent++;
     WriteToStreamStatement(sink, new DataInfo {
         type = info.type, baseAccess = $"{info.access}[i]", insideConfigStorage = listType.IsConfigStorage()
     }, stream);
     sink.indent--;
     sink.content($"}}");
 }
        public static void GenerateComparisonFunc(Type type, string funcPrefix)
        {
            const string instanceCastedName = "otherConcrete";
            const string instanceName       = "other";

            string otherName = instanceName;

            var updateFromType = type.TopParentImplementingFlag(GenTaskFlags.CompareChech) ?? type;

            MethodBuilder sink = MakeGenMethod(type, GenTaskFlags.CompareChech, funcPrefix + CompareFuncName, typeof(void),
                                               $"{updateFromType.RealName(true)} {instanceName}, Stack<string> path");

            if (type.IsList() || type.IsArray)
            {
                var countName = type.IsList() ? "Count" : "Length";
                var elemType  = type.FirstGenericArg();
                CompareCheckValue(sink, new DataInfo {
                    type       = typeof(int), pathLog = $"\"{countName}\"",
                    baseAccess = $"self.{countName}"
                }, $"{otherName}.{countName}");
                sink.content($"var count = Math.Min(self.{countName}, {otherName}.{countName});");
                sink.content($"for (int i = 0; i < count; i++)");
                sink.content($"{{");
                sink.indent++;
                CompareCheckValue(sink, new DataInfo {
                    type = elemType, baseAccess = $"self[i]", pathLog = $"i.ToString()"
                }, $"{otherName}[i]");
                sink.indent--;
                sink.content($"}}");
            }
            else
            {
                if (type.IsControllable())
                {
                    GenClassSink(type)
                    .inheritance($"ICompareChechable<{updateFromType.RealName(true)}>");
                }
                if (type != updateFromType)
                {
                    otherName = instanceCastedName;
                    sink.content($"var {instanceCastedName} = ({type.RealName(true)}){instanceName};");
                }

                var hasMembers = type.ProcessMembers(GenTaskFlags.CompareChech, true, memberInfo =>
                {
                    CompareCheckValue(sink, memberInfo, memberInfo.valueTransformer($"{otherName}.{memberInfo.baseAccess}"));
                });
                if (!hasMembers && sink.type == MethodType.Override)
                {
                    sink.doNotGen = true;
                }
            }
        }
Beispiel #6
0
 public static void SinkArrayUpdateFromWithFixedSize(MethodBuilder sink, Type type, string prefix, string other,
                                                     bool pooled)
 {
     sink.content($"for (int i = 0; i < {prefix}.Length; i++)");
     sink.content($"{{");
     sink.indent++;
     GenUpdateValueFromInstance(sink, new DataInfo {
         type = type, baseAccess = $"{prefix}[i]", canBeNull = true
     },
                                $"{other}[i]", pooled);
     sink.indent--;
     sink.content($"}}");
 }
 public static void TraversGenList(TraversStrategy strategy, MethodBuilder sink, Type elemType, string prefix, bool isArray)
 {
     strategy.start?.Invoke(sink, false);
     sink.content($"var size = {prefix}.{(isArray ? "Length" : "Count")};");
     sink.content($"for (int i = 0; i < size; i++)");
     sink.content($"{{");
     sink.indent++;
     strategy.elemProcess(sink, new DataInfo {
         type = elemType, baseAccess = $"{prefix}[i]"
     });
     sink.indent--;
     sink.content($"}}");
     strategy.finish?.Invoke(sink);
 }
 public static void SinkDictReaderCode(MethodBuilder sink, Type keyType, Type valType, string path,
                                       string stream, bool pooled, bool configStorage)
 {
     sink.content($"var size = {stream}.ReadInt32();");
     //sink.content($"{path}.Capacity = size;");
     sink.content($"for (int i = 0; i < size; i++)");
     sink.content($"{{");
     sink.indent++;
     sink.content($"var key = default({keyType.RealName(true)});");
     GenReadValueFromStream(sink, new DataInfo {
         type = keyType, baseAccess = $"key", sureIsNull = true, insideConfigStorage = configStorage
     }, stream, pooled);
     sink.content($"var val = default({valType.RealName(true)});");
     GenReadValueFromStream(sink, new DataInfo {
         type = valType, baseAccess = $"val", sureIsNull = true, insideConfigStorage = configStorage
     }, stream,
                            pooled);
     if (configStorage)
     {
         sink.content($"{path}.Add(val);"); // ConfigStorageDict must use id as a key.
     }
     else
     {
         sink.content($"{path}.Add(key, val);");
     }
     sink.indent--;
     sink.content($"}}");
 }
 public static void SinkDictWriterCode(MethodBuilder sink, Type keyType, Type valType, string path, string stream, bool configStorage)
 {
     sink.content($"{stream}.Write({path}.Count);");
     sink.content($"foreach (var item in {path})");
     sink.content($"{{");
     sink.indent++;
     WriteToStreamStatement(sink, new DataInfo {
         type = keyType, baseAccess = $"item.Key", insideConfigStorage = configStorage
     }, stream);
     WriteToStreamStatement(sink, new DataInfo {
         type = valType, baseAccess = $"item.Value", insideConfigStorage = configStorage
     }, stream);
     sink.indent--;
     sink.content($"}}");
 }
        public static void SinkListReaderCode(Type listType, MethodBuilder sink, Type type, string path, string stream, bool pooled)
        {
            string count = listType.IsList() ? "Count" : "Length";

            sink.content($"var size = {stream}.ReadInt32();");
            sink.content($"{path}.Capacity = size;");
            sink.content($"for (int i = 0; i < size; i++)");
            sink.content($"{{");
            sink.indent++;
            if (type.IsDataNode())
            {
                sink.content($"self.Add(null);");
                GenReadValueFromStream(sink,
                                       new DataInfo {
                    type       = type, baseAccess = $"self[self.{count} - 1]", insideConfigStorage = listType.IsConfigStorage(),
                    sureIsNull = true
                }, stream, pooled, false);
            }
            else
            {
                GenReadValueFromStream(sink, new DataInfo {
                    type = type, baseAccess = $"val", sureIsNull = true, insideConfigStorage = listType.IsConfigStorage()
                },
                                       stream, pooled, true);
                sink.content($"self.Add(val);");
            }
            sink.indent--;
            sink.content($"}}");
        }
 public static void TraverseGenDict(TraversStrategy strategy, MethodBuilder sink, Type keyType, Type valType, string path)
 {
     strategy.start?.Invoke(sink, false);
     sink.content($"foreach (var item in {path})");
     sink.content($"{{");
     sink.indent++;
     if (strategy.needDictKeyTraverse)
     {
         strategy.elemProcess(sink, new DataInfo {
             type = keyType, baseAccess = "item.Key"
         });
     }
     strategy.elemProcess(sink, new DataInfo {
         type = valType, baseAccess = "item.Value"
     });
     sink.indent--;
     sink.content($"}}");
     strategy.finish?.Invoke(sink);
 }
        public static void CompareCheckValue(MethodBuilder sink, DataInfo info, string otherValueReader)
        {
            if (info.type.IsAlmostPrimitive() || info.type.IsEnum || info.type.IsString())
            {
                sink.content($"if ({info.access} != {otherValueReader}) {CompErrorFunc}(path, {info.pathName}, {otherValueReader}, {info.access});");
            }
//            else if (info.isStatic && info.type.IsValueType == false && info.type.IsList() == false)
//            {
//                sink.content($"{CompRef}(path, {info.pathName}, {otherValueReader}, {info.access});");
//            }
            else
            {
                if (info.canBeNull)
                {
                    sink.content($"if ({CompNullComp}(path, {info.pathName}, {info.access}, {otherValueReader})) {{");
                    sink.indent++;
                }
                if (info.type.CanBeAncestor())
                {
                    sink.content($"if ({CompClassId}(path, {info.pathName}, {info.access}, {otherValueReader})) {{");
                    sink.indent++;
                }
                sink.content($"path.Push({info.pathName});");
                if (info.type.IsLoadableConfig())
                {
                    sink.content($"if ({info.access}.id != {otherValueReader}.id) {CompErrorFunc}(path, {info.pathName}, {otherValueReader}.id, {info.access}.id);");
                }
                else
                {
                    RequestGen(info.type, GenTaskFlags.CompareChech);
                    sink.content($"{info.access}.{CompareFuncName}({otherValueReader}, path);");
                }
                sink.content($"path.Pop();");
                if (info.type.CanBeAncestor())
                {
                    sink.indent--;
                    sink.content($"}}");
                }
                if (info.canBeNull)
                {
                    sink.indent--;
                    sink.content($"}}");
                }
            }
        }
        static void ConfigFromId(MethodBuilder sink, DataInfo info, Func <Type, string> idReader, bool needCreateVar)
        {
            var type       = typeof(ulong);
            var configType = info.carrierType.ConfigRootType();

            if (configType == null)
            {
                //TODO fix, right now it is difficult to reach generation hierarchy and cleary undeerstand config loading type for a field
                //Error($"Config root type for {info.carrierType} is not specified please add ConfigRootType attribute on top of your class hierarchy");
                //configType = typeof(Library);
                //return;
            }
            sink.content($"{OptVar(needCreateVar)}{info.access} = ({info.type.RealName(true)}){configType.NameWithNamespace()}.GetConfig({idReader(type)});");
        }
Beispiel #14
0
        public static void GenUpdateValueFromInstance(MethodBuilder sink, DataInfo info, string other, bool pooled,
                                                      bool needCreateVar = false, bool needTempVarThenAssign = false, bool readDataNodeFromRootWithId = false)
        {
            var t = info.type;
            // info can be transformed because read from can do temp value wrapping for it
            Func <DataInfo, string> defaultContent = info1 =>
                                                     $"{info1.access}.{UpdateFuncName}({other}{t.OptPoolIfUpdatebleWithPoolSecondArg(pooled)});";
            Action <MethodBuilder, DataInfo> baseReadCall = (s, info1) => s.content(defaultContent(info1));

            if (t.IsValueType && !t.IsControllable() || info.immutableData || t.IsImmutableData())
            {
                sink.content($"{OptVar(needCreateVar)}{info.access} = {other};");
                return;
            }
            else if (t.IsArray && t.GetElementType() != typeof(byte))
            {
                baseReadCall = (s, info1) =>
                {
                    string name         = info1.name;
                    string newCountName = $"{name.Replace('[', '_').Replace(']', '_')}Count";
                    string tempVarName  = $"{name.Replace('[', '_').Replace(']', '_')}Temp";
                    s.content($"var {newCountName} = {other}.Length;");
                    s.content($"var {tempVarName} = {name};");
                    s.content($"Array.Resize(ref {tempVarName}, {newCountName});");
                    s.content($"{name} = {tempVarName};");
                    s.content(defaultContent(info1));
                };
            }

            RequestGen(info.type, pooled ? GenTaskFlags.PooledUpdateFrom : GenTaskFlags.UpdateFrom);

            GeneralReadFrom(sink, info,
                            baseReadCall: baseReadCall,
                            //arrayLengthReader: $"{other}.Length",
                            isNullReader: $"{other} == null",
                            //refIdReader: $"{other}.id",
                            classIdReader: $"{other}.{CodeGen.PolymorphClassIdGetter}",
                            pooled: pooled,
                            refInst: other,
                            refIdReader: other + ".id",
                            directReader: other,
                            needCreateVar: needCreateVar,
                            useTempVarThenAssign: needTempVarThenAssign,
                            getDataNodeFromRootWithRefId: readDataNodeFromRootWithId
                            );
        }
        public static void WriteToStreamStatement(MethodBuilder sink, DataInfo info, string stream, bool writeDataNodeAsId = false)
        {
            var t = info.type;

            if (t == typeof(byte[]))
            {
                sink.content($"{stream}.WriteByteArray({info.access});");
            }
            else if (t.IsConfig() && info.insideConfigStorage == false)
            {
                sink.content($"{stream}.Write({info.access}.{UIdFuncName}());");
                return;
            }
            else if (t.IsRef())
            {
                sink.content($"{stream}.Write({info.access}.id);");
            }
            else if (t.IsReferencableDataNode() && writeDataNodeAsId)
            {
                sink.content($"{stream}.Write({info.access}.Id);");
            }
            else if (t.IsPrimitive || t.IsString())
            {
                sink.content($"{stream}.Write({info.access});");
            }
            else if (t.IsEnum)
            {
                sink.content($"{stream}.Write(({t.GetEnumUnderlyingType().Name}){info.access});");
            }
            else
            {
                if (t.CanBeAncestor())
                {
                    sink.content($"{stream}.Write({info.access}.{CodeGen.PolymorphClassIdGetter});");
                }

                sink.content($"{info.access}.{WriteFuncName}({stream});");
            }
        }
 public static void SinkArrayReaderCode(MethodBuilder sink, Type type, string path, string stream, bool pooled)
 {
     path = "array";
     sink.content($"var size = {stream}.ReadInt32();");
     sink.content($"var {path} = new {type.RealName(true)}[size];");
     sink.content($"for (int i = 0; i < size; i++)");
     sink.content($"{{");
     sink.indent++;
     GenReadValueFromStream(sink, new DataInfo {
         type = type, baseAccess = $"{path}[i]", sureIsNull = true
     },
                            stream, pooled);
     sink.indent--;
     sink.content($"}}");
     sink.content($"return {path};");
 }
Beispiel #17
0
        public static void CreateNewInstance(MethodBuilder sink, DataInfo info, string classIdReader, bool pooled,
                                             string refInst, bool needCreateVar, bool wrapType = false)
        {
            // Some bullshit logic here
            // All of this because of value wrapper concept that should be reconsidered
            var t    = wrapType ? info.realType : info.type;
            var name = wrapType ? info.accessPrefix + info.baseAccess : info.access;

            string newExpr  = "";
            bool   needCast = false;

            if (t == typeof(string))
            {
                newExpr = "string.Empty";
            }
            else if (t.IsArray)
            {
                newExpr = $"Array.Empty<{t.RealName(true).Remove(t.RealName(true).Length - 2)}>()";
            }
            else if (t.CanBeAncestor() && info.cantBeAncestor == false)
            {
                needCast = true;
                if (CodeGenTools.Valid(refInst))
                {
                    string poolArg = "";
                    if (t.HasPool() && pooled)
                    {
                        poolArg = "pool";
                    }
                    newExpr = $"{refInst}.{PolymorphNewInstOfSameType}({poolArg})";
                }
                else
                {
                    if (CodeGenTools.Valid(classIdReader) == false)
                    {
                        if (t.IsAbstract)
                        {
                            return;
                        }
                        newExpr = NewInstExpr(t, pooled);
                    }
                    else
                    {
                        var staticTypeCreator = baseClassMap.GetOrDefault(t, t).RealName(true);
                        if (t.IsGenericParameter)
                        {
                            if (t.GetGenericParameterConstraints().TryFind(par => !par.IsInterface, out var hardPar))
                            {
                                staticTypeCreator = hardPar.RealName(true);
                            }
                            else
                            {
                                Error($"can't generate new instance construction for unknown type {t} in {info.carrierType}, constrain this type with some base class like DataNode");
                            }
                        }
                        newExpr = $"{staticTypeCreator}.{PolymorphInstanceFuncName}({classIdReader})";
                    }
                }
            }
            else
            {
createNormally:
                if (t.IsAbstract)
                {
                    Error($"Type {t} is abstract but required to have constructor during {sink.classBuilder.name} generation");
                    return;
                }
                newExpr = NewInstExpr(t, pooled, info.defaultValue);
            }

            sink.content($"{(needCreateVar ? "var " : "")}{name} = {(needCast ? $"({t.RealName(true)})" : "")}{newExpr};");
        }
Beispiel #18
0
        public static void GeneralReadFrom(MethodBuilder sink, DataInfo info,
                                           Action <MethodBuilder, DataInfo> baseReadCall, string isNullReader, string classIdReader,
                                           string directReader, string refInst, string refIdReader, bool pooled, Func <Type, string> configIdReader = null, bool needCreateVar = false,
                                           bool useTempVarThenAssign = false, bool getDataNodeFromRootWithRefId = false)
        {
            var t         = info.type;
            var canBeNull = info.canBeNull && !t.IsValueType;

            var    originalInfo = info;
            string tempVar      = "__" + originalInfo.baseAccess.Replace("[", "").Replace("]", "");

            if (useTempVarThenAssign)
            {
                sink.content($"var {tempVar} = {originalInfo.access};");
                info = new DataInfo
                {
                    type       = originalInfo.type,
                    baseAccess = tempVar,
                };
            }

            var  name          = info.access;
            bool newInstCalled = false;

            if (needCreateVar)
            {
                sink.content($"{info.type.RealName(true)} {info.name} = default;");
            }

            if (t.IsImmutableValueType() || t.IsValueType && t.IsControllable() == false)
            {
                sink.content($"{name} = {directReader};");
                return;
            }
            else if (t.IsRef())
            {
                if (CodeGenTools.Valid(refIdReader))
                {
                    sink.content($"{info.access}.id = {refIdReader};");
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
            else
            {
                if (canBeNull)
                {
                    sink.content($"if ({isNullReader}) {{");
                    sink.indent++;
                    SinkRemovePostProcess(sink, info, pooled);
                    sink.content($"{name} = null;");
                    sink.indent--;
                    sink.content($"}}");
                    sink.content($"else {{ ");
                    sink.indent++;
                }

                bool fromExternalSource = false;
                if (t.IsConfig() && info.insideConfigStorage == false)
                {
                    ConfigFromId(sink, info, configIdReader, false);
                    fromExternalSource = true;
                }
                else if (getDataNodeFromRootWithRefId && typeof(IReferencableFromDataRoot).IsAssignableFrom(t))
                {
                    sink.content($"{info.access} = ({info.type.RealName(true)})root.Recall({refIdReader});");
                    fromExternalSource = true;
                }
                else
                {
                    if (info.sureIsNull && !info.type.IsValueType)
                    {
                        CreateNewInstance(sink, info, classIdReader, pooled, refInst, false);
                        newInstCalled = true;
                    }
                    else
                    {
                        string createNewCondition = "";
                        if (canBeNull || info.CanBeNullAfterConstruction())
                        {
                            createNewCondition = $"{name} == null";
                        }

                        string classIdVarName = $"{name.Replace('[', '_').Replace(']', '_').Replace('.', '_')}ClassId";
                        if (t.CanBeAncestor() && info.cantBeAncestor == false)
                        {
                            sink.content($"var {classIdVarName} = {classIdReader};");
                            createNewCondition = AddOrCondition(createNewCondition,
                                                                $"{name}.{PolymorphClassIdGetter} != {classIdVarName}");
                        }
                        if (info.type.IsImmutableType() == false && CodeGenTools.Valid(createNewCondition))
                        {
                            sink.content($"if ({createNewCondition}) {{");
                            sink.indent++;
                            SinkRemovePostProcess(sink, info, pooled);
                            CreateNewInstance(sink, info, classIdVarName, pooled, refInst, false);
                            newInstCalled = true;
                            sink.indent--;
                            sink.content($"}}");
                        }
                    }
                }

                if (!fromExternalSource)
                {
                    baseReadCall(sink, info);
                }

                if (canBeNull)
                {
                    sink.indent--;
                    sink.content($"}}");
                }
            }

            if (useTempVarThenAssign)
            {
                sink.content($"{originalInfo.access} = {tempVar};");
            }
        }
        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;");
                }
            }
        }
Beispiel #20
0
        public static void SinkUpdateFromList(MethodBuilder sink, Type elementType,
                                              string accessPrefix, string other, bool pooled, bool updateWhenAssigned)
        {
            var refInst = $"{other}[i]";

            sink.content($"int i = 0;");
            sink.content($"int oldCount = {accessPrefix}.Count;");
            sink.content($"int crossCount = Math.Min(oldCount, {other}.Count);");
            sink.content($"for (; i < crossCount; ++i)");
            sink.content($"{{");
            sink.indent++;
            GenUpdateValueFromInstance(sink, new DataInfo {
                type = elementType, baseAccess = $"self[i]"
            }, refInst,
                                       pooled,
                                       needTempVarThenAssign: elementType.IsValueType);
            sink.indent--;
            sink.content($"}}");
            sink.content($"for (; i < {other}.Count; ++i)");
            sink.content($"{{");
            sink.indent++;
            if (updateWhenAssigned)
            {
                sink.content($"self.Add(null);");
                GenUpdateValueFromInstance(sink, new DataInfo {
                    type = elementType, baseAccess = $"self[i]", sureIsNull = true
                },
                                           refInst, pooled: pooled);
            }
            else
            {
                GenUpdateValueFromInstance(sink, new DataInfo {
                    type = elementType, baseAccess = $"inst", sureIsNull = true
                },
                                           refInst, needCreateVar: true,
                                           pooled: pooled);
                sink.content($"self.Add(inst);");
            }
            sink.indent--;
            sink.content($"}}");
            sink.content($"for (; i < oldCount; ++i)");
            sink.content($"{{");
            sink.indent++;
            SinkRemovePostProcess(sink,
                                  new DataInfo {
                type = elementType, baseAccess = $"self[{accessPrefix}.Count - 1]"
            }, pooled);
            sink.content($"self.RemoveAt({accessPrefix}.Count - 1);");
            sink.indent--;
            sink.content($"}}");
        }
Beispiel #21
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);
                });
            }
        }
Beispiel #22
0
 static void JsonAssertReadStartStatement(MethodBuilder sink, string condition)
 {
     sink.content($"if ({condition}) throw new JsonSerializationException(\"Bad Json Format\");");
 }
Beispiel #23
0
        public static void WriteJsonValueStatement(MethodBuilder sink, DataInfo info, bool inList, bool writeDataNodeAsId = false)
        {
            var t = info.type;

            if (t.IsConfig() == false)
            {
                RequestGen(t, GenTaskFlags.JsonSerialization);
            }

            if (info.canBeNull)
            {
                sink.content($"if ({info.access} == null)");
                sink.openBrace();
                if (!inList)
                {
                    sink.content($"writer.WritePropertyName(\"{info.name}\");");
                }
                sink.content($"writer.WriteNull();");
                sink.closeBrace();
                sink.content($"else");
                sink.openBrace();
            }

            if (!inList)
            {
                sink.content($"writer.WritePropertyName(\"{info.name}\");");
            }

            if (t.IsFix64())
            {
                sink.content($"writer.WriteValue({info.access}.RawValue);");
                sink.content($"writer.WriteFixedPreview({info.access}, \"{info.access}\");");
                return;
            }
            else if (writeDataNodeAsId && t.IsDataNode() && typeof(IReferencableFromDataRoot).IsAssignableFrom(t))
            {
                sink.content($"writer.WriteValue({info.access}.id);");
            }
            else if (t == typeof(byte[]))
            {
                sink.content($"writer.WriteValue({info.access}.ToBase64());");
            }
            else if (t.IsConfig())
            {
                sink.content($"writer.WriteValue({info.access}.{UIdFuncName}());");
            }
            else if (t.IsRef())
            {
                sink.content($"writer.WriteValue({info.access}.id);");
            }
            else if (t.IsPrimitive || t.IsString())
            {
                sink.content($"writer.WriteValue({info.access});");
            }
            else if (t.IsEnum)
            {
                sink.content($"writer.WriteValue({info.access}.ToString());");
            }
            else
            {
                sink.content($"{info.access}.{JsonWriteFuncName}(writer);");
            }

            if (info.canBeNull)
            {
                sink.closeBrace();
            }
        }