// 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); }
/// <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; }
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; }
/// <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)); }
/// <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; }
static void CheckMirror(NullableTypeTree normal, NullableTypeTree abnormal) { normal.ToAbnormalNull().ToNormalNull().Should().Be(normal); abnormal.ToNormalNull().ToAbnormalNull().Should().Be(abnormal); }
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); }