@@ -18,10 +18,16 @@ namespace Discord.Rest | |||||
public DiscordRestClient(DiscordRestConfig config) : base(config) | public DiscordRestClient(DiscordRestConfig config) : base(config) | ||||
{ | { | ||||
_serializer = DiscordRestJsonSerializer.Global.CreateScope(); | _serializer = DiscordRestJsonSerializer.Global.CreateScope(); | ||||
_serializer.Error += ex => | |||||
if (config.LogLevel >= LogSeverity.Warning) | |||||
{ | { | ||||
_restLogger.WarningAsync("Serializer Error", ex).GetAwaiter().GetResult(); | |||||
}; | |||||
_serializer.ModelError += (path, ex) | |||||
=> _restLogger.WarningAsync($"Failed to deserialize {path}", ex).GetAwaiter().GetResult(); | |||||
} | |||||
if (config.LogLevel >= LogSeverity.Debug) | |||||
{ | |||||
_serializer.UnmappedProperty += path | |||||
=> _restLogger.DebugAsync($"Unmapped property: {path}"); | |||||
} | |||||
SetApiClient(new API.DiscordRestApiClient(config.RestClientProvider, DiscordConfig.UserAgent, _serializer, config.DefaultRetryMode)); | SetApiClient(new API.DiscordRestApiClient(config.RestClientProvider, DiscordConfig.UserAgent, _serializer, config.DefaultRetryMode)); | ||||
} | } | ||||
@@ -12,19 +12,19 @@ namespace Discord.Serialization.Json.Converters | |||||
_innerConverter = innerConverter; | _innerConverter = innerConverter; | ||||
} | } | ||||
public override EntityOrId<T> Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override EntityOrId<T> Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
if (reader.ValueType == JsonValueType.Number) | if (reader.ValueType == JsonValueType.Number) | ||||
return new EntityOrId<T>(reader.ParseUInt64()); | return new EntityOrId<T>(reader.ParseUInt64()); | ||||
return new EntityOrId<T>(_innerConverter.Read(map, model, ref reader, false)); | |||||
return new EntityOrId<T>(_innerConverter.Read(serializer, modelMap, propMap, model, ref reader, false)); | |||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, EntityOrId<T> value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, EntityOrId<T> value, string key) | |||||
{ | { | ||||
if (value.Object != null) | if (value.Object != null) | ||||
_innerConverter.Write(map, model, ref writer, value.Object, key); | |||||
_innerConverter.Write(serializer, modelMap, propMap, model, ref writer, value.Object, key); | |||||
else | else | ||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
@@ -5,7 +5,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
internal class ImagePropertyConverter : JsonPropertyConverter<API.Image> | internal class ImagePropertyConverter : JsonPropertyConverter<API.Image> | ||||
{ | { | ||||
public override API.Image Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override API.Image Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -13,7 +13,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected String"); | throw new SerializationException("Bad input, expected String"); | ||||
return new API.Image(reader.ParseString()); | return new API.Image(reader.ParseString()); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, API.Image value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, API.Image value, string key) | |||||
{ | { | ||||
string str; | string str; | ||||
if (value.Stream != null) | if (value.Stream != null) | ||||
@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
internal class Int53PropertyConverter : JsonPropertyConverter<long> | internal class Int53PropertyConverter : JsonPropertyConverter<long> | ||||
{ | { | ||||
public override long Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override long Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number"); | throw new SerializationException("Bad input, expected Number"); | ||||
return reader.ParseInt64(); | return reader.ParseInt64(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, long value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, long value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -11,13 +11,13 @@ namespace Discord.Serialization.Json.Converters | |||||
_innerConverter = innerConverter; | _innerConverter = innerConverter; | ||||
} | } | ||||
public override Optional<T> Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
=> new Optional<T>(_innerConverter.Read(map, model, ref reader, isTopLevel)); | |||||
public override Optional<T> Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
=> new Optional<T>(_innerConverter.Read(serializer, modelMap, propMap, model, ref reader, isTopLevel)); | |||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, Optional<T> value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, Optional<T> value, string key) | |||||
{ | { | ||||
if (value.IsSpecified) | if (value.IsSpecified) | ||||
_innerConverter.Write(map, model, ref writer, value.Value, key); | |||||
_innerConverter.Write(serializer, modelMap, propMap, model, ref writer, value.Value, key); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
internal class UInt53PropertyConverter : JsonPropertyConverter<ulong> | internal class UInt53PropertyConverter : JsonPropertyConverter<ulong> | ||||
{ | { | ||||
public override ulong Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override ulong Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number"); | throw new SerializationException("Bad input, expected Number"); | ||||
return reader.ParseUInt64(); | return reader.ParseUInt64(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, ulong value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, ulong value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -42,13 +42,24 @@ namespace Discord.Serialization | |||||
public void Add(ReadOnlyBuffer<byte> key, TValue value) | public void Add(ReadOnlyBuffer<byte> key, TValue value) | ||||
{ | { | ||||
if (!TryAdd(key, value)) | |||||
throw new ArgumentException("Duplicate key"); | |||||
} | |||||
public void Add(ReadOnlySpan<byte> key, TValue value) | |||||
{ | |||||
if (!TryAdd(key, value)) | |||||
throw new ArgumentException("Duplicate key"); | |||||
} | |||||
public bool TryAdd(ReadOnlyBuffer<byte> key, TValue value) | |||||
{ | |||||
int hashCode = GetKeyHashCode(key) & 0x7FFFFFFF; | int hashCode = GetKeyHashCode(key) & 0x7FFFFFFF; | ||||
int targetBucket = hashCode % _buckets.Length; | int targetBucket = hashCode % _buckets.Length; | ||||
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next) | for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next) | ||||
{ | { | ||||
if (_entries[i].hashCode == hashCode && KeyEquals(_entries[i].key, key)) | if (_entries[i].hashCode == hashCode && KeyEquals(_entries[i].key, key)) | ||||
throw new ArgumentException("Duplicate key", nameof(key)); | |||||
return false; | |||||
} | } | ||||
int index; | int index; | ||||
if (_freeCount > 0) | if (_freeCount > 0) | ||||
@@ -73,6 +84,43 @@ namespace Discord.Serialization | |||||
_entries[index].key = key; | _entries[index].key = key; | ||||
_entries[index].value = value; | _entries[index].value = value; | ||||
_buckets[targetBucket] = index; | _buckets[targetBucket] = index; | ||||
return true; | |||||
} | |||||
//Duplicate code for perf reasons | |||||
public bool TryAdd(ReadOnlySpan<byte> key, TValue value) | |||||
{ | |||||
int hashCode = GetKeyHashCode(key) & 0x7FFFFFFF; | |||||
int targetBucket = hashCode % _buckets.Length; | |||||
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next) | |||||
{ | |||||
if (_entries[i].hashCode == hashCode && KeyEquals(_entries[i].key, key)) | |||||
return false; | |||||
} | |||||
int index; | |||||
if (_freeCount > 0) | |||||
{ | |||||
index = _freeList; | |||||
_freeList = _entries[index].next; | |||||
_freeCount--; | |||||
} | |||||
else | |||||
{ | |||||
if (_count == _entries.Length) | |||||
{ | |||||
Resize(); | |||||
targetBucket = hashCode % _buckets.Length; | |||||
} | |||||
index = _count; | |||||
_count++; | |||||
} | |||||
_entries[index].hashCode = hashCode; | |||||
_entries[index].next = _buckets[targetBucket]; | |||||
_entries[index].key = new ReadOnlyBuffer<byte>(key.ToArray()); | |||||
_entries[index].value = value; | |||||
_buckets[targetBucket] = index; | |||||
return true; | |||||
} | } | ||||
private void Resize() | private void Resize() | ||||
{ | { | ||||
@@ -94,13 +94,13 @@ namespace Discord.Serialization | |||||
public void AddSelector(Serializer serializer, string groupKey, Type keyType, object keyValue, Type converterType) | public void AddSelector(Serializer serializer, string groupKey, Type keyType, object keyValue, Type converterType) | ||||
{ | { | ||||
var group = CreateSelectorGroup(keyType, groupKey); | var group = CreateSelectorGroup(keyType, groupKey); | ||||
group.AddDynamicConverter(keyValue, BuildConverter(converterType, serializer)); | |||||
group.AddDynamicConverter(keyValue, BuildConverter(converterType, serializer )); | |||||
} | } | ||||
public object Get(Serializer serializer, Type type, PropertyInfo propInfo = null, bool throwOnNotFound = true) | public object Get(Serializer serializer, Type type, PropertyInfo propInfo = null, bool throwOnNotFound = true) | ||||
{ | { | ||||
//Check parent | //Check parent | ||||
object converter = _parent?.Get(serializer, type, propInfo, false); | |||||
var converter = _parent?.Get(serializer, type, propInfo, false); | |||||
if (converter != null) | if (converter != null) | ||||
return converter; | return converter; | ||||
@@ -190,6 +190,7 @@ namespace Discord.Serialization | |||||
else | else | ||||
throw new SerializationException($"{converterType.Name} has an unsupported constructor"); | throw new SerializationException($"{converterType.Name} has an unsupported constructor"); | ||||
} | } | ||||
return constructor.Invoke(args); | return constructor.Invoke(args); | ||||
} | } | ||||
@@ -8,6 +8,9 @@ | |||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | <AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<Compile Include="..\Discord.Net.Core\Utils\ConcurrentHashSet.cs" Link="Utils\ConcurrentHashSet.cs" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<PackageReference Include="System.Buffers" Version="4.4.0" /> | <PackageReference Include="System.Buffers" Version="4.4.0" /> | ||||
<PackageReference Include="System.Collections.Immutable" Version="1.4.0" /> | <PackageReference Include="System.Collections.Immutable" Version="1.4.0" /> | ||||
<PackageReference Include="System.Interactive.Async" Version="3.1.1" /> | <PackageReference Include="System.Interactive.Async" Version="3.1.1" /> | ||||
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters | |||||
_valueConverter = valueConverter; | _valueConverter = valueConverter; | ||||
} | } | ||||
public override Dictionary<string, TValue> Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override Dictionary<string, TValue> Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if ((isTopLevel && !reader.Read()) || reader.TokenType != JsonTokenType.StartObject) | if ((isTopLevel && !reader.Read()) || reader.TokenType != JsonTokenType.StartObject) | ||||
throw new SerializationException("Bad input, expected StartObject"); | throw new SerializationException("Bad input, expected StartObject"); | ||||
@@ -26,20 +26,20 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected PropertyName"); | throw new SerializationException("Bad input, expected PropertyName"); | ||||
string key = reader.Value.ParseString(); | string key = reader.Value.ParseString(); | ||||
var value = _valueConverter.Read(map, model, ref reader, false); | |||||
var value = _valueConverter.Read(serializer, modelMap, propMap, model, ref reader, false); | |||||
dic.Add(key, value); | dic.Add(key, value); | ||||
} | } | ||||
return dic; | return dic; | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, Dictionary<string, TValue> value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, Dictionary<string, TValue> value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteObjectStart(key); | writer.WriteObjectStart(key); | ||||
else | else | ||||
writer.WriteObjectStart(); | writer.WriteObjectStart(); | ||||
foreach (var pair in value) | foreach (var pair in value) | ||||
_valueConverter.Write(map, model, ref writer, pair.Value, pair.Key); | |||||
_valueConverter.Write(serializer, modelMap, propMap, model, ref writer, pair.Value, pair.Key); | |||||
writer.WriteObjectEnd(); | writer.WriteObjectEnd(); | ||||
} | } | ||||
} | } | ||||
@@ -5,10 +5,10 @@ namespace Discord.Serialization.Json.Converters | |||||
//TODO: Only supports cases where the key arrives first | //TODO: Only supports cases where the key arrives first | ||||
public class DynamicPropertyConverter : JsonPropertyConverter<object> | public class DynamicPropertyConverter : JsonPropertyConverter<object> | ||||
{ | { | ||||
public override object Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override object Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (map.GetDynamicConverter(model, false) is IJsonPropertyReader<object> converter) | |||||
return converter.Read(map, model, ref reader, isTopLevel); | |||||
if (propMap.GetDynamicConverter(model, false) is IJsonPropertyReader<object> converter) | |||||
return converter.Read(serializer, modelMap, propMap, model, ref reader, isTopLevel); | |||||
else | else | ||||
{ | { | ||||
JsonReaderUtils.Skip(ref reader); | JsonReaderUtils.Skip(ref reader); | ||||
@@ -16,7 +16,7 @@ namespace Discord.Serialization.Json.Converters | |||||
} | } | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, object value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, object value, string key) | |||||
{ | { | ||||
if (value == null) | if (value == null) | ||||
{ | { | ||||
@@ -27,8 +27,8 @@ namespace Discord.Serialization.Json.Converters | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
var converter = (IJsonPropertyWriter)map.GetDynamicConverter(model, true); | |||||
converter.Write(map, model, ref writer, value, key); | |||||
var converter = (IJsonPropertyWriter)propMap.GetDynamicConverter(model, true); | |||||
converter.Write(serializer, modelMap, propMap, model, ref writer, value, key); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -7,7 +7,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
private static readonly EnumMap<T> _map = EnumMap.For<T>(); | private static readonly EnumMap<T> _map = EnumMap.For<T>(); | ||||
public override T Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override T Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -15,7 +15,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return _map.FromInt64(reader.Value); | return _map.FromInt64(reader.Value); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, T value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, T value, string key) | |||||
{ | { | ||||
long intVal = _map.ToInt64(value); | long intVal = _map.ToInt64(value); | ||||
if (key != null) | if (key != null) | ||||
@@ -30,7 +30,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
private static readonly EnumMap<T> _map = EnumMap.For<T>(); | private static readonly EnumMap<T> _map = EnumMap.For<T>(); | ||||
public override T Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override T Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -38,7 +38,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return _map.FromUInt64(reader.Value); | return _map.FromUInt64(reader.Value); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, T value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, T value, string key) | |||||
{ | { | ||||
ulong uintVal = _map.ToUInt64(value); | ulong uintVal = _map.ToUInt64(value); | ||||
if (key != null) | if (key != null) | ||||
@@ -53,7 +53,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
private static readonly EnumMap<T> _map = EnumMap.For<T>(); | private static readonly EnumMap<T> _map = EnumMap.For<T>(); | ||||
public override T Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override T Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -61,7 +61,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected String"); | throw new SerializationException("Bad input, expected String"); | ||||
return _map.FromKey(reader.Value); | return _map.FromKey(reader.Value); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, T value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, T value, string key) | |||||
{ | { | ||||
string strVal = _map.ToUtf16Key(value); | string strVal = _map.ToUtf16Key(value); | ||||
if (key != null) | if (key != null) | ||||
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters | |||||
_innerConverter = innerConverter; | _innerConverter = innerConverter; | ||||
} | } | ||||
public override T[] Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override T[] Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if ((isTopLevel && !reader.Read()) || reader.TokenType != JsonTokenType.StartArray) | if ((isTopLevel && !reader.Read()) || reader.TokenType != JsonTokenType.StartArray) | ||||
throw new SerializationException("Bad input, expected StartArray"); | throw new SerializationException("Bad input, expected StartArray"); | ||||
@@ -22,19 +22,19 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
if (reader.TokenType == JsonTokenType.EndArray) | if (reader.TokenType == JsonTokenType.EndArray) | ||||
return list.ToArray(); | return list.ToArray(); | ||||
list.Add(_innerConverter.Read(map, model, ref reader, false)); | |||||
list.Add(_innerConverter.Read(serializer, modelMap, propMap, model, ref reader, false)); | |||||
} | } | ||||
throw new SerializationException("Bad input, expected EndArray"); | throw new SerializationException("Bad input, expected EndArray"); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, T[] value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, T[] value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteArrayStart(key); | writer.WriteArrayStart(key); | ||||
else | else | ||||
writer.WriteArrayStart(); | writer.WriteArrayStart(); | ||||
for (int i = 0; i < value.Length; i++) | for (int i = 0; i < value.Length; i++) | ||||
_innerConverter.Write(map, model, ref writer, value[i], null); | |||||
_innerConverter.Write(serializer, modelMap, propMap, model, ref writer, value[i], null); | |||||
writer.WriteArrayEnd(); | writer.WriteArrayEnd(); | ||||
} | } | ||||
} | } | ||||
@@ -48,7 +48,7 @@ namespace Discord.Serialization.Json.Converters | |||||
_innerConverter = innerConverter; | _innerConverter = innerConverter; | ||||
} | } | ||||
public override List<T> Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override List<T> Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if ((isTopLevel && !reader.Read()) || reader.TokenType != JsonTokenType.StartArray) | if ((isTopLevel && !reader.Read()) || reader.TokenType != JsonTokenType.StartArray) | ||||
throw new SerializationException("Bad input, expected StartArray"); | throw new SerializationException("Bad input, expected StartArray"); | ||||
@@ -58,19 +58,19 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
if (reader.TokenType == JsonTokenType.EndArray) | if (reader.TokenType == JsonTokenType.EndArray) | ||||
return list; | return list; | ||||
list.Add(_innerConverter.Read(map, model, ref reader, false)); | |||||
list.Add(_innerConverter.Read(serializer, modelMap, propMap, model, ref reader, false)); | |||||
} | } | ||||
throw new SerializationException("Bad input, expected EndArray"); | throw new SerializationException("Bad input, expected EndArray"); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, List<T> value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, List<T> value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteArrayStart(key); | writer.WriteArrayStart(key); | ||||
else | else | ||||
writer.WriteArrayStart(); | writer.WriteArrayStart(); | ||||
for (int i = 0; i < value.Count; i++) | for (int i = 0; i < value.Count; i++) | ||||
_innerConverter.Write(map, model, ref writer, value[i], null); | |||||
_innerConverter.Write(serializer, modelMap, propMap, model, ref writer, value[i], null); | |||||
writer.WriteArrayEnd(); | writer.WriteArrayEnd(); | ||||
} | } | ||||
} | } | ||||
@@ -12,19 +12,19 @@ namespace Discord.Serialization.Json.Converters | |||||
_innerConverter = innerConverter; | _innerConverter = innerConverter; | ||||
} | } | ||||
public override T? Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override T? Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
if (reader.ValueType == JsonValueType.Null) | if (reader.ValueType == JsonValueType.Null) | ||||
return null; | return null; | ||||
return _innerConverter.Read(map, model, ref reader, false); | |||||
return _innerConverter.Read(serializer, modelMap, propMap, model, ref reader, false); | |||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, T? value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, T? value, string key) | |||||
{ | { | ||||
if (value.HasValue) | if (value.HasValue) | ||||
_innerConverter.Write(map, model, ref writer, value.Value, key); | |||||
_innerConverter.Write(serializer, modelMap, propMap, model, ref writer, value.Value, key); | |||||
else | else | ||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
@@ -1,18 +1,19 @@ | |||||
using System.Text.Json; | |||||
using System; | |||||
using System.Text.Json; | |||||
namespace Discord.Serialization.Json.Converters | namespace Discord.Serialization.Json.Converters | ||||
{ | { | ||||
public class ObjectPropertyConverter<T> : JsonPropertyConverter<T> | public class ObjectPropertyConverter<T> : JsonPropertyConverter<T> | ||||
where T : class, new() | where T : class, new() | ||||
{ | { | ||||
private readonly ModelMap<T> _map; | |||||
private readonly ModelMap _map; | |||||
public ObjectPropertyConverter(Serializer serializer) | public ObjectPropertyConverter(Serializer serializer) | ||||
{ | { | ||||
_map = serializer.MapModel<T>(); | _map = serializer.MapModel<T>(); | ||||
} | } | ||||
public override T Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override T Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
var subModel = new T(); | var subModel = new T(); | ||||
@@ -30,13 +31,19 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected PropertyName"); | throw new SerializationException("Bad input, expected PropertyName"); | ||||
if (_map.TryGetProperty(reader.Value, out var property)) | if (_map.TryGetProperty(reader.Value, out var property)) | ||||
(property as IJsonPropertyMap<T>).Read(subModel, ref reader); | |||||
{ | |||||
try { (property as IJsonPropertyMap<T>).Read(serializer, subModel, ref reader); } | |||||
catch (Exception ex) { RaiseModelError(serializer, property, ex); } | |||||
} | |||||
else | else | ||||
{ | |||||
RaiseUnmappedProperty(serializer, _map, reader.Value); | |||||
JsonReaderUtils.Skip(ref reader); //Unknown property, skip | JsonReaderUtils.Skip(ref reader); //Unknown property, skip | ||||
} | |||||
} | } | ||||
throw new SerializationException("Bad input, expected EndObject"); | throw new SerializationException("Bad input, expected EndObject"); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, T value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, T value, string key) | |||||
{ | { | ||||
if (value == null) | if (value == null) | ||||
{ | { | ||||
@@ -51,8 +58,8 @@ namespace Discord.Serialization.Json.Converters | |||||
writer.WriteObjectStart(key); | writer.WriteObjectStart(key); | ||||
else | else | ||||
writer.WriteObjectStart(); | writer.WriteObjectStart(); | ||||
for (int i = 0; i < _map.Properties.Length; i++) | |||||
(_map.Properties[i] as IJsonPropertyMap<T>).Write(value, ref writer); | |||||
for (int i = 0; i < _map.Properties.Count; i++) | |||||
(_map.Properties[i] as IJsonPropertyMap<T>).Write(serializer, value, ref writer); | |||||
writer.WriteObjectEnd(); | writer.WriteObjectEnd(); | ||||
} | } | ||||
} | } | ||||
@@ -5,7 +5,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
public class DateTimePropertyConverter : JsonPropertyConverter<DateTime> | public class DateTimePropertyConverter : JsonPropertyConverter<DateTime> | ||||
{ | { | ||||
public override DateTime Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override DateTime Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -13,7 +13,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected String"); | throw new SerializationException("Bad input, expected String"); | ||||
return reader.ParseDateTime(); | return reader.ParseDateTime(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, DateTime value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, DateTime value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -24,7 +24,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class DateTimeOffsetPropertyConverter : JsonPropertyConverter<DateTimeOffset> | public class DateTimeOffsetPropertyConverter : JsonPropertyConverter<DateTimeOffset> | ||||
{ | { | ||||
public override DateTimeOffset Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override DateTimeOffset Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -32,7 +32,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected String"); | throw new SerializationException("Bad input, expected String"); | ||||
return reader.ParseDateTimeOffset(); | return reader.ParseDateTimeOffset(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, DateTimeOffset value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, DateTimeOffset value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
public class SinglePropertyConverter : JsonPropertyConverter<float> | public class SinglePropertyConverter : JsonPropertyConverter<float> | ||||
{ | { | ||||
public override float Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override float Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseSingle(); | return reader.ParseSingle(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, float value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, float value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value.ToString()); | writer.WriteAttribute(key, value.ToString()); | ||||
@@ -23,7 +23,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class DoublePropertyConverter : JsonPropertyConverter<double> | public class DoublePropertyConverter : JsonPropertyConverter<double> | ||||
{ | { | ||||
public override double Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override double Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -31,7 +31,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseDouble(); | return reader.ParseDouble(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, double value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, double value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value.ToString()); | writer.WriteAttribute(key, value.ToString()); | ||||
@@ -42,7 +42,7 @@ namespace Discord.Serialization.Json.Converters | |||||
internal class DecimalPropertyConverter : JsonPropertyConverter<decimal> | internal class DecimalPropertyConverter : JsonPropertyConverter<decimal> | ||||
{ | { | ||||
public override decimal Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override decimal Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -50,7 +50,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseDecimal(); | return reader.ParseDecimal(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, decimal value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, decimal value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value.ToString()); | writer.WriteAttribute(key, value.ToString()); | ||||
@@ -5,7 +5,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
public class BooleanPropertyConverter : JsonPropertyConverter<bool> | public class BooleanPropertyConverter : JsonPropertyConverter<bool> | ||||
{ | { | ||||
public override bool Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override bool Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -16,7 +16,7 @@ namespace Discord.Serialization.Json.Converters | |||||
default: throw new SerializationException("Bad input, expected False or True"); | default: throw new SerializationException("Bad input, expected False or True"); | ||||
} | } | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, bool value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, bool value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -27,7 +27,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class GuidPropertyConverter : JsonPropertyConverter<Guid> | public class GuidPropertyConverter : JsonPropertyConverter<Guid> | ||||
{ | { | ||||
public override Guid Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override Guid Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -35,7 +35,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected String"); | throw new SerializationException("Bad input, expected String"); | ||||
return reader.ParseGuid(); | return reader.ParseGuid(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, Guid value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, Guid value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value.ToString()); | writer.WriteAttribute(key, value.ToString()); | ||||
@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
public class Int8PropertyConverter : JsonPropertyConverter<sbyte> | public class Int8PropertyConverter : JsonPropertyConverter<sbyte> | ||||
{ | { | ||||
public override sbyte Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override sbyte Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseInt8(); | return reader.ParseInt8(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, sbyte value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, sbyte value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -23,7 +23,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class Int16PropertyConverter : JsonPropertyConverter<short> | public class Int16PropertyConverter : JsonPropertyConverter<short> | ||||
{ | { | ||||
public override short Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override short Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -31,7 +31,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseInt16(); | return reader.ParseInt16(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, short value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, short value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -42,7 +42,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class Int32PropertyConverter : JsonPropertyConverter<int> | public class Int32PropertyConverter : JsonPropertyConverter<int> | ||||
{ | { | ||||
public override int Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override int Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -50,7 +50,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseInt32(); | return reader.ParseInt32(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, int value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, int value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -61,7 +61,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class Int64PropertyConverter : JsonPropertyConverter<long> | public class Int64PropertyConverter : JsonPropertyConverter<long> | ||||
{ | { | ||||
public override long Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override long Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -69,7 +69,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseInt64(); | return reader.ParseInt64(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, long value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, long value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value.ToString()); | writer.WriteAttribute(key, value.ToString()); | ||||
@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
/*public class CharPropertyConverter : JsonPropertyConverter<char> | /*public class CharPropertyConverter : JsonPropertyConverter<char> | ||||
{ | { | ||||
public override char Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override char Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected String"); | throw new SerializationException("Bad input, expected String"); | ||||
return reader.ParseChar(); | return reader.ParseChar(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, char value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, char value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -23,7 +23,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class StringPropertyConverter : JsonPropertyConverter<string> | public class StringPropertyConverter : JsonPropertyConverter<string> | ||||
{ | { | ||||
public override string Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override string Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -33,7 +33,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected String"); | throw new SerializationException("Bad input, expected String"); | ||||
return reader.ParseString(); | return reader.ParseString(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, string value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, string value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters | |||||
{ | { | ||||
public class UInt8PropertyConverter : JsonPropertyConverter<byte> | public class UInt8PropertyConverter : JsonPropertyConverter<byte> | ||||
{ | { | ||||
public override byte Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override byte Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseUInt8(); | return reader.ParseUInt8(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, byte value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, byte value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -23,7 +23,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class UInt16PropertyConverter : JsonPropertyConverter<ushort> | public class UInt16PropertyConverter : JsonPropertyConverter<ushort> | ||||
{ | { | ||||
public override ushort Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override ushort Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -31,7 +31,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseUInt16(); | return reader.ParseUInt16(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, ushort value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, ushort value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -42,7 +42,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class UInt32PropertyConverter : JsonPropertyConverter<uint> | public class UInt32PropertyConverter : JsonPropertyConverter<uint> | ||||
{ | { | ||||
public override uint Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override uint Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -50,7 +50,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseUInt32(); | return reader.ParseUInt32(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, uint value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, uint value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value); | writer.WriteAttribute(key, value); | ||||
@@ -61,7 +61,7 @@ namespace Discord.Serialization.Json.Converters | |||||
public class UInt64PropertyConverter : JsonPropertyConverter<ulong> | public class UInt64PropertyConverter : JsonPropertyConverter<ulong> | ||||
{ | { | ||||
public override ulong Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public override ulong Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
if (isTopLevel) | if (isTopLevel) | ||||
reader.Read(); | reader.Read(); | ||||
@@ -69,7 +69,7 @@ namespace Discord.Serialization.Json.Converters | |||||
throw new SerializationException("Bad input, expected Number or String"); | throw new SerializationException("Bad input, expected Number or String"); | ||||
return reader.ParseUInt64(); | return reader.ParseUInt64(); | ||||
} | } | ||||
public override void Write(PropertyMap map, object model, ref JsonWriter writer, ulong value, string key) | |||||
public override void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, ulong value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteAttribute(key, value.ToString()); | writer.WriteAttribute(key, value.ToString()); | ||||
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters | |||||
_map = serializer.MapModel<T>(); | _map = serializer.MapModel<T>(); | ||||
} | } | ||||
public T Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel) | |||||
public T Read(ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel) | |||||
{ | { | ||||
var subModel = new T(); | var subModel = new T(); | ||||
@@ -32,7 +32,7 @@ namespace Discord.Serialization.Json.Converters | |||||
} | } | ||||
throw new SerializationException("Bad input, expected EndObject"); | throw new SerializationException("Bad input, expected EndObject"); | ||||
} | } | ||||
public void Write(PropertyMap map, object model, ref JsonWriter writer, T value, string key) | |||||
public void Write(ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, T value, string key) | |||||
{ | { | ||||
if (key != null) | if (key != null) | ||||
writer.WriteObjectStart(key); | writer.WriteObjectStart(key); | ||||
@@ -1,26 +0,0 @@ | |||||
using System.Text.Json; | |||||
namespace Discord.Serialization.Json | |||||
{ | |||||
public abstract class JsonPropertyConverter<T> : IJsonPropertyReader<T>, IJsonPropertyWriter<T>, IJsonPropertyWriter | |||||
{ | |||||
public abstract T Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel); | |||||
public abstract void Write(PropertyMap map, object model, ref JsonWriter writer, T value, string key); | |||||
void IJsonPropertyWriter.Write(PropertyMap map, object model, ref JsonWriter writer, object value, string key) | |||||
=> Write(map, model, ref writer, (T)value, key); | |||||
} | |||||
public interface IJsonPropertyReader<out T> | |||||
{ | |||||
T Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel); | |||||
} | |||||
public interface IJsonPropertyWriter<in T> | |||||
{ | |||||
void Write(PropertyMap map, object model, ref JsonWriter writer, T value, string key); | |||||
} | |||||
public interface IJsonPropertyWriter | |||||
{ | |||||
void Write(PropertyMap map, object model, ref JsonWriter writer, object value, string key); | |||||
} | |||||
} |
@@ -0,0 +1,34 @@ | |||||
using System; | |||||
using System.Text.Json; | |||||
namespace Discord.Serialization.Json | |||||
{ | |||||
public abstract class JsonPropertyConverter<T> : IJsonPropertyReader<T>, IJsonPropertyWriter<T>, IJsonPropertyWriter | |||||
{ | |||||
public abstract T Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel); | |||||
public abstract void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, T value, string key); | |||||
void IJsonPropertyWriter.Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, object value, string key) | |||||
=> Write(serializer, modelMap, propMap, model, ref writer, (T)value, key); | |||||
protected void RaiseUnmappedProperty(Serializer serializer, ModelMap modelMap, ReadOnlyBuffer<byte> propertyKey) | |||||
=> serializer.RaiseUnknownProperty(modelMap.Path, propertyKey); | |||||
protected void RaiseUnmappedProperty(Serializer serializer, ModelMap modelMap, ReadOnlySpan<byte> propertyKey) | |||||
=> serializer.RaiseUnknownProperty(modelMap.Path, propertyKey); | |||||
protected void RaiseModelError(Serializer serializer, PropertyMap propMap, Exception ex) | |||||
=> serializer.RaiseModelError(propMap.Path, ex); | |||||
} | |||||
public interface IJsonPropertyReader<out T> | |||||
{ | |||||
T Read(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonReader reader, bool isTopLevel); | |||||
} | |||||
public interface IJsonPropertyWriter<in T> | |||||
{ | |||||
void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, T value, string key); | |||||
} | |||||
public interface IJsonPropertyWriter | |||||
{ | |||||
void Write(Serializer serializer, ModelMap modelMap, PropertyMap propMap, object model, ref JsonWriter writer, object value, string key); | |||||
} | |||||
} |
@@ -9,36 +9,38 @@ namespace Discord.Serialization.Json | |||||
string Key { get; } | string Key { get; } | ||||
ReadOnlyBuffer<byte> Utf8Key { get; } | ReadOnlyBuffer<byte> Utf8Key { get; } | ||||
void Write(TModel model, ref JsonWriter writer); | |||||
void Read(TModel model, ref JsonReader reader); | |||||
void Write(Serializer serializer, TModel model, ref JsonWriter writer); | |||||
void Read(Serializer serializer, TModel model, ref JsonReader reader); | |||||
} | } | ||||
internal class JsonPropertyMap<TModel, TValue> : PropertyMap<TModel, TValue>, IJsonPropertyMap<TModel> | internal class JsonPropertyMap<TModel, TValue> : PropertyMap<TModel, TValue>, IJsonPropertyMap<TModel> | ||||
{ | { | ||||
private readonly ModelMap _modelMap; | |||||
private readonly JsonPropertyConverter<TValue> _converter; | private readonly JsonPropertyConverter<TValue> _converter; | ||||
private readonly Func<TModel, TValue> _getFunc; | private readonly Func<TModel, TValue> _getFunc; | ||||
private readonly Action<TModel, TValue> _setFunc; | private readonly Action<TModel, TValue> _setFunc; | ||||
public JsonPropertyMap(Serializer serializer, PropertyInfo propInfo, JsonPropertyConverter<TValue> converter) | |||||
: base(serializer, propInfo) | |||||
public JsonPropertyMap(Serializer serializer, ModelMap modelMap, PropertyInfo propInfo, JsonPropertyConverter<TValue> converter) | |||||
: base(serializer, modelMap, propInfo) | |||||
{ | { | ||||
_modelMap = modelMap; | |||||
_converter = converter; | _converter = converter; | ||||
_getFunc = propInfo.GetMethod.CreateDelegate(typeof(Func<TModel, TValue>)) as Func<TModel, TValue>; | _getFunc = propInfo.GetMethod.CreateDelegate(typeof(Func<TModel, TValue>)) as Func<TModel, TValue>; | ||||
_setFunc = propInfo.SetMethod.CreateDelegate(typeof(Action<TModel, TValue>)) as Action<TModel, TValue>; | _setFunc = propInfo.SetMethod.CreateDelegate(typeof(Action<TModel, TValue>)) as Action<TModel, TValue>; | ||||
} | } | ||||
public void Read(TModel model, ref JsonReader reader) | |||||
public void Read(Serializer serializer, TModel model, ref JsonReader reader) | |||||
{ | { | ||||
var value = _converter.Read(this, model, ref reader, true); | |||||
var value = _converter.Read(serializer, _modelMap, this, model, ref reader, true); | |||||
_setFunc(model, value); | _setFunc(model, value); | ||||
} | } | ||||
public void Write(TModel model, ref JsonWriter writer) | |||||
public void Write(Serializer serializer, TModel model, ref JsonWriter writer) | |||||
{ | { | ||||
var value = _getFunc(model); | var value = _getFunc(model); | ||||
if (value == null && ExcludeNull) | if (value == null && ExcludeNull) | ||||
return; | return; | ||||
_converter.Write(this, model, ref writer, value, Key); | |||||
_converter.Write(serializer, _modelMap, this, model, ref writer, value, Key); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -18,10 +18,10 @@ namespace Discord.Serialization.Json | |||||
where TConverter : JsonPropertyConverter<TValue> | where TConverter : JsonPropertyConverter<TValue> | ||||
=> AddConverter(typeof(TValue), typeof(TConverter), condition); | => AddConverter(typeof(TValue), typeof(TConverter), condition); | ||||
protected override PropertyMap CreatePropertyMap<TModel, TValue>(PropertyInfo propInfo) | |||||
protected override PropertyMap CreatePropertyMap<TModel, TValue>(ModelMap modelMap, PropertyInfo propInfo) | |||||
{ | { | ||||
var converter = (JsonPropertyConverter<TValue>)GetConverter(typeof(TValue), propInfo); | var converter = (JsonPropertyConverter<TValue>)GetConverter(typeof(TValue), propInfo); | ||||
return new JsonPropertyMap<TModel, TValue>(this, propInfo, converter); | |||||
return new JsonPropertyMap<TModel, TValue>(this, modelMap, propInfo, converter); | |||||
} | } | ||||
public TModel Read<TModel>(Utf8String str) | public TModel Read<TModel>(Utf8String str) | ||||
@@ -32,14 +32,16 @@ namespace Discord.Serialization.Json | |||||
if (!reader.Read()) | if (!reader.Read()) | ||||
return default; | return default; | ||||
var converter = GetConverter(typeof(TModel)) as JsonPropertyConverter<TModel>; | var converter = GetConverter(typeof(TModel)) as JsonPropertyConverter<TModel>; | ||||
return converter.Read(null, null, ref reader, false); | |||||
//Don't wrap this. We should throw an exception if we cant create the model. | |||||
return converter.Read(this, null, null, null, ref reader, false); | |||||
} | } | ||||
public override void Write<TModel>(ArrayFormatter stream, TModel model) | public override void Write<TModel>(ArrayFormatter stream, TModel model) | ||||
{ | { | ||||
var writer = new JsonWriter(stream); | var writer = new JsonWriter(stream); | ||||
var converter = GetConverter(typeof(TModel)) as JsonPropertyConverter<TModel>; | var converter = GetConverter(typeof(TModel)) as JsonPropertyConverter<TModel>; | ||||
converter.Write(null, null, ref writer, model, null); | |||||
//Don't wrap this, always throw exceptions on Write. | |||||
converter.Write(this, null, null, null, ref writer, model, null); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,22 +1,28 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | |||||
using System.Reflection; | |||||
namespace Discord.Serialization | namespace Discord.Serialization | ||||
{ | { | ||||
public class ModelMap<TModel> | |||||
where TModel : class, new() | |||||
public class ModelMap | |||||
{ | { | ||||
private BufferDictionary<PropertyMap> _propDict; | |||||
private readonly List<PropertyMap> _propList; | |||||
private readonly BufferDictionary<PropertyMap> _propDict; | |||||
public string Path { get; } | |||||
public bool HasDynamics { get; } | public bool HasDynamics { get; } | ||||
public PropertyMap[] Properties { get; } | |||||
public IReadOnlyList<PropertyMap> Properties => _propList; | |||||
public ModelMap(Serializer serializer, TypeInfo type, List<PropertyMap> properties) | |||||
internal ModelMap(string path) | |||||
{ | { | ||||
Properties = properties.ToArray(); | |||||
_propDict = new BufferDictionary<PropertyMap>(properties.ToDictionary(x => x.Utf8Key)); | |||||
Path = path; | |||||
_propList = new List<PropertyMap>(); | |||||
_propDict = new BufferDictionary<PropertyMap>(); | |||||
} | |||||
internal void AddProperty(PropertyMap propMap) | |||||
{ | |||||
_propList.Add(propMap); | |||||
_propDict.Add(propMap.Utf8Key, propMap); | |||||
} | } | ||||
public bool TryGetProperty(ReadOnlyBuffer<byte> key, out PropertyMap value) | public bool TryGetProperty(ReadOnlyBuffer<byte> key, out PropertyMap value) | ||||
@@ -11,18 +11,19 @@ namespace Discord.Serialization | |||||
public string Key { get; } | public string Key { get; } | ||||
public ReadOnlyBuffer<byte> Utf8Key { get; } | public ReadOnlyBuffer<byte> Utf8Key { get; } | ||||
public string Name { get; } | public string Name { get; } | ||||
public string Path { get; } | |||||
public bool ExcludeNull { get; } | public bool ExcludeNull { get; } | ||||
public PropertyMap(Serializer serializer, PropertyInfo propInfo) | |||||
internal PropertyMap(Serializer serializer, PropertyInfo propInfo, ModelMap modelMap) | |||||
{ | { | ||||
Name = propInfo.Name; | Name = propInfo.Name; | ||||
Path = $"{modelMap.Path}.{propInfo.Name}"; | |||||
var attr = propInfo.GetCustomAttribute<ModelPropertyAttribute>(); | var attr = propInfo.GetCustomAttribute<ModelPropertyAttribute>(); | ||||
Key = attr.Key ?? propInfo.Name; | Key = attr.Key ?? propInfo.Name; | ||||
Utf8Key = new ReadOnlyBuffer<byte>(new Utf8String(Key).Bytes.ToArray()); | Utf8Key = new ReadOnlyBuffer<byte>(new Utf8String(Key).Bytes.ToArray()); | ||||
ExcludeNull = attr.ExcludeNull; | ExcludeNull = attr.ExcludeNull; | ||||
} | } | ||||
public abstract object GetDynamicConverter(object model, bool throwOnMissing); | public abstract object GetDynamicConverter(object model, bool throwOnMissing); | ||||
@@ -54,11 +55,10 @@ namespace Discord.Serialization | |||||
=> _group?.GetDynamicConverter(_getWrappedSelectorFunc, model); | => _group?.GetDynamicConverter(_getWrappedSelectorFunc, model); | ||||
} | } | ||||
private readonly Delegate _getSelectorFunc, _getWrappedSelectorFunc; | |||||
private readonly IReadOnlyList<Selector> _selectors; | private readonly IReadOnlyList<Selector> _selectors; | ||||
public PropertyMap(Serializer serializer, PropertyInfo propInfo) | |||||
: base(serializer, propInfo) | |||||
internal PropertyMap(Serializer serializer, ModelMap modelMap, PropertyInfo propInfo) | |||||
: base(serializer, propInfo, modelMap) | |||||
{ | { | ||||
_selectors = propInfo.GetCustomAttributes<ModelSelectorAttribute>() | _selectors = propInfo.GetCustomAttributes<ModelSelectorAttribute>() | ||||
.Select(x => | .Select(x => | ||||
@@ -4,18 +4,21 @@ using System.Collections.Generic; | |||||
using System.Linq; | using System.Linq; | ||||
using System.Reflection; | using System.Reflection; | ||||
using System.Text.Formatting; | using System.Text.Formatting; | ||||
using System.Text.Utf8; | |||||
namespace Discord.Serialization | namespace Discord.Serialization | ||||
{ | { | ||||
public abstract class Serializer | public abstract class Serializer | ||||
{ | { | ||||
public event Action<Exception> Error; //TODO: Impl | |||||
public event Action<string, Exception> ModelError; | |||||
public event Action<string> UnmappedProperty; | |||||
private static readonly MethodInfo _createPropertyMapMethod | private static readonly MethodInfo _createPropertyMapMethod | ||||
= typeof(Serializer).GetTypeInfo().GetDeclaredMethod(nameof(CreatePropertyMap)); | = typeof(Serializer).GetTypeInfo().GetDeclaredMethod(nameof(CreatePropertyMap)); | ||||
private readonly ConcurrentDictionary<Type, object> _maps; | private readonly ConcurrentDictionary<Type, object> _maps; | ||||
private readonly ConverterCollection _converters; | private readonly ConverterCollection _converters; | ||||
private readonly ConcurrentHashSet<string> _unknownProps = new ConcurrentHashSet<string>(); | |||||
protected Serializer() | protected Serializer() | ||||
: this(null) { } | : this(null) { } | ||||
@@ -50,16 +53,18 @@ namespace Discord.Serialization | |||||
public ISelectorGroup GetSelectorGroup(Type keyType, string groupKey) | public ISelectorGroup GetSelectorGroup(Type keyType, string groupKey) | ||||
=> _converters.GetSelectorGroup(keyType, groupKey); | => _converters.GetSelectorGroup(keyType, groupKey); | ||||
protected internal ModelMap<TModel> MapModel<TModel>() | |||||
where TModel : class, new() | |||||
protected internal ModelMap MapModel<TModel>() | |||||
{ | { | ||||
return _maps.GetOrAdd(typeof(TModel), _ => | return _maps.GetOrAdd(typeof(TModel), _ => | ||||
{ | { | ||||
var type = typeof(TModel).GetTypeInfo(); | var type = typeof(TModel).GetTypeInfo(); | ||||
var searchType = type; | |||||
var properties = new List<PropertyMap>(); | var properties = new List<PropertyMap>(); | ||||
while (type != null) | |||||
var map = new ModelMap(type.Name); | |||||
while (searchType != null) | |||||
{ | { | ||||
var propInfos = type.DeclaredProperties | |||||
var propInfos = searchType.DeclaredProperties | |||||
.Where(x => x.CanRead && x.CanWrite) | .Where(x => x.CanRead && x.CanWrite) | ||||
.ToArray(); | .ToArray(); | ||||
@@ -67,24 +72,68 @@ namespace Discord.Serialization | |||||
{ | { | ||||
if (propInfos[i].GetCustomAttribute<ModelPropertyAttribute>() != null) | if (propInfos[i].GetCustomAttribute<ModelPropertyAttribute>() != null) | ||||
{ | { | ||||
var propMap = MapProperty<TModel>(propInfos[i]); | |||||
properties.Add(propMap); | |||||
var propMap = MapProperty<TModel>(map, propInfos[i]); | |||||
map.AddProperty(propMap); | |||||
} | } | ||||
} | } | ||||
type = type.BaseType?.GetTypeInfo(); | |||||
searchType = searchType.BaseType?.GetTypeInfo(); | |||||
} | } | ||||
return new ModelMap<TModel>(this, type, properties); | |||||
}) as ModelMap<TModel>; | |||||
return map; | |||||
}) as ModelMap; | |||||
} | } | ||||
private PropertyMap MapProperty<TModel>(PropertyInfo propInfo) | |||||
=> _createPropertyMapMethod.MakeGenericMethod(typeof(TModel), propInfo.PropertyType).Invoke(this, new object[] { propInfo }) as PropertyMap; | |||||
protected abstract PropertyMap CreatePropertyMap<TModel, TValue>(PropertyInfo propInfo); | |||||
private PropertyMap MapProperty<TModel>(ModelMap modelMap, PropertyInfo propInfo) | |||||
=> _createPropertyMapMethod.MakeGenericMethod(typeof(TModel), propInfo.PropertyType).Invoke(this, new object[] { modelMap, propInfo }) as PropertyMap; | |||||
protected abstract PropertyMap CreatePropertyMap<TModel, TValue>(ModelMap modelMap, PropertyInfo propInfo); | |||||
public TModel Read<TModel>(ReadOnlyBuffer<byte> data) | public TModel Read<TModel>(ReadOnlyBuffer<byte> data) | ||||
=> Read<TModel>(data.Span); | => Read<TModel>(data.Span); | ||||
public abstract TModel Read<TModel>(ReadOnlySpan<byte> data); | public abstract TModel Read<TModel>(ReadOnlySpan<byte> data); | ||||
public abstract void Write<TModel>(ArrayFormatter stream, TModel model); | public abstract void Write<TModel>(ArrayFormatter stream, TModel model); | ||||
internal void RaiseModelError(string path, Exception ex) | |||||
{ | |||||
if (ModelError != null) | |||||
ModelError?.Invoke(path, ex); | |||||
} | |||||
internal void RaiseModelError(ModelMap modelMap, Exception ex) | |||||
{ | |||||
if (ModelError != null) | |||||
ModelError?.Invoke(modelMap.Path, ex); | |||||
} | |||||
internal void RaiseModelError(PropertyMap propMap, Exception ex) | |||||
{ | |||||
if (ModelError != null) | |||||
ModelError?.Invoke(propMap.Path, ex); | |||||
} | |||||
internal void RaiseUnmappedProperty(string model, string propertyMap) | |||||
{ | |||||
if (UnmappedProperty != null) | |||||
{ | |||||
string path = $"{model}.{propertyMap}"; | |||||
if (_unknownProps.TryAdd(path)) | |||||
UnmappedProperty?.Invoke(path); | |||||
} | |||||
} | |||||
internal void RaiseUnknownProperty(string model, ReadOnlyBuffer<byte> propertyMap) | |||||
{ | |||||
if (UnmappedProperty != null) | |||||
{ | |||||
string path = $"{model}.{new Utf8String(propertyMap.Span).ToString()}"; | |||||
if (_unknownProps.TryAdd(path)) | |||||
UnmappedProperty?.Invoke(path); | |||||
} | |||||
} | |||||
internal void RaiseUnknownProperty(string model, ReadOnlySpan<byte> propertyMap) | |||||
{ | |||||
if (UnmappedProperty != null) | |||||
{ | |||||
string path = $"{model}.{new Utf8String(propertyMap).ToString()}"; | |||||
if (_unknownProps.TryAdd(path)) | |||||
UnmappedProperty?.Invoke(path); | |||||
} | |||||
} | |||||
} | } | ||||
} | } |
@@ -68,10 +68,16 @@ namespace Discord.Audio | |||||
_audioLogger = Discord.LogManager.CreateLogger($"Audio #{clientId}"); | _audioLogger = Discord.LogManager.CreateLogger($"Audio #{clientId}"); | ||||
_serializer = DiscordVoiceJsonSerializer.Global.CreateScope(); | _serializer = DiscordVoiceJsonSerializer.Global.CreateScope(); | ||||
_serializer.Error += ex => | |||||
if (Discord.LogManager.Level >= LogSeverity.Warning) | |||||
{ | { | ||||
_audioLogger.WarningAsync("Serializer Error", ex).GetAwaiter().GetResult(); | |||||
}; | |||||
_serializer.ModelError += (path, ex) | |||||
=> _audioLogger.WarningAsync($"Failed to deserialize {path}", ex).GetAwaiter().GetResult(); | |||||
} | |||||
if (Discord.LogManager.Level >= LogSeverity.Debug) | |||||
{ | |||||
_serializer.UnmappedProperty += path | |||||
=> _audioLogger.DebugAsync($"Unmapped property: {path}"); | |||||
} | |||||
ApiClient = new DiscordVoiceApiClient(guild.Id, Discord.WebSocketProvider, Discord.UdpSocketProvider, _serializer); | ApiClient = new DiscordVoiceApiClient(guild.Id, Discord.WebSocketProvider, Discord.UdpSocketProvider, _serializer); | ||||
ApiClient.SentGatewayMessage += async opCode => await _audioLogger.DebugAsync($"Sent {opCode}").ConfigureAwait(false); | ApiClient.SentGatewayMessage += async opCode => await _audioLogger.DebugAsync($"Sent {opCode}").ConfigureAwait(false); | ||||
@@ -56,10 +56,16 @@ namespace Discord.WebSocket | |||||
_connectionGroupLock = new SemaphoreSlim(1, 1); | _connectionGroupLock = new SemaphoreSlim(1, 1); | ||||
_serializer = DiscordSocketJsonSerializer.Global.CreateScope(); | _serializer = DiscordSocketJsonSerializer.Global.CreateScope(); | ||||
_serializer.Error += ex => | |||||
if (config.LogLevel >= LogSeverity.Warning) | |||||
{ | { | ||||
_restLogger.WarningAsync("Serializer Error", ex).GetAwaiter().GetResult(); | |||||
}; | |||||
_serializer.ModelError += (path, ex) | |||||
=> _restLogger.WarningAsync($"Failed to deserialize {path}", ex).GetAwaiter().GetResult(); | |||||
} | |||||
if (config.LogLevel >= LogSeverity.Debug) | |||||
{ | |||||
_serializer.UnmappedProperty += path | |||||
=> _restLogger.DebugAsync($"Unmapped property: {path}"); | |||||
} | |||||
SetApiClient(new API.DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordConfig.UserAgent, _serializer)); | SetApiClient(new API.DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordConfig.UserAgent, _serializer)); | ||||
@@ -88,10 +88,16 @@ namespace Discord.WebSocket | |||||
_gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}"); | _gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}"); | ||||
_serializer = DiscordSocketJsonSerializer.Global.CreateScope(); | _serializer = DiscordSocketJsonSerializer.Global.CreateScope(); | ||||
_serializer.Error += ex => | |||||
if (config.LogLevel >= LogSeverity.Warning) | |||||
{ | { | ||||
_restLogger.WarningAsync("Serializer Error", ex).GetAwaiter().GetResult(); | |||||
}; | |||||
_serializer.ModelError += (path, ex) | |||||
=> _gatewayLogger.WarningAsync($"Failed to deserialize {path}", ex).GetAwaiter().GetResult(); | |||||
} | |||||
if (config.LogLevel >= LogSeverity.Debug) | |||||
{ | |||||
_serializer.UnmappedProperty += path | |||||
=> _gatewayLogger.DebugAsync($"Unmapped property: {path}"); | |||||
} | |||||
SetApiClient(new API.DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordConfig.UserAgent, _serializer, config.GatewayHost, config.DefaultRetryMode)); | SetApiClient(new API.DiscordSocketApiClient(config.RestClientProvider, config.WebSocketProvider, DiscordConfig.UserAgent, _serializer, config.GatewayHost, config.DefaultRetryMode)); | ||||