-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
736 additions
and
0 deletions.
There are no files selected for viewing
13 changes: 13 additions & 0 deletions
13
Badeend.ValueCollections.SystemTextJson/Badeend.ValueCollections.SystemTextJson.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<PackageId>Badeend.ValueCollections.SystemTextJson</PackageId> | ||
<Description>System.Text.Json converters for Badeend.ValueCollections</Description> | ||
<TargetFrameworks>netstandard2.0;net8</TargetFrameworks> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<PackageReference Include="System.Text.Json" Version="8.0.0" Condition="'$(TargetFramework)' == 'netstandard2.0'" /> | ||
|
||
<PackageReference Include="Badeend.ValueCollections" Version="$(Version)" Condition="'$(ProjectReferences)' == 'Remote'" /> | ||
<ProjectReference Include="..\Badeend.ValueCollections\Badeend.ValueCollections.csproj" Condition="'$(ProjectReferences)' == 'Local'" /> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
/// <summary> | ||
/// Methods for configuring <c>System.Text.Json</c>. | ||
/// </summary> | ||
[SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces", Justification = "Don't care; the name `Configuration` is too generic and the type `System.Configuration` is not widespread enough for me to care.")] | ||
public static class Configuration | ||
{ | ||
private static readonly JsonConverter ValueSliceConverterFactory = new JsonArrayConverterFactory(typeof(ValueSlice<>), typeof(ValueSliceConverter<>)); | ||
|
||
private static readonly JsonConverter ValueListConverterFactory = new JsonArrayConverterFactory(typeof(ValueList<>), typeof(ValueListConverter<>)); | ||
|
||
private static readonly JsonConverter ValueListBuilderConverterFactory = new JsonArrayConverterFactory(typeof(ValueListBuilder<>), typeof(ValueListBuilderConverter<>)); | ||
|
||
private static readonly JsonConverter ValueSetConverterFactory = new JsonArrayConverterFactory(typeof(ValueSet<>), typeof(ValueSetConverter<>)); | ||
|
||
private static readonly JsonConverter ValueSetBuilderConverterFactory = new JsonArrayConverterFactory(typeof(ValueSetBuilder<>), typeof(ValueSetBuilderConverter<>)); | ||
|
||
private static readonly JsonConverter ValueDictionaryConverterFactory = new JsonObjectConverterFactory(typeof(ValueDictionary<,>), typeof(ValueDictionaryConverter<,>)); | ||
|
||
private static readonly JsonConverter ValueDictionaryBuilderConverterFactory = new JsonObjectConverterFactory(typeof(ValueDictionaryBuilder<,>), typeof(ValueDictionaryBuilderConverter<,>)); | ||
|
||
/// <summary> | ||
/// Configure <c>System.Text.Json</c> to serialize and deserialize <c>Badeend.ValueCollections</c> data types. | ||
/// </summary> | ||
/// <returns>The <paramref name="options"/> instance for further chaining.</returns> | ||
public static JsonSerializerOptions AddValueCollections(this JsonSerializerOptions options) | ||
{ | ||
if (options is null) | ||
{ | ||
throw new ArgumentNullException(nameof(options)); | ||
} | ||
|
||
options.Converters.Add(ValueSliceConverterFactory); | ||
options.Converters.Add(ValueListConverterFactory); | ||
options.Converters.Add(ValueListBuilderConverterFactory); | ||
options.Converters.Add(ValueSetConverterFactory); | ||
options.Converters.Add(ValueSetBuilderConverterFactory); | ||
options.Converters.Add(ValueDictionaryConverterFactory); | ||
options.Converters.Add(ValueDictionaryBuilderConverterFactory); | ||
|
||
return options; | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
Badeend.ValueCollections.SystemTextJson/JsonArrayConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
/// <summary> | ||
/// Utility for converters that read/write JSON arrays. | ||
/// </summary> | ||
internal readonly struct JsonArrayConverter<T> | ||
{ | ||
private readonly JsonConverter<T> valueConverter; | ||
private readonly Type valueType; | ||
|
||
internal JsonArrayConverter(JsonConverter<T> valueConverter) | ||
{ | ||
this.valueConverter = valueConverter; | ||
this.valueType = typeof(T); | ||
} | ||
|
||
internal void ReadInto(ref Utf8JsonReader reader, ICollection<T> destination, JsonSerializerOptions options) | ||
{ | ||
if (reader.TokenType != JsonTokenType.StartArray) | ||
{ | ||
throw new JsonException(); | ||
} | ||
|
||
while (reader.Read()) | ||
{ | ||
if (reader.TokenType == JsonTokenType.EndArray) | ||
{ | ||
return; | ||
} | ||
|
||
var value = this.valueConverter.Read(ref reader, this.valueType, options)!; | ||
|
||
destination.Add(value); | ||
} | ||
|
||
throw new JsonException(); | ||
} | ||
|
||
internal void Write(Utf8JsonWriter writer, IEnumerable<T> source, JsonSerializerOptions options) | ||
{ | ||
writer.WriteStartArray(); | ||
|
||
foreach (var value in source) | ||
{ | ||
this.valueConverter.Write(writer, value, options); | ||
} | ||
|
||
writer.WriteEndArray(); | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
Badeend.ValueCollections.SystemTextJson/JsonArrayConverterFactory.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
internal sealed class JsonArrayConverterFactory : JsonConverterFactory | ||
{ | ||
private readonly Type genericValueType; | ||
private readonly Type genericConverterType; | ||
|
||
internal JsonArrayConverterFactory(Type genericValueType, Type genericConverterType) | ||
{ | ||
this.genericValueType = genericValueType; | ||
this.genericConverterType = genericConverterType; | ||
} | ||
|
||
public override bool CanConvert(Type typeToConvert) | ||
{ | ||
if (!typeToConvert.IsGenericType) | ||
{ | ||
return false; | ||
} | ||
|
||
return typeToConvert.GetGenericTypeDefinition() == this.genericValueType; | ||
} | ||
|
||
public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options) | ||
{ | ||
Type[] typeArguments = type.GetGenericArguments(); | ||
Type valueType = typeArguments[0]; | ||
|
||
JsonConverter converter = (JsonConverter)Activator.CreateInstance( | ||
type: this.genericConverterType.MakeGenericType([valueType]), | ||
args: [options.GetConverter(valueType)])!; | ||
|
||
return converter; | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
Badeend.ValueCollections.SystemTextJson/JsonObjectConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
/// <summary> | ||
/// Utility for converters that read/write JSON objects. | ||
/// </summary> | ||
internal readonly struct JsonObjectConverter<TKey, TValue> | ||
where TKey : notnull | ||
{ | ||
private readonly JsonConverter<TKey> keyConverter; | ||
private readonly Type keyType; | ||
private readonly JsonConverter<TValue> valueConverter; | ||
private readonly Type valueType; | ||
|
||
internal JsonObjectConverter(JsonConverter<TKey> keyConverter, JsonConverter<TValue> valueConverter) | ||
{ | ||
this.keyConverter = keyConverter; | ||
this.keyType = typeof(TKey); | ||
this.valueConverter = valueConverter; | ||
this.valueType = typeof(TValue); | ||
} | ||
|
||
internal void ReadInto(ref Utf8JsonReader reader, IDictionary<TKey, TValue> destination, JsonSerializerOptions options) | ||
{ | ||
if (reader.TokenType != JsonTokenType.StartObject) | ||
{ | ||
throw new JsonException(); | ||
} | ||
|
||
while (reader.Read()) | ||
{ | ||
if (reader.TokenType == JsonTokenType.EndObject) | ||
{ | ||
return; | ||
} | ||
|
||
if (reader.TokenType != JsonTokenType.PropertyName) | ||
{ | ||
throw new JsonException(); | ||
} | ||
|
||
var key = this.keyConverter.ReadAsPropertyName(ref reader, this.keyType, options); | ||
|
||
if (!reader.Read()) | ||
{ | ||
throw new JsonException(); | ||
} | ||
|
||
var value = this.valueConverter.Read(ref reader, this.valueType, options)!; | ||
|
||
destination.Add(key, value); | ||
} | ||
|
||
throw new JsonException(); | ||
} | ||
|
||
internal void Write(Utf8JsonWriter writer, IEnumerable<KeyValuePair<TKey, TValue>> source, JsonSerializerOptions options) | ||
{ | ||
writer.WriteStartObject(); | ||
|
||
foreach (var entry in source) | ||
{ | ||
this.keyConverter.WriteAsPropertyName(writer, entry.Key, options); | ||
this.valueConverter.Write(writer, entry.Value, options); | ||
} | ||
|
||
writer.WriteEndObject(); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
Badeend.ValueCollections.SystemTextJson/JsonObjectConverterFactory.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
internal sealed class JsonObjectConverterFactory : JsonConverterFactory | ||
{ | ||
private readonly Type genericValueType; | ||
private readonly Type genericConverterType; | ||
|
||
internal JsonObjectConverterFactory(Type genericValueType, Type genericConverterType) | ||
{ | ||
this.genericValueType = genericValueType; | ||
this.genericConverterType = genericConverterType; | ||
} | ||
|
||
public override bool CanConvert(Type typeToConvert) | ||
{ | ||
if (!typeToConvert.IsGenericType) | ||
{ | ||
return false; | ||
} | ||
|
||
return typeToConvert.GetGenericTypeDefinition() == this.genericValueType; | ||
} | ||
|
||
public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options) | ||
{ | ||
Type[] typeArguments = type.GetGenericArguments(); | ||
Type keyType = typeArguments[0]; | ||
Type valueType = typeArguments[1]; | ||
|
||
JsonConverter converter = (JsonConverter)Activator.CreateInstance( | ||
type: this.genericConverterType.MakeGenericType([keyType, valueType]), | ||
args: [options.GetConverter(keyType), options.GetConverter(valueType)])!; | ||
|
||
return converter; | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
Badeend.ValueCollections.SystemTextJson/ValueDictionaryBuilderConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Instantiated using reflection")] | ||
internal sealed class ValueDictionaryBuilderConverter<TKey, TValue>(JsonConverter<TKey> keyConverter, JsonConverter<TValue> valueConverter) : JsonConverter<ValueDictionaryBuilder<TKey, TValue>> | ||
where TKey : notnull | ||
{ | ||
private readonly JsonObjectConverter<TKey, TValue> inner = new(keyConverter, valueConverter); | ||
|
||
public override ValueDictionaryBuilder<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
{ | ||
var builder = new ValueDictionaryBuilder<TKey, TValue>(); | ||
this.inner.ReadInto(ref reader, builder, options); | ||
return builder; | ||
} | ||
|
||
public override void Write(Utf8JsonWriter writer, ValueDictionaryBuilder<TKey, TValue> dictionary, JsonSerializerOptions options) | ||
{ | ||
this.inner.Write(writer, dictionary, options); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
Badeend.ValueCollections.SystemTextJson/ValueDictionaryConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Instantiated using reflection")] | ||
internal sealed class ValueDictionaryConverter<TKey, TValue>(JsonConverter<TKey> keyConverter, JsonConverter<TValue> valueConverter) : JsonConverter<ValueDictionary<TKey, TValue>> | ||
where TKey : notnull | ||
{ | ||
private readonly JsonObjectConverter<TKey, TValue> inner = new(keyConverter, valueConverter); | ||
|
||
public override ValueDictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
{ | ||
var builder = new ValueDictionaryBuilder<TKey, TValue>(); | ||
this.inner.ReadInto(ref reader, builder, options); | ||
return builder.Build(); | ||
} | ||
|
||
public override void Write(Utf8JsonWriter writer, ValueDictionary<TKey, TValue> dictionary, JsonSerializerOptions options) | ||
{ | ||
this.inner.Write(writer, dictionary, options); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
Badeend.ValueCollections.SystemTextJson/ValueListBuilderConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Instantiated using reflection")] | ||
internal sealed class ValueListBuilderConverter<T>(JsonConverter<T> valueConverter) : JsonConverter<ValueListBuilder<T>> | ||
{ | ||
private readonly JsonArrayConverter<T> inner = new(valueConverter); | ||
|
||
public override ValueListBuilder<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
{ | ||
var builder = new ValueListBuilder<T>(); | ||
this.inner.ReadInto(ref reader, builder, options); | ||
return builder; | ||
} | ||
|
||
public override void Write(Utf8JsonWriter writer, ValueListBuilder<T> builder, JsonSerializerOptions options) | ||
{ | ||
this.inner.Write(writer, builder, options); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
Badeend.ValueCollections.SystemTextJson/ValueListConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Instantiated using reflection")] | ||
internal sealed class ValueListConverter<T>(JsonConverter<T> valueConverter) : JsonConverter<ValueList<T>> | ||
{ | ||
private readonly JsonArrayConverter<T> inner = new(valueConverter); | ||
|
||
public override ValueList<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
{ | ||
var builder = new ValueListBuilder<T>(); | ||
this.inner.ReadInto(ref reader, builder, options); | ||
return builder.Build(); | ||
} | ||
|
||
public override void Write(Utf8JsonWriter writer, ValueList<T> list, JsonSerializerOptions options) | ||
{ | ||
this.inner.Write(writer, list, options); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
Badeend.ValueCollections.SystemTextJson/ValueSetBuilderConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Badeend.ValueCollections.SystemTextJson; | ||
|
||
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Instantiated using reflection")] | ||
internal sealed class ValueSetBuilderConverter<T>(JsonConverter<T> valueConverter) : JsonConverter<ValueSetBuilder<T>> | ||
{ | ||
private readonly JsonArrayConverter<T> inner = new(valueConverter); | ||
|
||
public override ValueSetBuilder<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
{ | ||
var builder = new ValueSetBuilder<T>(); | ||
this.inner.ReadInto(ref reader, builder, options); | ||
return builder; | ||
} | ||
|
||
public override void Write(Utf8JsonWriter writer, ValueSetBuilder<T> builder, JsonSerializerOptions options) | ||
{ | ||
this.inner.Write(writer, builder, options); | ||
} | ||
} |
Oops, something went wrong.