private Option<IArrayTypeSymbol?> _ByteArrayType;
+ public INamedTypeSymbol? MemoryByteType => _MemoryByteType.HasValue
+ ? _MemoryByteType.Value
+ : (_MemoryByteType = new(MemoryType?.Construct(Compilation.GetSpecialType(SpecialType.System_Byte)))).Value;
+
+ private Option<INamedTypeSymbol?> _MemoryByteType;
+
+ public INamedTypeSymbol? ReadOnlyMemoryByteType => _ReadOnlyMemoryByteType.HasValue
+ ? _ReadOnlyMemoryByteType.Value
+ : (_ReadOnlyMemoryByteType = new(ReadOnlyMemoryType?.Construct(Compilation.GetSpecialType(SpecialType.System_Byte)))).Value;
+
+ private Option<INamedTypeSymbol?> _ReadOnlyMemoryByteType;
+
public INamedTypeSymbol? GuidType => GetOrResolveType(typeof(Guid), ref _GuidType);
private Option<INamedTypeSymbol?> _GuidType;
switch (collectionType)
{
case CollectionType.Array:
+ case CollectionType.MemoryOfT:
+ case CollectionType.ReadOnlyMemoryOfT:
createCollectionMethodExpr = $"{createCollectionInfoMethodName}<{valueTypeFQN}>({OptionsLocalVariableName}, {InfoVarName})";
break;
case CollectionType.IEnumerable:
writer.WriteLine();
string getCurrentElementExpr;
+ const string elementVarName = "element";
switch (typeGenerationSpec.CollectionType)
{
case CollectionType.Array:
getCurrentElementExpr = $"{ValueVarName}[i]";
break;
+ case CollectionType.MemoryOfT:
+ case CollectionType.ReadOnlyMemoryOfT:
+ writer.WriteLine($"foreach ({valueTypeGenerationSpec.TypeRef.FullyQualifiedName} {elementVarName} in {ValueVarName}.Span)");
+ getCurrentElementExpr = elementVarName;
+ break;
+
case CollectionType.IListOfT:
case CollectionType.List:
case CollectionType.IList:
break;
default:
- const string elementVarName = "element";
writer.WriteLine($"foreach ({valueTypeGenerationSpec.TypeRef.FullyQualifiedName} {elementVarName} in {ValueVarName})");
getCurrentElementExpr = elementVarName;
break;
CollectionType.ConcurrentQueue => "CreateConcurrentQueueInfo",
CollectionType.ImmutableEnumerable => "CreateImmutableEnumerableInfo",
CollectionType.IAsyncEnumerableOfT => "CreateIAsyncEnumerableInfo",
+ CollectionType.MemoryOfT => "CreateMemoryInfo",
+ CollectionType.ReadOnlyMemoryOfT => "CreateReadOnlyMemoryInfo",
CollectionType.ISet => "CreateISetInfo",
CollectionType.Dictionary => "CreateDictionaryInfo",
immutableCollectionFactoryTypeFullName = null;
needsRuntimeType = false;
+ if (SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, _knownSymbols.MemoryType))
+ {
+ Debug.Assert(!SymbolEqualityComparer.Default.Equals(type, _knownSymbols.MemoryByteType));
+ valueType = ((INamedTypeSymbol)type).TypeArguments[0];
+ collectionType = CollectionType.MemoryOfT;
+ return true;
+ }
+
+ if (SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, _knownSymbols.ReadOnlyMemoryType))
+ {
+ Debug.Assert(!SymbolEqualityComparer.Default.Equals(type, _knownSymbols.ReadOnlyMemoryByteType));
+ valueType = ((INamedTypeSymbol)type).TypeArguments[0];
+ collectionType = CollectionType.ReadOnlyMemoryOfT;
+ return true;
+ }
+
// IAsyncEnumerable<T> takes precedence over IEnumerable.
if (type.GetCompatibleGenericBaseType(_knownSymbols.IAsyncEnumerableOfTType) is INamedTypeSymbol iAsyncEnumerableType)
{
SymbolEqualityComparer.Default.Equals(_knownSymbols.UIntPtrType, type) ||
_knownSymbols.MemberInfoType.IsAssignableFrom(type) ||
_knownSymbols.DelegateType.IsAssignableFrom(type) ||
- SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, _knownSymbols.MemoryType) ||
- SymbolEqualityComparer.Default.Equals(type.OriginalDefinition, _knownSymbols.ReadOnlyMemoryType) ||
type is IArrayTypeSymbol { Rank: > 1 };
}
#pragma warning restore
AddTypeIfNotNull(knownSymbols.ByteArrayType);
+ AddTypeIfNotNull(knownSymbols.MemoryByteType);
+ AddTypeIfNotNull(knownSymbols.ReadOnlyMemoryByteType);
AddTypeIfNotNull(knownSymbols.TimeSpanType);
AddTypeIfNotNull(knownSymbols.DateTimeOffsetType);
AddTypeIfNotNull(knownSymbols.DateOnlyType);
IEnumerableOfT,
Stack,
Queue,
- ImmutableEnumerable
+ ImmutableEnumerable,
+ MemoryOfT,
+ ReadOnlyMemoryOfT
}
}
public static System.Text.Json.Serialization.JsonConverter<System.Text.Json.Nodes.JsonNode?> JsonNodeConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<System.Text.Json.Nodes.JsonObject?> JsonObjectConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<System.Text.Json.Nodes.JsonValue?> JsonValueConverter { get { throw null; } }
+ public static System.Text.Json.Serialization.JsonConverter<System.Memory<byte>> MemoryByteConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<object?> ObjectConverter { get { throw null; } }
+ public static System.Text.Json.Serialization.JsonConverter<System.ReadOnlyMemory<byte>> ReadOnlyMemoryByteConverter { get { throw null; } }
[System.CLSCompliantAttribute(false)]
public static System.Text.Json.Serialization.JsonConverter<sbyte> SByteConverter { get { throw null; } }
public static System.Text.Json.Serialization.JsonConverter<float> SingleConverter { get { throw null; } }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateIReadOnlyDictionaryInfo<TCollection, TKey, TValue>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.IReadOnlyDictionary<TKey, TValue> where TKey : notnull { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateISetInfo<TCollection, TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.ISet<TElement> { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateListInfo<TCollection, TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.List<TElement> { throw null; }
+ public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<Memory<TElement>> CreateMemoryInfo<TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<Memory<TElement>> collectionInfo) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> CreateObjectInfo<T>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<T> objectInfo) where T : notnull { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonPropertyInfo CreatePropertyInfo<T>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<T> propertyInfo) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateQueueInfo<TCollection>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo, System.Action<TCollection, object?> addFunc) where TCollection : System.Collections.IEnumerable { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateQueueInfo<TCollection, TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.Queue<TElement> { throw null; }
+ public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<ReadOnlyMemory<TElement>> CreateReadOnlyMemoryInfo<TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<ReadOnlyMemory<TElement>> collectionInfo) { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateStackInfo<TCollection>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo, System.Action<TCollection, object?> addFunc) where TCollection : System.Collections.IEnumerable { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<TCollection> CreateStackInfo<TCollection, TElement>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<TCollection> collectionInfo) where TCollection : System.Collections.Generic.Stack<TElement> { throw null; }
public static System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> CreateValueInfo<T>(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.JsonConverter converter) { throw null; }
<Compile Include="System\Text\Json\Serialization\Converters\CastingConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Collection\ImmutableDictionaryOfTKeyTValueConverterWithReflection.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Collection\ImmutableEnumerableOfTConverterWithReflection.cs" />
+ <Compile Include="System\Text\Json\Serialization\Converters\Collection\ReadOnlyMemoryConverter.cs" />
+ <Compile Include="System\Text\Json\Serialization\Converters\Collection\MemoryConverterFactory.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Collection\StackOrQueueConverterWithReflection.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\JsonMetadataServicesConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Object\ObjectWithParameterizedConstructorConverter.Large.Reflection.cs" />
+ <Compile Include="System\Text\Json\Serialization\Converters\Collection\MemoryConverter.cs" />
+ <Compile Include="System\Text\Json\Serialization\Converters\Value\ReadOnlyMemoryByteConverter.cs" />
+ <Compile Include="System\Text\Json\Serialization\Converters\Value\MemoryByteConverter.cs" />
<Compile Include="System\Text\Json\Serialization\Converters\Value\JsonPrimitiveConverter.cs" />
<Compile Include="System\Text\Json\Serialization\IgnoreReferenceResolver.cs" />
<Compile Include="System\Text\Json\Serialization\IJsonOnDeserialized.cs" />
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+
+namespace System.Text.Json.Serialization.Converters
+{
+ internal sealed class MemoryConverter<T> : JsonCollectionConverter<Memory<T>, T>
+ {
+ internal override bool CanHaveMetadata => false;
+
+ protected override void Add(in T value, ref ReadStack state)
+ {
+ ((List<T>)state.Current.ReturnValue!).Add(value);
+ }
+
+ protected override void CreateCollection(ref Utf8JsonReader reader, scoped ref ReadStack state, JsonSerializerOptions options)
+ {
+ state.Current.ReturnValue = new List<T>();
+ }
+
+ protected override void ConvertCollection(ref ReadStack state, JsonSerializerOptions options)
+ {
+ Memory<T> memory = ((List<T>)state.Current.ReturnValue!).ToArray().AsMemory();
+ state.Current.ReturnValue = memory;
+ }
+
+ protected override bool OnWriteResume(Utf8JsonWriter writer, Memory<T> value, JsonSerializerOptions options, ref WriteStack state)
+ {
+ int index = state.Current.EnumeratorIndex;
+
+ JsonConverter<T> elementConverter = GetElementConverter(ref state);
+ ReadOnlySpan<T> valueSpan = value.Span;
+
+ if (elementConverter.CanUseDirectReadOrWrite && state.Current.NumberHandling == null)
+ {
+ // Fast path that avoids validation and extra indirection.
+ for (; index < valueSpan.Length; index++)
+ {
+ elementConverter.Write(writer, valueSpan[index], options);
+ }
+ }
+ else
+ {
+ for (; index < value.Length; index++)
+ {
+ T element = valueSpan[index];
+ if (!elementConverter.TryWrite(writer, element, options, ref state))
+ {
+ state.Current.EnumeratorIndex = index;
+ return false;
+ }
+
+ state.Current.EndCollectionElement();
+
+ if (ShouldFlush(writer, ref state))
+ {
+ state.Current.EnumeratorIndex = ++index;
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+}
--- /dev/null
+ï»ż// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+namespace System.Text.Json.Serialization.Converters
+{
+ [RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
+ internal sealed class MemoryConverterFactory : JsonConverterFactory
+ {
+ public override bool CanConvert(Type typeToConvert)
+ {
+ if (!typeToConvert.IsGenericType || !typeToConvert.IsValueType)
+ {
+ return false;
+ }
+
+ Type typeDef = typeToConvert.GetGenericTypeDefinition();
+ return typeDef == typeof(Memory<>) || typeDef == typeof(ReadOnlyMemory<>);
+ }
+
+ public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+ {
+ Debug.Assert(CanConvert(typeToConvert));
+
+ Type converterType = typeToConvert.GetGenericTypeDefinition() == typeof(Memory<>) ?
+ typeof(MemoryConverter<>) : typeof(ReadOnlyMemoryConverter<>);
+
+ Type elementType = typeToConvert.GetGenericArguments()[0];
+
+ return (JsonConverter)Activator.CreateInstance(
+ converterType.MakeGenericType(elementType))!;
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+
+namespace System.Text.Json.Serialization.Converters
+{
+ internal sealed class ReadOnlyMemoryConverter<T> : JsonCollectionConverter<ReadOnlyMemory<T>, T>
+ {
+ internal override bool CanHaveMetadata => false;
+
+ protected override void Add(in T value, ref ReadStack state)
+ {
+ ((List<T>)state.Current.ReturnValue!).Add(value);
+ }
+
+ protected override void CreateCollection(ref Utf8JsonReader reader, scoped ref ReadStack state, JsonSerializerOptions options)
+ {
+ state.Current.ReturnValue = new List<T>();
+ }
+
+ protected override void ConvertCollection(ref ReadStack state, JsonSerializerOptions options)
+ {
+ ReadOnlyMemory<T> memory = ((List<T>)state.Current.ReturnValue!).ToArray().AsMemory();
+ state.Current.ReturnValue = memory;
+ }
+
+ protected override bool OnWriteResume(Utf8JsonWriter writer, ReadOnlyMemory<T> value, JsonSerializerOptions options, ref WriteStack state)
+ {
+ int index = state.Current.EnumeratorIndex;
+
+ JsonConverter<T> elementConverter = GetElementConverter(ref state);
+ ReadOnlySpan<T> valueSpan = value.Span;
+
+ if (elementConverter.CanUseDirectReadOrWrite && state.Current.NumberHandling == null)
+ {
+ // Fast path that avoids validation and extra indirection.
+ for (; index < valueSpan.Length; index++)
+ {
+ elementConverter.Write(writer, valueSpan[index], options);
+ }
+ }
+ else
+ {
+ for (; index < value.Length; index++)
+ {
+ T element = valueSpan[index];
+ if (!elementConverter.TryWrite(writer, element, options, ref state))
+ {
+ state.Current.EnumeratorIndex = index;
+ return false;
+ }
+
+ state.Current.EndCollectionElement();
+
+ if (ShouldFlush(writer, ref state))
+ {
+ state.Current.EnumeratorIndex = ++index;
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Text.Json.Serialization.Converters
+{
+ internal sealed class MemoryByteConverter : JsonConverter<Memory<byte>>
+ {
+ public override Memory<byte> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return reader.GetBytesFromBase64();
+ }
+
+ public override void Write(Utf8JsonWriter writer, Memory<byte> value, JsonSerializerOptions options)
+ {
+ writer.WriteBase64StringValue(value.Span);
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Text.Json.Serialization.Converters
+{
+ internal sealed class ReadOnlyMemoryByteConverter : JsonConverter<ReadOnlyMemory<byte>>
+ {
+ public override ReadOnlyMemory<byte> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return reader.GetBytesFromBase64();
+ }
+
+ public override void Write(Utf8JsonWriter writer, ReadOnlyMemory<byte> value, JsonSerializerOptions options)
+ {
+ writer.WriteBase64StringValue(value.Span);
+ }
+ }
+}
type == typeof(SerializationInfo) ||
type == typeof(IntPtr) ||
type == typeof(UIntPtr) ||
- // Exclude Memory<T> and ReadOnlyMemory<T> types.
- IsMemoryType(type) ||
// Exclude delegates.
typeof(Delegate).IsAssignableFrom(type);
-
- static bool IsMemoryType(Type type)
- {
- if (!type.IsGenericType || !type.IsValueType)
- {
- return false;
- }
-
- Type typeDef = type.GetGenericTypeDefinition();
- return typeDef == typeof(Memory<>) || typeDef == typeof(ReadOnlyMemory<>);
- }
}
public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options)
new EnumConverterFactory(),
new JsonNodeConverterFactory(),
new FSharpTypeConverterFactory(),
+ new MemoryConverterFactory(),
// IAsyncEnumerable takes precedence over IEnumerable.
new IAsyncEnumerableConverterFactory(),
// IEnumerable should always be second to last since they can convert any IEnumerable.
private static Dictionary<Type, JsonConverter> GetDefaultSimpleConverters()
{
- const int NumberOfSimpleConverters = 26;
+ const int NumberOfSimpleConverters = 28;
var converters = new Dictionary<Type, JsonConverter>(NumberOfSimpleConverters);
// Use a dictionary for simple converters.
Add(JsonMetadataServices.Int64Converter);
Add(JsonMetadataServices.JsonElementConverter);
Add(JsonMetadataServices.JsonDocumentConverter);
+ Add(JsonMetadataServices.MemoryByteConverter);
+ Add(JsonMetadataServices.ReadOnlyMemoryByteConverter);
Add(JsonMetadataServices.ObjectConverter);
Add(JsonMetadataServices.SByteConverter);
Add(JsonMetadataServices.SingleConverter);
options,
collectionInfo,
new IEnumerableConverter<TCollection>());
+
+ /// <summary>
+ /// Creates serialization metadata for <see cref="Memory{T}"/>.
+ /// </summary>
+ /// <typeparam name="TElement">The generic definition of the element type.</typeparam>
+ /// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
+ /// <param name="collectionInfo">Provides serialization metadata about the collection type.</param>
+ /// <returns>Serialization metadata for the given type.</returns>
+ /// <remarks>This API is for use by the output of the System.Text.Json source generator and should not be called directly.</remarks>
+ public static JsonTypeInfo<Memory<TElement>> CreateMemoryInfo<TElement>(JsonSerializerOptions options, JsonCollectionInfoValues<Memory<TElement>> collectionInfo)
+ => CreateCore(
+ options,
+ collectionInfo,
+ new MemoryConverter<TElement>());
+
+ /// <summary>
+ /// Creates serialization metadata for <see cref="ReadOnlyMemory{T}"/>.
+ /// </summary>
+ /// <typeparam name="TElement">The generic definition of the element type.</typeparam>
+ /// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
+ /// <param name="collectionInfo">Provides serialization metadata about the collection type.</param>
+ /// <returns>Serialization metadata for the given type.</returns>
+ /// <remarks>This API is for use by the output of the System.Text.Json source generator and should not be called directly.</remarks>
+ public static JsonTypeInfo<ReadOnlyMemory<TElement>> CreateReadOnlyMemoryInfo<TElement>(JsonSerializerOptions options, JsonCollectionInfoValues<ReadOnlyMemory<TElement>> collectionInfo)
+ => CreateCore(
+ options,
+ collectionInfo,
+ new ReadOnlyMemoryConverter<TElement>());
}
}
private static JsonConverter<JsonDocument?>? s_jsonDocumentConverter;
/// <summary>
+ /// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="Memory{Byte}"/> values.
+ /// </summary>
+ /// <remarks>This API is for use by the output of the System.Text.Json source generator and should not be called directly.</remarks>
+ public static JsonConverter<Memory<byte>> MemoryByteConverter => s_memoryByteConverter ??= new MemoryByteConverter();
+ private static JsonConverter<Memory<byte>>? s_memoryByteConverter;
+
+ /// <summary>
+ /// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="ReadOnlyMemory{Byte}"/> values.
+ /// </summary>
+ /// <remarks>This API is for use by the output of the System.Text.Json source generator and should not be called directly.</remarks>
+ public static JsonConverter<ReadOnlyMemory<byte>> ReadOnlyMemoryByteConverter => s_readOnlyMemoryByteConverter ??= new ReadOnlyMemoryByteConverter();
+ private static JsonConverter<ReadOnlyMemory<byte>>? s_readOnlyMemoryByteConverter;
+
+ /// <summary>
/// Returns a <see cref="JsonConverter{T}"/> instance that converts <see cref="object"/> values.
/// </summary>
/// <remarks>This API is for use by the output of the System.Text.Json source generator and should not be called directly.</remarks>
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Text.Json.Tests;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+ public abstract partial class CollectionTests
+ {
+ private static readonly byte[] s_testData = "This is some test data!!!"u8.ToArray();
+
+ [Fact]
+ public async Task SerializeMemoryOfTAsync()
+ {
+ Memory<int> memoryInt = new int[] { 1, 2, 3 }.AsMemory();
+ Assert.Equal("[1,2,3]", await Serializer.SerializeWrapper(memoryInt));
+
+ Memory<EmptyClass> memoryPoco = new EmptyClass[] { new(), new(), new() }.AsMemory();
+ Assert.Equal("[{},{},{}]", await Serializer.SerializeWrapper(memoryPoco));
+ }
+
+ [Fact]
+ public async Task SerializeReadOnlyMemoryOfTAsync()
+ {
+ ReadOnlyMemory<int> memoryInt = new int[] { 1, 2, 3 }.AsMemory();
+ Assert.Equal("[1,2,3]", await Serializer.SerializeWrapper(memoryInt));
+
+ ReadOnlyMemory<EmptyClass> memoryPoco = new EmptyClass[] { new(), new(), new() }.AsMemory();
+ Assert.Equal("[{},{},{}]", await Serializer.SerializeWrapper(memoryPoco));
+ }
+
+ [Fact]
+ public async Task DeserializeMemoryOfTAsync()
+ {
+ Memory<int> memoryInt = await Serializer.DeserializeWrapper<Memory<int>>("[1,2,3]");
+ AssertExtensions.SequenceEqual(new int[] { 1, 2, 3 }, memoryInt.Span);
+
+ Memory<EmptyClass> memoryPoco = new EmptyClass[] { new(), new(), new() }.AsMemory();
+ Assert.Equal(3, memoryPoco.Length);
+ }
+
+ [Fact]
+ public async Task DeserializeReadOnlyMemoryOfTAsync()
+ {
+ ReadOnlyMemory<int> memoryInt = await Serializer.DeserializeWrapper<ReadOnlyMemory<int>>("[1,2,3]");
+ AssertExtensions.SequenceEqual(new int[] { 1, 2, 3 }, memoryInt.Span);
+
+ ReadOnlyMemory<EmptyClass> memoryPoco = await Serializer.DeserializeWrapper<ReadOnlyMemory<EmptyClass>>("[{},{},{}]");
+ Assert.Equal(3, memoryPoco.Length);
+ }
+
+ [Fact]
+ public async Task SerializeMemoryOfTClassAsync()
+ {
+ MemoryOfTClass<int> memoryOfIntClass = new MemoryOfTClass<int>();
+ memoryOfIntClass.Memory = new int[] { 1, 2, 3 };
+
+ string json = await Serializer.SerializeWrapper(memoryOfIntClass);
+ Assert.Equal(@"{""Memory"":[1,2,3]}", json);
+ }
+
+ [Fact]
+ public async Task SerializeReadOnlyMemoryOfTClassAsync()
+ {
+ ReadOnlyMemoryOfTClass<int> memoryOfIntClass = new ReadOnlyMemoryOfTClass<int>();
+ memoryOfIntClass.ReadOnlyMemory = new int[] { 1, 2, 3 };
+
+ string json = await Serializer.SerializeWrapper(memoryOfIntClass);
+ Assert.Equal(@"{""ReadOnlyMemory"":[1,2,3]}", json);
+ }
+
+ [Fact]
+ public async Task DeserializeMemoryOfTClassAsync()
+ {
+ string json = @"{""Memory"":[1,2,3]}";
+ MemoryOfTClass<int> memoryOfIntClass = await Serializer.DeserializeWrapper<MemoryOfTClass<int>>(json);
+ AssertExtensions.SequenceEqual(new int[] { 1, 2, 3 }, memoryOfIntClass.Memory.Span);
+ }
+
+ [Fact]
+ public async Task DeserializeReadOnlyMemoryOfTClassAsync()
+ {
+ string json = @"{""ReadOnlyMemory"":[1,2,3]}";
+ ReadOnlyMemoryOfTClass<int> memoryOfIntClass = await Serializer.DeserializeWrapper<ReadOnlyMemoryOfTClass<int>>(json);
+ AssertExtensions.SequenceEqual(new int[] { 1, 2, 3 }, memoryOfIntClass.ReadOnlyMemory.Span);
+ }
+
+ [Fact]
+ public async Task SerializeMemoryByteAsync()
+ {
+ Assert.Equal("\"VGhpcyBpcyBzb21lIHRlc3QgZGF0YSEhIQ==\"", await Serializer.SerializeWrapper<Memory<byte>>(s_testData.AsMemory()));
+ Assert.Equal("\"VGhpcyBpcyBzb21lIHRlc3QgZGF0YSEhIQ==\"", await Serializer.SerializeWrapper<ReadOnlyMemory<byte>>(s_testData.AsMemory()));
+ }
+
+ [Fact]
+ public async Task DeserializeMemoryByteAsync()
+ {
+ Memory<byte> memory = await Serializer.DeserializeWrapper<Memory<byte>>("\"VGhpcyBpcyBzb21lIHRlc3QgZGF0YSEhIQ==\"");
+ AssertExtensions.SequenceEqual(s_testData, memory.Span);
+
+ ReadOnlyMemory<byte> readOnlyMemory = await Serializer.DeserializeWrapper<ReadOnlyMemory<byte>>("\"VGhpcyBpcyBzb21lIHRlc3QgZGF0YSEhIQ==\"");
+ AssertExtensions.SequenceEqual(s_testData, readOnlyMemory.Span);
+ }
+
+ [Fact]
+ public async Task SerializeMemoryByteClassAsync()
+ {
+ MemoryOfTClass<byte> memoryOfByteClass = new MemoryOfTClass<byte>();
+ memoryOfByteClass.Memory = s_testData;
+
+ string json = await Serializer.SerializeWrapper(memoryOfByteClass);
+ Assert.Equal(@"{""Memory"":""VGhpcyBpcyBzb21lIHRlc3QgZGF0YSEhIQ==""}", json);
+ }
+
+ [Fact]
+ public async Task DeserializeMemoryByteClassAsync()
+ {
+ string json = @"{""Memory"":""VGhpcyBpcyBzb21lIHRlc3QgZGF0YSEhIQ==""}";
+
+ MemoryOfTClass<byte> memoryOfByteClass = await Serializer.DeserializeWrapper<MemoryOfTClass<byte>>(json);
+ AssertExtensions.SequenceEqual<byte>(s_testData, memoryOfByteClass.Memory.Span);
+ }
+ }
+}
public List<ClassWithRecursiveCollectionTypes> List { get; set; }
public IReadOnlyDictionary<string, ClassWithRecursiveCollectionTypes>? Dictionary { get; set; }
}
+
+ internal class MemoryOfTClass<T>
+ {
+ public Memory<T> Memory { get; set; }
+ }
+
+ internal class ReadOnlyMemoryOfTClass<T>
+ {
+ public ReadOnlyMemory<T> ReadOnlyMemory { get; set; }
+ }
}
yield return WrapArgs((IntPtr)123);
yield return WrapArgs<IntPtr?>(new IntPtr(123)); // One nullable variation.
yield return WrapArgs((UIntPtr)123);
- yield return WrapArgs((Memory<byte>)new byte[] { 1, 2, 3 });
- yield return WrapArgs((ReadOnlyMemory<byte>)new byte[] { 1, 2, 3 });
static object[] WrapArgs<T>(T value) => new object[] { new ValueWrapper<T>(value) };
}
[JsonSerializable(typeof(KeyValuePair<string, KeyValuePair<string, int>>))]
[JsonSerializable(typeof(StackWrapper))]
[JsonSerializable(typeof(ClassWithRecursiveCollectionTypes))]
+ [JsonSerializable(typeof(MemoryOfTClass<byte>))]
+ [JsonSerializable(typeof(ReadOnlyMemoryOfTClass<byte>))]
+ [JsonSerializable(typeof(MemoryOfTClass<int>))]
+ [JsonSerializable(typeof(ReadOnlyMemoryOfTClass<int>))]
+ [JsonSerializable(typeof(MemoryOfTClass<EmptyClass>))]
+ [JsonSerializable(typeof(ReadOnlyMemoryOfTClass<EmptyClass>))]
internal sealed partial class CollectionTestsContext_Metadata : JsonSerializerContext
{
}
[JsonSerializable(typeof(KeyValuePair<string, KeyValuePair<string, int>>))]
[JsonSerializable(typeof(StackWrapper))]
[JsonSerializable(typeof(ClassWithRecursiveCollectionTypes))]
+ [JsonSerializable(typeof(MemoryOfTClass<byte>))]
+ [JsonSerializable(typeof(ReadOnlyMemoryOfTClass<byte>))]
+ [JsonSerializable(typeof(MemoryOfTClass<int>))]
+ [JsonSerializable(typeof(ReadOnlyMemoryOfTClass<int>))]
+ [JsonSerializable(typeof(MemoryOfTClass<EmptyClass>))]
+ [JsonSerializable(typeof(ReadOnlyMemoryOfTClass<EmptyClass>))]
internal sealed partial class CollectionTestsContext_Default : JsonSerializerContext
{
}
[JsonSerializable(typeof(ClassWithType<IntPtr?>))]
[JsonSerializable(typeof(UIntPtr))]
[JsonSerializable(typeof(ClassWithType<UIntPtr>))]
- [JsonSerializable(typeof(Memory<byte>))]
- [JsonSerializable(typeof(ClassWithType<Memory<byte>>))]
- [JsonSerializable(typeof(ReadOnlyMemory<byte>))]
- [JsonSerializable(typeof(ClassWithType<ReadOnlyMemory<byte>>))]
[JsonSerializable(typeof(IAsyncEnumerable<int>))]
[JsonSerializable(typeof(ClassWithType<IAsyncEnumerable<int>>))]
[JsonSerializable(typeof(ClassThatImplementsIAsyncEnumerable))]
[JsonSerializable(typeof(ClassWithType<IntPtr?>))]
[JsonSerializable(typeof(UIntPtr))]
[JsonSerializable(typeof(ClassWithType<UIntPtr>))]
- [JsonSerializable(typeof(Memory<byte>))]
- [JsonSerializable(typeof(ClassWithType<Memory<byte>>))]
- [JsonSerializable(typeof(ReadOnlyMemory<byte>))]
- [JsonSerializable(typeof(ClassWithType<ReadOnlyMemory<byte>>))]
[JsonSerializable(typeof(IAsyncEnumerable<int>))]
[JsonSerializable(typeof(ClassWithType<IAsyncEnumerable<int>>))]
[JsonSerializable(typeof(ClassThatImplementsIAsyncEnumerable))]
<Compile Include="..\Common\CollectionTests\CollectionTests.Generic.Write.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.Generic.Write.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.Immutable.Read.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.Immutable.Read.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.KeyValuePair.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.KeyValuePair.cs" />
+ <Compile Include="..\Common\CollectionTests\CollectionTests.Memory.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.Memory.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.NonGeneric.Read.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.NonGeneric.Read.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.NonGeneric.Write.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.NonGeneric.Write.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.ObjectModel.Read.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.ObjectModel.Read.cs" />
}
[Theory]
+ [InlineData(LanguageVersion.Default)]
+ [InlineData(LanguageVersion.Preview)]
+ [InlineData(LanguageVersion.Latest)]
+ [InlineData(LanguageVersion.LatestMajor)]
+ [InlineData(LanguageVersion.CSharp9)]
+#if ROSLYN4_4_OR_GREATER
+ [InlineData(LanguageVersion.CSharp10)]
+ [InlineData(LanguageVersion.CSharp11)]
+#endif
+ public void SupportedLanguageVersions_Memory_SucceedCompilation(LanguageVersion langVersion)
+ {
+ string source = """
+ using System;
+ using System.Text.Json.Serialization;
+
+ namespace HelloWorld
+ {
+ public class MyClass<T>
+ {
+ public MyClass(
+ Memory<T> memoryOfT,
+ Memory<byte> memoryByte,
+ ReadOnlyMemory<T> readOnlyMemoryOfT,
+ ReadOnlyMemory<byte> readOnlyMemoryByte)
+ {
+ MemoryOfT = memoryOfT;
+ MemoryByte = memoryByte;
+ ReadOnlyMemoryOfT = readOnlyMemoryOfT;
+ ReadOnlyMemoryByte = readOnlyMemoryByte;
+ }
+
+ public Memory<T> MemoryOfT { get; set; }
+ public Memory<byte> MemoryByte { get; set; }
+ public ReadOnlyMemory<T> ReadOnlyMemoryOfT { get; set; }
+ public ReadOnlyMemory<byte> ReadOnlyMemoryByte { get; set; }
+ }
+
+ [JsonSerializable(typeof(MyClass<int>))]
+ public partial class MyJsonContext : JsonSerializerContext
+ {
+ }
+ }
+ """;
+
+ CSharpParseOptions parseOptions = CompilationHelper.CreateParseOptions(langVersion);
+ Compilation compilation = CompilationHelper.CreateCompilation(source, parseOptions: parseOptions);
+
+ CompilationHelper.RunJsonSourceGenerator(compilation);
+ }
+
+ [Theory]
[InlineData(LanguageVersion.CSharp1)]
[InlineData(LanguageVersion.CSharp2)]
[InlineData(LanguageVersion.CSharp3)]
<Compile Include="..\Common\CollectionTests\CollectionTests.Generic.Write.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.Generic.Write.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.Immutable.Read.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.Immutable.Read.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.KeyValuePair.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.KeyValuePair.cs" />
+ <Compile Include="..\Common\CollectionTests\CollectionTests.Memory.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.Memory.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.NonGeneric.Read.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.NonGeneric.Read.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.NonGeneric.Write.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.NonGeneric.Write.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.ObjectModel.Read.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.ObjectModel.Read.cs" />