Browse Source

Added logging for deserialization errors and unknown properties

voice-allocs
RogueException 7 years ago
parent
commit
1e68b4a6fd
32 changed files with 315 additions and 165 deletions
  1. +9
    -3
      src/Discord.Net.Rest/DiscordRestClient.cs
  2. +4
    -4
      src/Discord.Net.Rest/Serialization/Json/Converters/EntityOrIdPropertyConverter.cs
  3. +2
    -2
      src/Discord.Net.Rest/Serialization/Json/Converters/ImagePropertyConverter.cs
  4. +2
    -2
      src/Discord.Net.Rest/Serialization/Json/Converters/Int53PropertyConverter.cs
  5. +4
    -4
      src/Discord.Net.Rest/Serialization/Json/Converters/OptionalPropertyConverter.cs
  6. +2
    -2
      src/Discord.Net.Rest/Serialization/Json/Converters/UInt53PropertyConverter.cs
  7. +49
    -1
      src/Discord.Net.Serialization/BufferDictionary.cs
  8. +3
    -2
      src/Discord.Net.Serialization/ConverterCollection.cs
  9. +3
    -0
      src/Discord.Net.Serialization/Discord.Net.Serialization.csproj
  10. +4
    -4
      src/Discord.Net.Serialization/Json/Converters/Dictionary.cs
  11. +6
    -6
      src/Discord.Net.Serialization/Json/Converters/Dynamic.cs
  12. +6
    -6
      src/Discord.Net.Serialization/Json/Converters/Enum.cs
  13. +8
    -8
      src/Discord.Net.Serialization/Json/Converters/List.cs
  14. +4
    -4
      src/Discord.Net.Serialization/Json/Converters/Nullable.cs
  15. +14
    -7
      src/Discord.Net.Serialization/Json/Converters/Object.cs
  16. +4
    -4
      src/Discord.Net.Serialization/Json/Converters/Primitives.DateTime.cs
  17. +6
    -6
      src/Discord.Net.Serialization/Json/Converters/Primitives.Float.cs
  18. +4
    -4
      src/Discord.Net.Serialization/Json/Converters/Primitives.Other.cs
  19. +8
    -8
      src/Discord.Net.Serialization/Json/Converters/Primitives.Signed.cs
  20. +4
    -4
      src/Discord.Net.Serialization/Json/Converters/Primitives.String.cs
  21. +8
    -8
      src/Discord.Net.Serialization/Json/Converters/Primitives.Unsigned.cs
  22. +2
    -2
      src/Discord.Net.Serialization/Json/Converters/Struct.cs
  23. +0
    -26
      src/Discord.Net.Serialization/Json/IJsonPropertyConverter.cs
  24. +34
    -0
      src/Discord.Net.Serialization/Json/JsonPropertyConverter.cs
  25. +10
    -8
      src/Discord.Net.Serialization/Json/JsonPropertyMap.cs
  26. +6
    -4
      src/Discord.Net.Serialization/Json/JsonSerializer.cs
  27. +15
    -9
      src/Discord.Net.Serialization/ModelMap.cs
  28. +5
    -5
      src/Discord.Net.Serialization/PropertyMap.cs
  29. +62
    -13
      src/Discord.Net.Serialization/Serializer.cs
  30. +9
    -3
      src/Discord.Net.WebSocket/Audio/AudioClient.cs
  31. +9
    -3
      src/Discord.Net.WebSocket/DiscordShardedClient.cs
  32. +9
    -3
      src/Discord.Net.WebSocket/DiscordSocketClient.cs

+ 9
- 3
src/Discord.Net.Rest/DiscordRestClient.cs View File

@@ -18,10 +18,16 @@ namespace Discord.Rest
public DiscordRestClient(DiscordRestConfig config) : base(config)
{
_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));
}


+ 4
- 4
src/Discord.Net.Rest/Serialization/Json/Converters/EntityOrIdPropertyConverter.cs View File

@@ -12,19 +12,19 @@ namespace Discord.Serialization.Json.Converters
_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)
reader.Read();
if (reader.ValueType == JsonValueType.Number)
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)
_innerConverter.Write(map, model, ref writer, value.Object, key);
_innerConverter.Write(serializer, modelMap, propMap, model, ref writer, value.Object, key);
else
{
if (key != null)


+ 2
- 2
src/Discord.Net.Rest/Serialization/Json/Converters/ImagePropertyConverter.cs View File

@@ -5,7 +5,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -13,7 +13,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected String");
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;
if (value.Stream != null)


+ 2
- 2
src/Discord.Net.Rest/Serialization/Json/Converters/Int53PropertyConverter.cs View File

@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number");
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)
writer.WriteAttribute(key, value);


