Example #1
0
 // The factory method is JsonSerializationCodeGen.CreateTypeInfo.
 internal JsonTypeInfo(NullableTypeTree t, int number, string name, IReadOnlyList <string>?previousNames, JsonCodeGenHandler?writeHandler)
 {
     Debug.Assert(number >= 0 && t.IsNormalNull);
     Type = t;
     // We cannot use the oblivious type (that may have computed for the writeHandler) here because
     // value tuple must use their generic form (not the parentheses) in switch case.
     GenCSharpName = t.Type.ToCSharpName(useValueTupleParentheses: false);
     Number        = number;
     NumberName    = number.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
     TypeSpecOrder = -1.0f;
     // By default, the ECMAScriptStandardJsonName is the JsonName.
     NonNullableJsonName = name;
     NonNullableECMAScriptStandardJsonName = new ECMAScriptStandardJsonName(name, false);
     NonNullablePreviousJsonNames          = previousNames ?? Array.Empty <string>();
     if (t.Type.IsValueType)
     {
         NonNullHandler = new HandlerForValueType(this);
     }
     else
     {
         var n = new HandlerForReferenceType(this);
         NonNullHandler = n.ToNonNullHandler();
     }
     GenericWriteHandler = writeHandler ?? NonNullHandler;
 }
        JsonTypeInfo?TryRegisterInfoForEnum(NullableTypeTree t)
        {
            if (!t.Type.GetExternalNames(_monitor, out string name, out string[]? previousNames))
            {
                return(null);
            }
            var uT        = Enum.GetUnderlyingType(t.Type).GetNullableTypeTree();
            var uTHandler = _map[uT];

            var info = AllowTypeInfo(t.ToNormalNull(), name, previousNames);

            return(info?.Configure(
                       (ICodeWriter write, string variableName)
                       => write.Append("w.WriteNumberValue( (").Append(uTHandler.GenCSharpName).Append(')').Append(variableName).Append(" );"),
                       (ICodeWriter read, string variableName, bool assignOnly, bool isNullable)
                       =>
            {
                // No need to defer here: the underlying types are basic number types.
                read.OpenBlock()
                .Append("var ");
                uTHandler.GenerateRead(read, "u", true);
                read.NewLine()
                .Append(variableName).Append(" = (").Append(info.GenCSharpName).Append(")u;")
                .CloseBlock();
            }));
        }
 public HandlerForTypeMapping(JsonCodeGenHandler mapping, NullableTypeTree t)
 {
     Debug.Assert(mapping is HandlerForReferenceType && mapping.IsNullable);
     _mapping      = mapping;
     Type          = t;
     GenCSharpName = t.Type.ToCSharpName();
     _nonNullable  = new HandlerForNonNullableTypeMapping(this);
 }
Example #4
0
 /// <summary>
 /// Initializes a new <see cref="TSType"/> for a <see cref="NullableTypeTree"/> that must be "normally null".
 /// </summary>
 /// <param name="t">The type.</param>
 /// <param name="typeName">The TypeScript type name to use.</param>
 /// <param name="imports">Required imports if any.</param>
 public TSType(NullableTypeTree t, string typeName, IReadOnlyList <TSTypeFile> imports)
 {
     if (!t.IsNormalNull)
     {
         throw new ArgumentException("NullableTypeTree must be IsNormalNull.", nameof(t));
     }
     Type     = t;
     TypeName = typeName;
     Imports  = imports;
 }
Example #5
0
 public PocoPropertyInfo(PropertyInfo first,
                         int initialIndex,
                         bool isReadOnly,
                         NullabilityTypeInfo nullabilityTypeInfo,
                         NullableTypeTree nullTree,
                         bool isStandardCollection)
 {
     DeclaredProperties = new List <PropertyInfo>()
     {
         first
     };
     Index                    = initialIndex;
     IsReadOnly               = isReadOnly;
     NullabilityTypeInfo      = nullabilityTypeInfo;
     PropertyNullableTypeTree = nullTree;
     IsStandardCollectionType = isStandardCollection;
 }
