Skip to content

Commit

Permalink
Update assignment of Json ReadOnlyMemory Property (#4829)
Browse files Browse the repository at this point in the history
Fixes: #4778
  • Loading branch information
nisha-bhatia authored Oct 23, 2024
1 parent 49300ce commit e600be5
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1158,26 +1158,26 @@ private MethodBodyStatement DeserializeValue(
{
if (valueType.IsList || valueType.IsArray)
{
if (valueType.IsArray && valueType.ElementType.IsReadOnlyMemory)
if (valueType.IsReadOnlyMemory)
{
var array = new VariableExpression(valueType.ElementType.PropertyInitializationType, "array");
var arrayVar = new VariableExpression(new CSharpType(valueType.ElementType.FrameworkType.MakeArrayType()), "array");
var index = new VariableExpression(typeof(int), "index");
var deserializeReadOnlyMemory = new MethodBodyStatement[]
{
Declare(index, Int(0)),
Declare(array, New.Array(valueType.ElementType, jsonElement.GetArrayLength())),
Declare(arrayVar, New.Array(valueType.ElementType, jsonElement.GetArrayLength())),
ForeachStatement.Create("item", jsonElement.EnumerateArray(), out ScopedApi<JsonElement> item).Add(new MethodBodyStatement[]
{
NullCheckCollectionItemIfRequired(valueType.ElementType, item, item.Assign(Null).Terminate(),
new MethodBodyStatement[]
{
DeserializeValue(valueType.ElementType, item, serializationFormat, out ValueExpression deserializedArrayElement),
item.Assign(deserializedArrayElement).Terminate(),
new IndexableExpression(arrayVar)[index].Assign(deserializedArrayElement).Terminate(),
}),
index.Increment().Terminate()
})
};
value = New.Instance(valueType.ElementType, array);
value = New.Instance(new CSharpType(typeof(ReadOnlyMemory<>), valueType.ElementType), arrayVar);
return deserializeReadOnlyMemory;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,5 +271,25 @@ public async Task CanCustomizeModelName()
Assert.AreEqual("CustomModel", modelProvider.CustomCodeView?.Name);
Assert.AreEqual("CustomModel", serializationProvider.CustomCodeView?.Name);
}

[Test]
public async Task CanCustomizePropertyIntoReadOnlyMemory()
{
await MockHelpers.LoadMockPluginAsync(compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());

var modelProp = InputFactory.Property("prop1", InputFactory.Array(InputPrimitiveType.Int32));
var inputModel = InputFactory.Model("mockInputModel", properties: [modelProp], usage: InputModelTypeUsage.Json);

var plugin = await MockHelpers.LoadMockPluginAsync(
inputModels: () => [inputModel],
compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());

var modelProvider = plugin.Object.OutputLibrary.TypeProviders.Single(t => t is ModelProvider);
var serializationProvider = modelProvider.SerializationProviders.Single(t => t is MrwSerializationTypeDefinition);
Assert.IsNotNull(serializationProvider);
var writer = new TypeProviderWriter(serializationProvider);
var file = writer.Write();
Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// <auto-generated/>

#nullable disable

using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Text.Json;
using Sample;

namespace Sample.Models
{
/// <summary></summary>
public partial class MockInputModel : global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.MockInputModel>
{
void global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.MockInputModel>.Write(global::System.Text.Json.Utf8JsonWriter writer, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
writer.WriteStartObject();
this.JsonModelWriteCore(writer, options);
writer.WriteEndObject();
}

/// <param name="writer"> The JSON writer. </param>
/// <param name="options"> The client options for reading and writing models. </param>
protected virtual void JsonModelWriteCore(global::System.Text.Json.Utf8JsonWriter writer, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>)this).GetFormatFromOptions(options) : options.Format;
if ((format != "J"))
{
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.MockInputModel)} does not support writing '{format}' format.");
}
writer.WritePropertyName("prop1"u8);
writer.WriteStartArray();
foreach (byte item in Prop1.Span)
{
writer.WriteNumberValue(item);
}
writer.WriteEndArray();
if (((options.Format != "W") && (_additionalBinaryDataProperties != null)))
{
foreach (var item in _additionalBinaryDataProperties)
{
writer.WritePropertyName(item.Key);
#if NET6_0_OR_GREATER
writer.WriteRawValue(item.Value);
#else
using (global::System.Text.Json.JsonDocument document = global::System.Text.Json.JsonDocument.Parse(item.Value))
{
global::System.Text.Json.JsonSerializer.Serialize(writer, document.RootElement);
}
#endif
}
}
}

global::Sample.Models.MockInputModel global::System.ClientModel.Primitives.IJsonModel<global::Sample.Models.MockInputModel>.Create(ref global::System.Text.Json.Utf8JsonReader reader, global::System.ClientModel.Primitives.ModelReaderWriterOptions options) => ((global::Sample.Models.MockInputModel)this.JsonModelCreateCore(ref reader, options));

/// <param name="reader"> The JSON reader. </param>
/// <param name="options"> The client options for reading and writing models. </param>
protected virtual global::Sample.Models.MockInputModel JsonModelCreateCore(ref global::System.Text.Json.Utf8JsonReader reader, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>)this).GetFormatFromOptions(options) : options.Format;
if ((format != "J"))
{
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.MockInputModel)} does not support reading '{format}' format.");
}
using global::System.Text.Json.JsonDocument document = global::System.Text.Json.JsonDocument.ParseValue(ref reader);
return global::Sample.Models.MockInputModel.DeserializeMockInputModel(document.RootElement, options);
}