+ 4
- 4
src/Discord.Net.Rest/Serialization/Json/Converters/OptionalPropertyConverter.cs View File

@@ -11,13 +11,13 @@ namespace Discord.Serialization.Json.Converters
_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)
_innerConverter.Write(map, model, ref writer, value.Value, key);
_innerConverter.Write(serializer, modelMap, propMap, model, ref writer, value.Value, key);
}
}
}

+ 2
- 2
src/Discord.Net.Rest/Serialization/Json/Converters/UInt53PropertyConverter.cs View File

@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number");
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)
writer.WriteAttribute(key, value);


+ 49
- 1
src/Discord.Net.Serialization/BufferDictionary.cs View File

@@ -42,13 +42,24 @@ namespace Discord.Serialization

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 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))
throw new ArgumentException("Duplicate key", nameof(key));
return false;
}
int index;
if (_freeCount > 0)
@@ -73,6 +84,43 @@ namespace Discord.Serialization
_entries[index].key = key;
_entries[index].value = value;
_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()
{


+ 3
- 2
src/Discord.Net.Serialization/ConverterCollection.cs View File

@@ -94,13 +94,13 @@ namespace Discord.Serialization
public void AddSelector(Serializer serializer, string groupKey, Type keyType, object keyValue, Type converterType)
{
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)
{
//Check parent
object converter = _parent?.Get(serializer, type, propInfo, false);
var converter = _parent?.Get(serializer, type, propInfo, false);
if (converter != null)
return converter;

@@ -190,6 +190,7 @@ namespace Discord.Serialization
else
throw new SerializationException($"{converterType.Name} has an unsupported constructor");
}

return constructor.Invoke(args);
}



+ 3
- 0
src/Discord.Net.Serialization/Discord.Net.Serialization.csproj View File

@@ -8,6 +8,9 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<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.Collections.Immutable" Version="1.4.0" />
<PackageReference Include="System.Interactive.Async" Version="3.1.1" />


+ 4
- 4
src/Discord.Net.Serialization/Json/Converters/Dictionary.cs View File

@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters
_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)
throw new SerializationException("Bad input, expected StartObject");
@@ -26,20 +26,20 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected PropertyName");

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);
}
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)
writer.WriteObjectStart(key);
else
writer.WriteObjectStart();
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();
}
}


+ 6
- 6
src/Discord.Net.Serialization/Json/Converters/Dynamic.cs View File

@@ -5,10 +5,10 @@ namespace Discord.Serialization.Json.Converters
//TODO: Only supports cases where the key arrives first
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
{
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)
{
@@ -27,8 +27,8 @@ namespace Discord.Serialization.Json.Converters
}
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);
}
}
}


+ 6
- 6
src/Discord.Net.Serialization/Json/Converters/Enum.cs View File

@@ -7,7 +7,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -15,7 +15,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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);
if (key != null)
@@ -30,7 +30,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -38,7 +38,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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);
if (key != null)
@@ -53,7 +53,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -61,7 +61,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected String");
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);
if (key != null)


+ 8
- 8
src/Discord.Net.Serialization/Json/Converters/List.cs View File

@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters
_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)
throw new SerializationException("Bad input, expected StartArray");
@@ -22,19 +22,19 @@ namespace Discord.Serialization.Json.Converters
{
if (reader.TokenType == JsonTokenType.EndArray)
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");
}

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)
writer.WriteArrayStart(key);
else
writer.WriteArrayStart();
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();
}
}
@@ -48,7 +48,7 @@ namespace Discord.Serialization.Json.Converters
_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)
throw new SerializationException("Bad input, expected StartArray");
@@ -58,19 +58,19 @@ namespace Discord.Serialization.Json.Converters
{
if (reader.TokenType == JsonTokenType.EndArray)
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");
}

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)
writer.WriteArrayStart(key);
else
writer.WriteArrayStart();
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();
}
}


+ 4
- 4
src/Discord.Net.Serialization/Json/Converters/Nullable.cs View File

