Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1822,44 +1822,49 @@ private MethodBodyStatement CreateValueSerializationStatement(
SerializationFormat serializationFormat,
ValueExpression value)
{
// append the `.Value` if needed (when the type is nullable and a value type)
value = value.NullableStructValue(type);

// now we just need to focus on how we serialize a value
if (type.IsFrameworkType)
return ScmCodeModelGenerator.Instance.TypeFactory.SerializeJsonValue(type.FrameworkType, value, _utf8JsonWriterSnippet, _mrwOptionsParameterSnippet, serializationFormat);

if (!type.IsEnum)
return _utf8JsonWriterSnippet.WriteObjectValue(value.As(type), options: _mrwOptionsParameterSnippet);

if (type.IsStruct) //is extensible
{
if (type.UnderlyingEnumType.Equals(typeof(string)))
return _utf8JsonWriterSnippet.WriteStringValue(value.Invoke(nameof(ToString)));

return _utf8JsonWriterSnippet.WriteNumberValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}"));
}
else
{
if (type.UnderlyingEnumType.Equals(typeof(int)))
// when the fixed enum is implemented as int, we cast to the value
return _utf8JsonWriterSnippet.WriteNumberValue(value.CastTo(type.UnderlyingEnumType));

if (type.UnderlyingEnumType.Equals(typeof(string)))
return _utf8JsonWriterSnippet.WriteStringValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}"));

return _utf8JsonWriterSnippet.WriteNumberValue(value.Invoke($"ToSerial{type.UnderlyingEnumType.Name}"));
}
return ScmCodeModelGenerator.Instance.TypeFactory.SerializeJsonValue(type, value, _utf8JsonWriterSnippet, _mrwOptionsParameterSnippet, serializationFormat);
}

internal static MethodBodyStatement SerializeJsonValueCore(
Type valueType,
CSharpType valueType,
ValueExpression value,
ScopedApi<Utf8JsonWriter> utf8JsonWriter,
ScopedApi<ModelReaderWriterOptions> mrwOptionsParameter,
SerializationFormat serializationFormat)
{
MethodBodyStatement? statement = valueType switch
// append the `.Value` if needed (when the type is nullable and a value type)
value = value.NullableStructValue(valueType);

// Handle enums
if (valueType.IsEnum)
{
if (valueType.IsStruct) // extensible enum
{
if (valueType.UnderlyingEnumType.Equals(typeof(string)))
return utf8JsonWriter.WriteStringValue(value.Invoke(nameof(ToString)));

return utf8JsonWriter.WriteNumberValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}"));
}
else // fixed enum
{
if (valueType.UnderlyingEnumType.Equals(typeof(int)))
// when the fixed enum is implemented as int, we cast to the value
return utf8JsonWriter.WriteNumberValue(value.CastTo(valueType.UnderlyingEnumType));

if (valueType.UnderlyingEnumType.Equals(typeof(string)))
return utf8JsonWriter.WriteStringValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}"));

return utf8JsonWriter.WriteNumberValue(value.Invoke($"ToSerial{valueType.UnderlyingEnumType.Name}"));
}
}

// Handle non-enum types
if (!valueType.IsFrameworkType)
return utf8JsonWriter.WriteObjectValue(value.As(valueType), options: mrwOptionsParameter);

