diff --git a/src/NexusMods.DataModel/JsonConverters/OptionalConverter.cs b/src/NexusMods.DataModel/JsonConverters/OptionalConverter.cs new file mode 100644 index 0000000000..c71270a05e --- /dev/null +++ b/src/NexusMods.DataModel/JsonConverters/OptionalConverter.cs @@ -0,0 +1,69 @@ +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; +using DynamicData.Kernel; +using JetBrains.Annotations; + +namespace NexusMods.DataModel.JsonConverters; + +/// +/// Converter factory for +/// +[UsedImplicitly] +public class OptionalConverterFactory : JsonConverterFactory +{ + /// + public override bool CanConvert(Type typeToConvert) + { + if (!typeToConvert.IsGenericType) return false; + return typeToConvert.GetGenericTypeDefinition() == typeof(Optional<>); + } + + /// + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + var typeArguments = typeToConvert.GetGenericArguments(); + var valueType = typeArguments[0]; + + var converter = (JsonConverter)Activator.CreateInstance( + type: typeof(OptionalConverter<>).MakeGenericType(valueType), + bindingAttr: BindingFlags.Instance | BindingFlags.Public, + binder: null, + args: [options], + culture: null + )!; + + return converter; + } + + private class OptionalConverter : JsonConverter> + where TValue : notnull + { + private readonly JsonConverter _valueConverter; + + [UsedImplicitly] + public OptionalConverter(JsonSerializerOptions options) + { + _valueConverter = (JsonConverter)options.GetConverter(typeof(TValue)); + } + + public override Optional Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) return Optional.None; + var value = _valueConverter.Read(ref reader, typeToConvert, options); + return Optional.Create(value); + } + + public override void Write(Utf8JsonWriter writer, Optional value, JsonSerializerOptions options) + { + if (!value.HasValue) + { + writer.WriteNullValue(); + } + else + { + _valueConverter.Write(writer, value.Value, options); + } + } + } +} diff --git a/src/NexusMods.DataModel/Services.cs b/src/NexusMods.DataModel/Services.cs index f0aa4190ff..5d31e89a54 100644 --- a/src/NexusMods.DataModel/Services.cs +++ b/src/NexusMods.DataModel/Services.cs @@ -86,7 +86,9 @@ public static IServiceCollection AddDataModel(this IServiceCollection coll) coll.AddSingleton(); coll.AddSingleton(); coll.AddSingleton(); - + coll.AddSingleton(); + coll.AddSingleton(); + // Game Registry coll.AddSingleton(); coll.AddHostedService(s => (GameRegistry)s.GetRequiredService());