summaryrefslogtreecommitdiffstats
path: root/generator/plugins/dotnet/custom/OrTypeConverter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'generator/plugins/dotnet/custom/OrTypeConverter.cs')
-rw-r--r--generator/plugins/dotnet/custom/OrTypeConverter.cs595
1 files changed, 595 insertions, 0 deletions
diff --git a/generator/plugins/dotnet/custom/OrTypeConverter.cs b/generator/plugins/dotnet/custom/OrTypeConverter.cs
new file mode 100644
index 0000000..f2aadbf
--- /dev/null
+++ b/generator/plugins/dotnet/custom/OrTypeConverter.cs
@@ -0,0 +1,595 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+internal class OrTypeConverterHelpers
+{
+ public static Type[] SortTypesByHeuristic(Type[] types, JToken jToken)
+ {
+ var typePropertyScores = new Dictionary<Type, int>();
+
+ string[] jTokenPropertyNames = jToken.Children<JProperty>().Select(p => p.Name.ToUpper()).ToArray();
+
+ foreach (Type type in types)
+ {
+ string[] typePropertyNames = type.GetProperties().Select(p => p.Name.ToUpper()).ToArray();
+
+ int score = jTokenPropertyNames.Count(propertyName => typePropertyNames.Contains(propertyName));
+ typePropertyScores[type] = score;
+ }
+
+ return types.OrderByDescending(type => typePropertyScores[type]).ToArray();
+ }
+}
+
+public class OrTypeConverter<T, U> : JsonConverter<OrType<T, U>>
+{
+ public override OrType<T, U>? ReadJson(JsonReader reader, Type objectType, OrType<T, U>? existingValue, bool hasExistingValue, JsonSerializer serializer)
+ {
+ reader = reader ?? throw new ArgumentNullException(nameof(reader));
+
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+
+ Type[] types = new Type[] { typeof(T), typeof(U) };
+
+ if (reader.TokenType == JsonToken.Integer && (Validators.HasType(types, typeof(uint)) || Validators.HasType(types, typeof(int))))
+ {
+ return ReadIntegerToken(reader, serializer, types);
+ }
+ if (reader.TokenType == JsonToken.Float && Validators.HasType(types, typeof(float)))
+ {
+ return ReadFloatToken(reader, serializer, types);
+ }
+ if (reader.TokenType == JsonToken.Boolean && Validators.HasType(types, typeof(bool)))
+ {
+ return ReadBooleanToken(reader, serializer, types);
+ }
+ if (reader.TokenType == JsonToken.String && Validators.HasType(types, typeof(string)))
+ {
+ return ReadStringToken(reader, serializer, types);
+ }
+
+ var token = JToken.Load(reader);
+ return OrTypeConverter<T, U>.ReadObjectToken(token, serializer, OrTypeConverterHelpers.SortTypesByHeuristic(types, token));
+ }
+
+ private static OrType<T, U> ReadIntegerToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ long integer = serializer.Deserialize<long>(reader);
+ if (Validators.InUIntegerRange(integer) && Validators.HasType(types, typeof(uint)))
+ {
+ if (typeof(T) == typeof(uint))
+ {
+ return new OrType<T, U>((T)(object)(uint)integer);
+ }
+ if (typeof(U) == typeof(uint))
+ {
+ return new OrType<T, U>((U)(object)(uint)integer);
+ }
+ }
+ if (Validators.InIntegerRange(integer) && Validators.HasType(types, typeof(int)))
+ {
+ if (typeof(T) == typeof(int))
+ {
+ return new OrType<T, U>((T)(object)(int)integer);
+ }
+ if (typeof(U) == typeof(int))
+ {
+ return new OrType<T, U>((U)(object)(int)integer);
+ }
+ }
+ throw new ArgumentOutOfRangeException($"Integer out-of-range of LSP Signed Integer[{int.MinValue}:{int.MaxValue}] and out-of-range of LSP Unsigned Integer [{uint.MinValue}:{uint.MaxValue}] => {integer}");
+ }
+
+ private static OrType<T, U> ReadFloatToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ float real = serializer.Deserialize<float>(reader);
+ if (typeof(T) == typeof(float))
+ {
+ return new OrType<T, U>((T)(object)real);
+ }
+ if (typeof(U) == typeof(float))
+ {
+ return new OrType<T, U>((U)(object)real);
+ }
+ throw new InvalidOperationException("Invalid token type for float");
+ }
+
+ private static OrType<T, U> ReadBooleanToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ bool boolean = serializer.Deserialize<bool>(reader);
+ if (typeof(T) == typeof(bool))
+ {
+ return new OrType<T, U>((T)(object)boolean);
+ }
+ if (typeof(U) == typeof(bool))
+ {
+ return new OrType<T, U>((U)(object)boolean);
+ }
+ throw new InvalidOperationException("Invalid token type for boolean");
+ }
+
+ private static OrType<T, U> ReadStringToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ string str = serializer.Deserialize<string>(reader)!;
+ if (typeof(T) == typeof(string))
+ {
+ return new OrType<T, U>((T)(object)str);
+ }
+ if (typeof(U) == typeof(string))
+ {
+ return new OrType<T, U>((U)(object)str);
+ }
+ throw new InvalidOperationException("Invalid token type for string");
+ }
+
+ private static OrType<T, U> ReadObjectToken(JToken token, JsonSerializer serializer, Type[] types)
+ {
+ var exceptions = new List<Exception>();
+ foreach (Type type in types)
+ {
+ try
+ {
+ object? value = null;
+ if (token.Type == JTokenType.Array && type == typeof((uint, uint)))
+ {
+ uint[]? o = token.ToObject<uint[]>(serializer);
+ if (o != null)
+ {
+ value = (o[0], o[1]);
+ }
+ }
+ else
+ {
+ value = token.ToObject(type, serializer);
+ }
+
+ if (value != null)
+ {
+ if (value is T t)
+ {
+ return new OrType<T, U>(t);
+ }
+ if (value is U u)
+ {
+ return new OrType<T, U>(u);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ exceptions.Add(ex);
+ continue;
+ }
+ }
+
+ throw new JsonSerializationException("Unable to deserialize object", new AggregateException(exceptions));
+ }
+
+
+
+ public override void WriteJson(JsonWriter writer, OrType<T, U>? value, JsonSerializer serializer)
+ {
+ if (value is null)
+ {
+ writer.WriteNull();
+ }
+ else if (value?.Value?.GetType() == typeof((uint, uint)))
+ {
+ ValueTuple<uint, uint> o = (ValueTuple<uint, uint>)(value.Value);
+ serializer.Serialize(writer, new uint[] { o.Item1, o.Item2 });
+ }
+ else
+ {
+ serializer.Serialize(writer, value?.Value);
+ }
+ }
+}
+
+public class OrTypeConverter<T, U, V> : JsonConverter<OrType<T, U, V>>
+{
+ public override OrType<T, U, V>? ReadJson(JsonReader reader, Type objectType, OrType<T, U, V>? existingValue, bool hasExistingValue, JsonSerializer serializer)
+ {
+ reader = reader ?? throw new ArgumentNullException(nameof(reader));
+
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+
+ Type[] types = new Type[] { typeof(T), typeof(U), typeof(V) };
+
+ if (reader.TokenType == JsonToken.Integer && (Validators.HasType(types, typeof(uint)) || Validators.HasType(types, typeof(int))))
+ {
+ return ReadIntegerToken(reader, serializer, types);
+ }
+ if (reader.TokenType == JsonToken.Float && Validators.HasType(types, typeof(float)))
+ {
+ return ReadFloatToken(reader, serializer, types);
+ }
+ if (reader.TokenType == JsonToken.Boolean && Validators.HasType(types, typeof(bool)))
+ {
+ return ReadBooleanToken(reader, serializer, types);
+ }
+ if (reader.TokenType == JsonToken.String && Validators.HasType(types, typeof(string)))
+ {
+ return ReadStringToken(reader, serializer, types);
+ }
+
+ var token = JToken.Load(reader);
+ return OrTypeConverter<T, U, V>.ReadObjectToken(token, serializer, OrTypeConverterHelpers.SortTypesByHeuristic(types, token));
+ }
+
+ private static OrType<T, U, V> ReadIntegerToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ long integer = serializer.Deserialize<long>(reader);
+ if (Validators.InUIntegerRange(integer) && Validators.HasType(types, typeof(uint)))
+ {
+ if (typeof(T) == typeof(uint))
+ {
+ return new OrType<T, U, V>((T)(object)(uint)integer);
+ }
+ if (typeof(U) == typeof(uint))
+ {
+ return new OrType<T, U, V>((U)(object)(uint)integer);
+ }
+ if (typeof(V) == typeof(uint))
+ {
+ return new OrType<T, U, V>((V)(object)(uint)integer);
+ }
+ }
+ if (Validators.InIntegerRange(integer) && Validators.HasType(types, typeof(int)))
+ {
+ if (typeof(T) == typeof(int))
+ {
+ return new OrType<T, U, V>((T)(object)(int)integer);
+ }
+ if (typeof(U) == typeof(int))
+ {
+ return new OrType<T, U, V>((U)(object)(int)integer);
+ }
+ if (typeof(V) == typeof(int))
+ {
+ return new OrType<T, U, V>((V)(object)(int)integer);
+ }
+ }
+ throw new ArgumentOutOfRangeException($"Integer out-of-range of LSP Signed Integer[{int.MinValue}:{int.MaxValue}] and out-of-range of LSP Unsigned Integer [{uint.MinValue}:{uint.MaxValue}] => {integer}");
+ }
+
+ private static OrType<T, U, V> ReadFloatToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ float real = serializer.Deserialize<float>(reader);
+ if (typeof(T) == typeof(float))
+ {
+ return new OrType<T, U, V>((T)(object)real);
+ }
+ if (typeof(U) == typeof(float))
+ {
+ return new OrType<T, U, V>((U)(object)real);
+ }
+ if (typeof(V) == typeof(float))
+ {
+ return new OrType<T, U, V>((V)(object)real);
+ }
+ throw new InvalidOperationException("Invalid token type for float");
+ }
+
+ private static OrType<T, U, V> ReadBooleanToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ bool boolean = serializer.Deserialize<bool>(reader);
+ if (typeof(T) == typeof(bool))
+ {
+ return new OrType<T, U, V>((T)(object)boolean);
+ }
+ if (typeof(U) == typeof(bool))
+ {
+ return new OrType<T, U, V>((U)(object)boolean);
+ }
+ if (typeof(V) == typeof(bool))
+ {
+ return new OrType<T, U, V>((V)(object)boolean);
+ }
+ throw new InvalidOperationException("Invalid token type for boolean");
+ }
+
+ private static OrType<T, U, V> ReadStringToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ string str = serializer.Deserialize<string>(reader)!;
+ if (typeof(T) == typeof(string))
+ {
+ return new OrType<T, U, V>((T)(object)str);
+ }
+ if (typeof(U) == typeof(string))
+ {
+ return new OrType<T, U, V>((U)(object)str);
+ }
+ if (typeof(V) == typeof(string))
+ {
+ return new OrType<T, U, V>((V)(object)str);
+ }
+ throw new InvalidOperationException("Invalid token type for string");
+ }
+
+ private static OrType<T, U, V> ReadObjectToken(JToken token, JsonSerializer serializer, Type[] types)
+ {
+ var exceptions = new List<Exception>();
+ foreach (Type type in types)
+ {
+ try
+ {
+ object? value = null;
+ if (token.Type == JTokenType.Array && type == typeof((uint, uint)))
+ {
+ uint[]? o = token.ToObject<uint[]>(serializer);
+ if (o != null)
+ {
+ value = (o[0], o[1]);
+ }
+ }
+ else
+ {
+ value = token.ToObject(type, serializer);
+ }
+
+ if (value != null)
+ {
+ if (value is T t)
+ {
+ return new OrType<T, U, V>(t);
+ }
+ if (value is U u)
+ {
+ return new OrType<T, U, V>(u);
+ }
+ if (value is V v)
+ {
+ return new OrType<T, U, V>(v);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ exceptions.Add(ex);
+ continue;
+ }
+ }
+
+ throw new JsonSerializationException("Unable to deserialize object", new AggregateException(exceptions));
+ }
+
+ public override void WriteJson(JsonWriter writer, OrType<T, U, V>? value, JsonSerializer serializer)
+ {
+ if (value is null)
+ {
+ writer.WriteNull();
+ }
+ else if (value?.Value?.GetType() == typeof((uint, uint)))
+ {
+ ValueTuple<uint, uint> o = (ValueTuple<uint, uint>)(value.Value);
+ serializer.Serialize(writer, new uint[] { o.Item1, o.Item2 });
+ }
+ else
+ {
+ serializer.Serialize(writer, value?.Value);
+ }
+ }
+}
+
+public class OrTypeConverter<T, U, V, W> : JsonConverter<OrType<T, U, V, W>>
+{
+ public override OrType<T, U, V, W>? ReadJson(JsonReader reader, Type objectType, OrType<T, U, V, W>? existingValue, bool hasExistingValue, JsonSerializer serializer)
+ {
+ reader = reader ?? throw new ArgumentNullException(nameof(reader));
+
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return null;
+ }
+
+ Type[] types = new Type[] { typeof(T), typeof(U), typeof(V), typeof(W) };
+
+ if (reader.TokenType == JsonToken.Integer && (Validators.HasType(types, typeof(uint)) || Validators.HasType(types, typeof(int))))
+ {
+ return ReadIntegerToken(reader, serializer, types);
+ }
+ if (reader.TokenType == JsonToken.Float && Validators.HasType(types, typeof(float)))
+ {
+ return ReadFloatToken(reader, serializer, types);
+ }
+ if (reader.TokenType == JsonToken.Boolean && Validators.HasType(types, typeof(bool)))
+ {
+ return ReadBooleanToken(reader, serializer, types);
+ }
+ if (reader.TokenType == JsonToken.String && Validators.HasType(types, typeof(string)))
+ {
+ return ReadStringToken(reader, serializer, types);
+ }
+
+ var token = JToken.Load(reader);
+ return OrTypeConverter<T, U, V, W>.ReadObjectToken(token, serializer, OrTypeConverterHelpers.SortTypesByHeuristic(types, token));
+ }
+
+ private static OrType<T, U, V, W> ReadIntegerToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ long integer = serializer.Deserialize<long>(reader);
+ if (Validators.InUIntegerRange(integer) && Validators.HasType(types, typeof(uint)))
+ {
+ if (typeof(T) == typeof(uint))
+ {
+ return new OrType<T, U, V, W>((T)(object)(uint)integer);
+ }
+ if (typeof(U) == typeof(uint))
+ {
+ return new OrType<T, U, V, W>((U)(object)(uint)integer);
+ }
+ if (typeof(V) == typeof(uint))
+ {
+ return new OrType<T, U, V, W>((V)(object)(uint)integer);
+ }
+ if (typeof(W) == typeof(uint))
+ {
+ return new OrType<T, U, V, W>((W)(object)(uint)integer);
+ }
+ }
+ if (Validators.InIntegerRange(integer) && Validators.HasType(types, typeof(int)))
+ {
+ if (typeof(T) == typeof(int))
+ {
+ return new OrType<T, U, V, W>((T)(object)(int)integer);
+ }
+ if (typeof(U) == typeof(int))
+ {
+ return new OrType<T, U, V, W>((U)(object)(int)integer);
+ }
+ if (typeof(V) == typeof(int))
+ {
+ return new OrType<T, U, V, W>((V)(object)(int)integer);
+ }
+ if (typeof(W) == typeof(int))
+ {
+ return new OrType<T, U, V, W>((W)(object)(int)integer);
+ }
+ }
+ throw new ArgumentOutOfRangeException($"Integer out-of-range of LSP Signed Integer[{int.MinValue}:{int.MaxValue}] and out-of-range of LSP Unsigned Integer [{uint.MinValue}:{uint.MaxValue}] => {integer}");
+ }
+
+ private static OrType<T, U, V, W> ReadFloatToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ float real = serializer.Deserialize<float>(reader);
+ if (typeof(T) == typeof(float))
+ {
+ return new OrType<T, U, V, W>((T)(object)real);
+ }
+ if (typeof(U) == typeof(float))
+ {
+ return new OrType<T, U, V, W>((U)(object)real);
+ }
+ if (typeof(V) == typeof(float))
+ {
+ return new OrType<T, U, V, W>((V)(object)real);
+ }
+ if (typeof(W) == typeof(float))
+ {
+ return new OrType<T, U, V, W>((W)(object)real);
+ }
+ throw new InvalidOperationException("Invalid token type for float");
+ }
+
+ private static OrType<T, U, V, W> ReadBooleanToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ bool boolean = serializer.Deserialize<bool>(reader);
+ if (typeof(T) == typeof(bool))
+ {
+ return new OrType<T, U, V, W>((T)(object)boolean);
+ }
+ if (typeof(U) == typeof(bool))
+ {
+ return new OrType<T, U, V, W>((U)(object)boolean);
+ }
+ if (typeof(V) == typeof(bool))
+ {
+ return new OrType<T, U, V, W>((V)(object)boolean);
+ }
+ if (typeof(W) == typeof(bool))
+ {
+ return new OrType<T, U, V, W>((W)(object)boolean);
+ }
+ throw new InvalidOperationException("Invalid token type for boolean");
+ }
+
+ private static OrType<T, U, V, W> ReadStringToken(JsonReader reader, JsonSerializer serializer, Type[] types)
+ {
+ string str = serializer.Deserialize<string>(reader)!;
+ if (typeof(T) == typeof(string))
+ {
+ return new OrType<T, U, V, W>((T)(object)str);
+ }
+ if (typeof(U) == typeof(string))
+ {
+ return new OrType<T, U, V, W>((U)(object)str);
+ }
+ if (typeof(V) == typeof(string))
+ {
+ return new OrType<T, U, V, W>((V)(object)str);
+ }
+ if (typeof(W) == typeof(string))
+ {
+ return new OrType<T, U, V, W>((W)(object)str);
+ }
+ throw new InvalidOperationException("Invalid token type for string");
+ }
+
+ private static OrType<T, U, V, W> ReadObjectToken(JToken token, JsonSerializer serializer, Type[] types)
+ {
+ var exceptions = new List<Exception>();
+ foreach (Type type in types)
+ {
+ try
+ {
+ object? value = null;
+ if (token.Type == JTokenType.Array && type == typeof((uint, uint)))
+ {
+ uint[]? o = token.ToObject<uint[]>(serializer);
+ if (o != null)
+ {
+ value = (o[0], o[1]);
+ }
+ }
+ else
+ {
+ value = token.ToObject(type, serializer);
+ }
+
+ if (value != null)
+ {
+ if (value is T t)
+ {
+ return new OrType<T, U, V, W>(t);
+ }
+ if (value is U u)
+ {
+ return new OrType<T, U, V, W>(u);
+ }
+ if (value is V v)
+ {
+ return new OrType<T, U, V, W>(v);
+ }
+ if (value is W w)
+ {
+ return new OrType<T, U, V, W>(w);
+ }
+ }
+
+ }
+ catch (Exception ex)
+ {
+ exceptions.Add(ex);
+ continue;
+ }
+ }
+
+ throw new JsonSerializationException("Unable to deserialize object", new AggregateException(exceptions));
+ }
+
+ public override void WriteJson(JsonWriter writer, OrType<T, U, V, W>? value, JsonSerializer serializer)
+ {
+ if (value is null)
+ {
+ writer.WriteNull();
+ }
+ else if (value?.Value?.GetType() == typeof((uint, uint)))
+ {
+ ValueTuple<uint, uint> o = (ValueTuple<uint, uint>)(value.Value);
+ serializer.Serialize(writer, new uint[] { o.Item1, o.Item2 });
+ }
+ else
+ {
+ serializer.Serialize(writer, value?.Value);
+ }
+ }
+} \ No newline at end of file