// Handle framework types
var frameworkType = valueType.FrameworkType;
MethodBodyStatement? statement = frameworkType switch
{
var t when t == typeof(JsonElement) =>
value.As<JsonElement>().WriteTo(utf8JsonWriter),
Expand All @@ -1868,21 +1873,21 @@ var t when ValueTypeIsInt(t) && serializationFormat == SerializationFormat.Int_S
var t when ValueTypeIsNumber(t) =>
utf8JsonWriter.WriteNumberValue(value),
var t when t == typeof(object) =>
utf8JsonWriter.WriteObjectValue(value.As(valueType), mrwOptionsParameter),
utf8JsonWriter.WriteObjectValue(value.As(frameworkType), mrwOptionsParameter),
var t when t == typeof(string) || t == typeof(char) || t == typeof(Guid) =>
utf8JsonWriter.WriteStringValue(value),
var t when t == typeof(bool) =>
utf8JsonWriter.WriteBooleanValue(value),
var t when t == typeof(byte[]) =>
utf8JsonWriter.WriteBase64StringValue(value, serializationFormat.ToFormatSpecifier()),
var t when t == typeof(DateTimeOffset) || t == typeof(DateTime) || t == typeof(TimeSpan) =>
SerializeDateTimeRelatedTypes(valueType, serializationFormat, value, utf8JsonWriter, mrwOptionsParameter),
SerializeDateTimeRelatedTypes(frameworkType, serializationFormat, value, utf8JsonWriter, mrwOptionsParameter),
var t when t == typeof(IPAddress) =>
utf8JsonWriter.WriteStringValue(value.InvokeToString()),
var t when t == typeof(Uri) =>
utf8JsonWriter.WriteStringValue(new MemberExpression(value, nameof(Uri.AbsoluteUri))),
var t when t == typeof(BinaryData) =>
SerializeBinaryData(valueType, serializationFormat, value, utf8JsonWriter),
SerializeBinaryData(frameworkType, serializationFormat, value, utf8JsonWriter),
var t when t == typeof(Stream) =>
utf8JsonWriter.WriteBinaryData(BinaryDataSnippets.FromStream(value, false)),
_ => null
Expand All @@ -1894,24 +1899,49 @@ var t when ValueTypeIsNumber(t) =>
DiagnosticCodes.UnsupportedSerialization,
$"Serialization of type {valueType.Name} is not supported.",
severity: EmitterDiagnosticSeverity.Warning);

return utf8JsonWriter.WriteObjectValue(value.As(valueType), mrwOptionsParameter);
}

return statement;
}

internal static ValueExpression DeserializeJsonValueCore(
Type valueType,
CSharpType valueType,
ScopedApi<JsonElement> element,
ScopedApi<BinaryData> data,
ScopedApi<ModelReaderWriterOptions> mrwOptions,
SerializationFormat format)
{
ValueExpression? exp = valueType switch
// Handle enums
if (valueType.IsEnum)
{
var underlyingValue = DeserializeJsonValueCore(
new CSharpType(valueType.UnderlyingEnumType!),
element,
data,
mrwOptions,
format);
return valueType.ToEnum(underlyingValue);
}

// Handle nullable types
if (valueType.IsFrameworkType && valueType.FrameworkType == typeof(Nullable<>))
{
return DeserializeJsonValueCore(valueType.Arguments[0], element, data, mrwOptions, format);
}

// Handle non-framework types
if (!valueType.IsFrameworkType)
{
return GetDeserializationMethodInvocationForType(valueType, element, data, mrwOptions);
}

// Handle framework types
var frameworkType = valueType.FrameworkType;
ValueExpression? exp = frameworkType switch
{
Type t when t == typeof(Uri) =>
New.Instance(valueType, element.GetString()),
New.Instance(frameworkType, element.GetString()),
Type t when t == typeof(IPAddress) =>
Static<IPAddress>().Invoke(nameof(IPAddress.Parse), element.GetString()),
Type t when t == typeof(BinaryData) =>
Expand Down Expand Up @@ -1965,7 +1995,7 @@ Type t when ValueTypeIsInt(t) =>
DiagnosticCodes.UnsupportedSerialization,
$"Deserialization of type {valueType.Name} is not supported.",
severity: EmitterDiagnosticSeverity.Warning);
return GetDeserializationMethodInvocationForType(new CSharpType(valueType), element, data, mrwOptions);
return GetDeserializationMethodInvocationForType(valueType, element, data, mrwOptions);
}

return exp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,15 @@ private ExtensibleEnumSerializationProvider[] CreateExtensibleEnumSerializations
}

public virtual ValueExpression DeserializeJsonValue(
Type valueType,
CSharpType valueType,
ScopedApi<JsonElement> element,
ScopedApi<BinaryData> data,
ScopedApi<ModelReaderWriterOptions> mrwOptionsParameter,
SerializationFormat format)
=> MrwSerializationTypeDefinition.DeserializeJsonValueCore(valueType, element, data, mrwOptionsParameter, format);

public virtual MethodBodyStatement SerializeJsonValue(
Type valueType,
CSharpType valueType,
ValueExpression value,
ScopedApi<Utf8JsonWriter> utf8JsonWriter,
ScopedApi<ModelReaderWriterOptions> mrwOptionsParameter,
Expand Down
Loading