Example #6
0
        /// <summary>
        /// Factory for <see cref="JsonTypeInfo"/>: its <see cref="JsonTypeInfo.NumberName"/> is unique.
        /// This should be called only once per type that must be <see cref="NullableTypeTree.IsNormalNull"/>.
        /// To create a <see cref="NullableTypeTree"/> from a type, use the <see cref="NullabilityTypeExtensions.GetNullabilityKind(Type)"/>
        /// extension method.
        /// </summary>
        /// <param name="normalType">The type.</param>
        /// <param name="name">The non nullable serialized type name.</param>
        /// <param name="previousNames">Optional non nullable previous names.</param>
        /// <returns>A new type info.</returns>
        public JsonTypeInfo?CreateTypeInfo(NullableTypeTree normalType, string name, IReadOnlyList <string>?previousNames = null)
        {
            if (!normalType.IsNormalNull)
            {
                throw new ArgumentException("Must be a 'normalized null' type.", nameof(normalType));
            }
            if (name == null || name.Length == 0 || name[^ 1] == '?')
            {
                throw new ArgumentException("Must be a non nullable serialized type name.", nameof(name));
            }
            if (normalType.Type == typeof(void))
            {
                throw new ArgumentException("The typeof(void) type is invalid.", nameof(name));
            }

            JsonCodeGenHandler?writeHandler = null;

            if (normalType.RawSubTypes.Count > 0)
            {
                var oblivious = normalType.Type.GetNullableTypeTree();
                if (oblivious != normalType)
                {
                    if (oblivious.Kind.IsReferenceType())
                    {
                        oblivious = oblivious.ToAbnormalNull();
                    }
                    writeHandler = GetHandler(oblivious);
                    if (writeHandler == null)
                    {
                        _monitor.Error($"Unable to obtain the GenericWriteHandler for oblivious '{oblivious}' for type '{normalType}'.");
                        return(null);
                    }
                }
            }
            return(new JsonTypeInfo(normalType, _typeInfoAutoNumber++, name, previousNames, writeHandler));
        }
Example #7
0
        /// <summary>
        /// Simple helper that calls <see cref="CreateTypeInfo"/> and <see cref="AllowTypeInfo(JsonTypeInfo)"/>.
        /// The Json type info is created and allowed but its <see cref="JsonTypeInfo.Configure(CodeWriter, CodeReader)"/> must still be called.
        /// </summary>
        /// <param name="t">The type to allow..</param>
        /// <param name="name">The serialized name.</param>
        /// <param name="previousNames">Optional list of previous names (act as type aliases).</param>
        /// <returns>The allowed type info that must still be configured or null if it cannot be created.</returns>
        public JsonTypeInfo?AllowTypeInfo(NullableTypeTree t, string name, IReadOnlyList <string>?previousNames = null)
        {
            var info = CreateTypeInfo(t, name, previousNames);

            return(info == null ? null : AllowTypeInfo(info));
        }
 JsonCodeGenHandler ConfigureAndAddTypeInfoForListSetAndMap(JsonTypeInfo info, IFunctionScope fWrite, IFunctionScope fRead, NullableTypeTree tInterface)
 {
     Debug.Assert(!info.Type.Type.IsInterface && tInterface.Type.IsInterface);
     info.Configure(
         (ICodeWriter write, string variableName) =>
     {
         write.Append("PocoDirectory_CK.").Append(fWrite.Definition.MethodName.Name).Append("( w, ").Append(variableName).Append(", options );");
     },
         (ICodeWriter read, string variableName, bool assignOnly, bool isNullableVariable) =>
     {
         if (!assignOnly)
         {
             if (isNullableVariable)
             {
                 read.Append("if( ").Append(variableName).Append(" == null )")
                 .OpenBlock()
                 .Append(variableName).Append(" = new ").Append(info.GenCSharpName).Append("();")
                 .CloseBlock();
             }
             else
             {
                 read.Append(variableName).Append(".Clear();").NewLine();
             }
         }
         else
         {
             read.Append(variableName).Append(" = new ").Append(info.GenCSharpName).Append("();").NewLine();
         }
         // We cast the variable into its type to handle the case where the variable is an 'object' (or
         // any other base type) since these are regular collections (arrays are not handled here).
         read.Append("PocoDirectory_CK.")
         .Append(fRead.Definition.MethodName.Name)
         .Append("( ref r, (")
         .Append(info.GenCSharpName)
         .Append(")")
         .Append(variableName)
         .Append(", options );");
     });
     // The interface maps to the collection type and is its MostAbstractMapping.
     AllowTypeAlias(tInterface.ToNormalNull(), info, isMostAbstract: true);
     AllowTypeInfo(info);
     return(info.NullHandler);
 }
 /// <summary>
 /// Initializes a new <see cref="TypeInfoRequiredEventArg"/>.
 /// </summary>
 /// <param name="monitor">The monitor that event handlers should use.</param>
 /// <param name="c">The Json code generator context.</param>
 /// <param name="requiredType">The type for which Json serialization code is required.</param>
 public TypeInfoRequiredEventArg(IActivityMonitor monitor, JsonSerializationCodeGen c, NullableTypeTree requiredType)
     : base(monitor)
 {
     JsonCodeGen  = c;
     RequiredType = requiredType;
 }