@@ -12,19 +12,19 @@ namespace Discord.Serialization.Json.Converters
_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();
if (reader.ValueType == JsonValueType.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)
_innerConverter.Write(map, model, ref writer, value.Value, key);
_innerConverter.Write(serializer, modelMap, propMap, model, ref writer, value.Value, key);
else
{
if (key != null)


+ 14
- 7
src/Discord.Net.Serialization/Json/Converters/Object.cs View File

@@ -1,18 +1,19 @@
using System.Text.Json;
using System;
using System.Text.Json;

namespace Discord.Serialization.Json.Converters
{
public class ObjectPropertyConverter<T> : JsonPropertyConverter<T>
where T : class, new()
{
private readonly ModelMap<T> _map;
private readonly ModelMap _map;

public ObjectPropertyConverter(Serializer serializer)
{
_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();

@@ -30,13 +31,19 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected PropertyName");

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
{
RaiseUnmappedProperty(serializer, _map, reader.Value);
JsonReaderUtils.Skip(ref reader); //Unknown property, skip
}
}
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)
{
@@ -51,8 +58,8 @@ namespace Discord.Serialization.Json.Converters
writer.WriteObjectStart(key);
else
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();
}
}


+ 4
- 4
src/Discord.Net.Serialization/Json/Converters/Primitives.DateTime.cs View File

@@ -5,7 +5,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -13,7 +13,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected String");
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)
writer.WriteAttribute(key, value);
@@ -24,7 +24,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -32,7 +32,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected String");
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)
writer.WriteAttribute(key, value);


+ 6
- 6
src/Discord.Net.Serialization/Json/Converters/Primitives.Float.cs View File

@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value.ToString());
@@ -23,7 +23,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -31,7 +31,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value.ToString());
@@ -42,7 +42,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -50,7 +50,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value.ToString());


+ 4
- 4
src/Discord.Net.Serialization/Json/Converters/Primitives.Other.cs View File

@@ -5,7 +5,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -16,7 +16,7 @@ namespace Discord.Serialization.Json.Converters
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)
writer.WriteAttribute(key, value);
@@ -27,7 +27,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -35,7 +35,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected String");
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)
writer.WriteAttribute(key, value.ToString());


+ 8
- 8
src/Discord.Net.Serialization/Json/Converters/Primitives.Signed.cs View File

@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value);
@@ -23,7 +23,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -31,7 +31,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value);
@@ -42,7 +42,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -50,7 +50,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value);
@@ -61,7 +61,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -69,7 +69,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value.ToString());


+ 4
- 4
src/Discord.Net.Serialization/Json/Converters/Primitives.String.cs View File