internal static global::Sample.Models.MockInputModel DeserializeMockInputModel(global::System.Text.Json.JsonElement element, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
if ((element.ValueKind == global::System.Text.Json.JsonValueKind.Null))
{
return null;
}
global::System.ReadOnlyMemory<byte> prop1 = default;
global::System.Collections.Generic.IDictionary<string, global::System.BinaryData> additionalBinaryDataProperties = new global::Sample.ChangeTrackingDictionary<string, global::System.BinaryData>();
foreach (var prop in element.EnumerateObject())
{
if (prop.NameEquals("prop1"u8))
{
if ((prop.Value.ValueKind == global::System.Text.Json.JsonValueKind.Null))
{
continue;
}
int index = 0;
global::System.Byte[] array = new byte[prop.Value.GetArrayLength()];
foreach (var item in prop.Value.EnumerateArray())
{
array[index] = item.GetByte();
index++;
}
prop1 = new global::System.ReadOnlyMemory<byte>(array);
continue;
}
if ((options.Format != "W"))
{
additionalBinaryDataProperties.Add(prop.Name, global::System.BinaryData.FromString(prop.Value.GetRawText()));
}
}
return new global::Sample.Models.MockInputModel(prop1, additionalBinaryDataProperties);
}

global::System.BinaryData global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>.Write(global::System.ClientModel.Primitives.ModelReaderWriterOptions options) => this.PersistableModelWriteCore(options);

/// <param name="options"> The client options for reading and writing models. </param>
protected virtual global::System.BinaryData PersistableModelWriteCore(global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>)this).GetFormatFromOptions(options) : options.Format;
switch (format)
{
case "J":
return global::System.ClientModel.Primitives.ModelReaderWriter.Write(this, options);
default:
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.MockInputModel)} does not support writing '{options.Format}' format.");
}
}

global::Sample.Models.MockInputModel global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>.Create(global::System.BinaryData data, global::System.ClientModel.Primitives.ModelReaderWriterOptions options) => ((global::Sample.Models.MockInputModel)this.PersistableModelCreateCore(data, options));

/// <param name="data"> The data to parse. </param>
/// <param name="options"> The client options for reading and writing models. </param>
protected virtual global::Sample.Models.MockInputModel PersistableModelCreateCore(global::System.BinaryData data, global::System.ClientModel.Primitives.ModelReaderWriterOptions options)
{
string format = (options.Format == "W") ? ((global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>)this).GetFormatFromOptions(options) : options.Format;
switch (format)
{
case "J":
using (global::System.Text.Json.JsonDocument document = global::System.Text.Json.JsonDocument.Parse(data))
{
return global::Sample.Models.MockInputModel.DeserializeMockInputModel(document.RootElement, options);
}
default:
throw new global::System.FormatException($"The model {nameof(global::Sample.Models.MockInputModel)} does not support reading '{options.Format}' format.");
}
}

string global::System.ClientModel.Primitives.IPersistableModel<global::Sample.Models.MockInputModel>.GetFormatFromOptions(global::System.ClientModel.Primitives.ModelReaderWriterOptions options) => "J";

/// <param name="mockInputModel"> The <see cref="global::Sample.Models.MockInputModel"/> to serialize into <see cref="global::System.ClientModel.BinaryContent"/>. </param>
public static implicit operator BinaryContent(global::Sample.Models.MockInputModel mockInputModel)
{
return global::System.ClientModel.BinaryContent.Create(mockInputModel, global::Sample.ModelSerializationExtensions.WireOptions);
}

/// <param name="result"> The <see cref="global::System.ClientModel.ClientResult"/> to deserialize the <see cref="global::Sample.Models.MockInputModel"/> from. </param>
public static explicit operator MockInputModel(global::System.ClientModel.ClientResult result)
{
using global::System.ClientModel.Primitives.PipelineResponse response = result.GetRawResponse();
using global::System.Text.Json.JsonDocument document = global::System.Text.Json.JsonDocument.Parse(response.Content);
return global::Sample.Models.MockInputModel.DeserializeMockInputModel(document.RootElement, global::Sample.ModelSerializationExtensions.WireOptions);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#nullable disable

using Microsoft.Generator.CSharp.Customization;
using System;
using System.Collections.Generic;

namespace Sample.Models
{
public partial class MockInputModel
{
public ReadOnlyMemory<byte> Prop1 { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,14 @@ protected virtual void JsonModelWriteCore(global::System.Text.Json.Utf8JsonWrite
{
continue;
}
global::System.Collections.Generic.List<byte> array = new global::System.Collections.Generic.List<byte>();
int index = 0;
global::System.Byte[] array = new byte[prop.Value.GetArrayLength()];
foreach (var item in prop.Value.EnumerateArray())
{
array.Add(item.GetByte());
array[index] = item.GetByte();
index++;
}
newProp1 = array;
newProp1 = new global::System.ReadOnlyMemory<byte>(array);
continue;
}
if (prop.NameEquals("prop2"u8))
Expand All @@ -110,12 +112,14 @@ protected virtual void JsonModelWriteCore(global::System.Text.Json.Utf8JsonWrite
{
continue;
}
global::System.Collections.Generic.List<byte> array = new global::System.Collections.Generic.List<byte>();
int index = 0;
global::System.Byte[] array = new byte[prop.Value.GetArrayLength()];
foreach (var item in prop.Value.EnumerateArray())
{
array.Add(item.GetByte());
array[index] = item.GetByte();
index++;
}
newProp2 = array;
newProp2 = new global::System.ReadOnlyMemory<byte>(array);
continue;
}
if ((options.Format != "W"))
Expand Down

0 comments on commit e600be5

Please sign in to comment.