Example #10
0
 static void CheckMirror(NullableTypeTree normal, NullableTypeTree abnormal)
 {
     normal.ToAbnormalNull().ToNormalNull().Should().Be(normal);
     abnormal.ToNormalNull().ToAbnormalNull().Should().Be(abnormal);
 }
Example #11
0
        JsonTypeInfo?TryRegisterInfoForValueTuple(NullableTypeTree t, IReadOnlyList <NullableTypeTree> types)
        {
            JsonCodeGenHandler[] handlers = new JsonCodeGenHandler[types.Count];
            bool isJSCanonical            = true;
            var  jsonName   = new StringBuilder("[");
            var  jsJsonName = new StringBuilder("[");

            for (int i = 0; i < types.Count; i++)
            {
                if (i > 0)
                {
                    jsonName.Append(',');
                    jsJsonName.Append(',');
                }
                var h = GetHandler(types[i]);
                if (h == null)
                {
                    return(null);
                }
                handlers[i] = h;
                jsonName.Append(h.JsonName);
                isJSCanonical &= h.TypeInfo.NonNullableECMAScriptStandardJsonName.IsCanonical;
                jsJsonName.Append(h.TypeInfo.NonNullableECMAScriptStandardJsonName.Name);
            }
            jsonName.Append(']');
            jsJsonName.Append(']');

            JsonTypeInfo?info = AllowTypeInfo(t.ToNormalNull(), jsonName.ToString());

            if (info == null)
            {
                return(null);
            }

            info.SetECMAScriptStandardName(jsJsonName.ToString(), isJSCanonical);

            // Don't use 'in' modifier on non-readonly structs: See https://devblogs.microsoft.com/premier-developer/the-in-modifier-and-the-readonly-structs-in-c/
            // We use a 'ref' instead (ValueTuple TypeInfo below use SetByRefWriter).
            var fWriteDef = FunctionDefinition.Parse("internal static void WriteVT_" + info.NumberName + "( System.Text.Json.Utf8JsonWriter w, ref " + info.GenCSharpName + " v, PocoJsonSerializerOptions options )");
            var fReadDef  = FunctionDefinition.Parse("internal static void ReadVT_" + info.NumberName + "( ref System.Text.Json.Utf8JsonReader r, out " + info.GenCSharpName + " v, PocoJsonSerializerOptions options )");

            IFunctionScope?fWrite = _pocoDirectory.FindFunction(fWriteDef.Key, false);
            IFunctionScope?fRead;

            if (fWrite != null)
            {
                fRead = _pocoDirectory.FindFunction(fReadDef.Key, false);
                Debug.Assert(fRead != null);
            }
            else
            {
                fWrite = _pocoDirectory.CreateFunction(fWriteDef);
                fRead  = _pocoDirectory.CreateFunction(fReadDef);
                _finalReadWrite.Add(m =>
                {
                    fWrite.Append("w.WriteStartArray();").NewLine();
                    int itemNumber = 0;
                    foreach (var h in handlers)
                    {
                        h.GenerateWrite(fWrite, "v.Item" + (++itemNumber).ToString(CultureInfo.InvariantCulture));
                    }
                    fWrite.Append("w.WriteEndArray();").NewLine();

                    fRead.Append("r.Read();").NewLine();

                    itemNumber = 0;
                    foreach (var h in handlers)
                    {
                        h.GenerateRead(fRead, "v.Item" + (++itemNumber).ToString(CultureInfo.InvariantCulture), true);
                    }
                    fRead.Append("r.Read();").NewLine();
                });
            }

            info.SetByRefWriter()
            .Configure(
                (ICodeWriter write, string variableName) =>
            {
                write.Append("PocoDirectory_CK.").Append(fWrite.Definition.MethodName.Name).Append("( w, ref ").Append(variableName).Append(", options );");
            },
                (ICodeWriter read, string variableName, bool assignOnly, bool variableCanBeNull) =>
            {
                string vName = variableName;
                if (variableCanBeNull)
                {
                    read.OpenBlock()
                    .Append(info.GenCSharpName).Append(" notNull;").NewLine();
                    vName = "notNull";
                }
                read.Append("PocoDirectory_CK.").Append(fRead.Definition.MethodName.Name).Append("( ref r, out ").Append(vName).Append(", options );");
                if (variableCanBeNull)
                {
                    read.Append(variableName).Append(" = notNull;")
                    .CloseBlock();
                }
            });

            return(info);
        }