@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters
{
/*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)
reader.Read();
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected String");
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)
writer.WriteAttribute(key, value);
@@ -23,7 +23,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -33,7 +33,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected String");
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)
writer.WriteAttribute(key, value);


+ 8
- 8
src/Discord.Net.Serialization/Json/Converters/Primitives.Unsigned.cs View File

@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters
{
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)
reader.Read();
@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value);
@@ -23,7 +23,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -31,7 +31,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value);
@@ -42,7 +42,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -50,7 +50,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value);
@@ -61,7 +61,7 @@ namespace Discord.Serialization.Json.Converters

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)
reader.Read();
@@ -69,7 +69,7 @@ namespace Discord.Serialization.Json.Converters
throw new SerializationException("Bad input, expected Number or String");
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)
writer.WriteAttribute(key, value.ToString());


+ 2
- 2
src/Discord.Net.Serialization/Json/Converters/Struct.cs View File

@@ -12,7 +12,7 @@ namespace Discord.Serialization.Json.Converters
_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();

@@ -32,7 +32,7 @@ namespace Discord.Serialization.Json.Converters
}
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)
writer.WriteObjectStart(key);


+ 0
- 26
src/Discord.Net.Serialization/Json/IJsonPropertyConverter.cs View File

@@ -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);
}
}

+ 34
- 0
src/Discord.Net.Serialization/Json/JsonPropertyConverter.cs View File

@@ -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);
}
}

+ 10
- 8
src/Discord.Net.Serialization/Json/JsonPropertyMap.cs View File

@@ -9,36 +9,38 @@ namespace Discord.Serialization.Json
string Key { 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>
{
private readonly ModelMap _modelMap;
private readonly JsonPropertyConverter<TValue> _converter;
private readonly Func<TModel, TValue> _getFunc;
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;

_getFunc = propInfo.GetMethod.CreateDelegate(typeof(Func<TModel, TValue>)) as Func<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);
}
public void Write(TModel model, ref JsonWriter writer)
public void Write(Serializer serializer, TModel model, ref JsonWriter writer)
{
var value = _getFunc(model);
if (value == null && ExcludeNull)
return;
_converter.Write(this, model, ref writer, value, Key);
_converter.Write(serializer, _modelMap, this, model, ref writer, value, Key);
}
}
}

+ 6
- 4
src/Discord.Net.Serialization/Json/JsonSerializer.cs View File

@@ -18,10 +18,10 @@ namespace Discord.Serialization.Json
where TConverter : JsonPropertyConverter<TValue>
=> 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);
return new JsonPropertyMap<TModel, TValue>(this, propInfo, converter);
return new JsonPropertyMap<TModel, TValue>(this, modelMap, propInfo, converter);
}
public TModel Read<TModel>(Utf8String str)
@@ -32,14 +32,16 @@ namespace Discord.Serialization.Json
if (!reader.Read())
return default;
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)
{
var writer = new JsonWriter(stream);
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);
}
}
}

+ 15
- 9
src/Discord.Net.Serialization/ModelMap.cs View File

@@ -1,22 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

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 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)


+ 5
- 5
src/Discord.Net.Serialization/PropertyMap.cs View File

@@ -11,18 +11,19 @@ namespace Discord.Serialization
public string Key { get; }
public ReadOnlyBuffer<byte> Utf8Key { get; }
public string Name { get; }
public string Path { get; }

public bool ExcludeNull { get; }

public PropertyMap(Serializer serializer, PropertyInfo propInfo)
internal PropertyMap(Serializer serializer, PropertyInfo propInfo, ModelMap modelMap)
{
Name = propInfo.Name;
Path = $"{modelMap.Path}.{propInfo.Name}";

var attr = propInfo.GetCustomAttribute<ModelPropertyAttribute>();
Key = attr.Key ?? propInfo.Name;
Utf8Key = new ReadOnlyBuffer<byte>(new Utf8String(Key).Bytes.ToArray());
ExcludeNull = attr.ExcludeNull;

}
public abstract object GetDynamicConverter(object model, bool throwOnMissing);
@@ -54,11 +55,10 @@ namespace Discord.Serialization
=> _group?.GetDynamicConverter(_getWrappedSelectorFunc, model);
}
private readonly Delegate _getSelectorFunc, _getWrappedSelectorFunc;
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>()
.Select(x =>


+ 62
- 13
src/Discord.Net.Serialization/Serializer.cs View File

@@ -4,18 +4,21 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Formatting;
using System.Text.Utf8;

namespace Discord.Serialization
{
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
= typeof(Serializer).GetTypeInfo().GetDeclaredMethod(nameof(CreatePropertyMap));
private readonly ConcurrentDictionary<Type, object> _maps;
private readonly ConverterCollection _converters;
private readonly ConcurrentHashSet<string> _unknownProps = new ConcurrentHashSet<string>();

protected Serializer()
: this(null) { }
@@ -50,16 +53,18 @@ namespace Discord.Serialization
public ISelectorGroup GetSelectorGroup(Type keyType, string 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), _ =>
{
var type = typeof(TModel).GetTypeInfo();
var searchType = type;
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)
.ToArray();

@@ -67,24 +72,68 @@ namespace Discord.Serialization
{
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)
=> Read<TModel>(data.Span);
public abstract TModel Read<TModel>(ReadOnlySpan<byte> data);
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);
}
}
}
}

+ 9
- 3
src/Discord.Net.WebSocket/Audio/AudioClient.cs View File

@@ -68,10 +68,16 @@ namespace Discord.Audio
_audioLogger = Discord.LogManager.CreateLogger($"Audio #{clientId}");

_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.SentGatewayMessage += async opCode => await _audioLogger.DebugAsync($"Sent {opCode}").ConfigureAwait(false);


+ 9
- 3
src/Discord.Net.WebSocket/DiscordShardedClient.cs View File

@@ -56,10 +56,16 @@ namespace Discord.WebSocket
_connectionGroupLock = new SemaphoreSlim(1, 1);

_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));



+ 9
- 3
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -88,10 +88,16 @@ namespace Discord.WebSocket
_gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}");

_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));



Loading…
Cancel
Save