diff --git a/src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs b/src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs
index f6479a0ae..f0faaefb8 100644
--- a/src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs
+++ b/src/Discord.Net.Core/Entities/Guilds/PermissionTarget.cs
@@ -4,9 +4,9 @@ namespace Discord
{
public enum PermissionTarget
{
- [ModelEnum("role")]
+ [ModelEnumValue("role")]
Role,
- [ModelEnum("user")]
+ [ModelEnumValue("user")]
User
}
}
diff --git a/src/Discord.Net.Core/Entities/Permissions/Overwrite.cs b/src/Discord.Net.Core/Entities/Permissions/Overwrite.cs
index bda67a870..3531d6147 100644
--- a/src/Discord.Net.Core/Entities/Permissions/Overwrite.cs
+++ b/src/Discord.Net.Core/Entities/Permissions/Overwrite.cs
@@ -1,10 +1,13 @@
-namespace Discord
+using Discord.Serialization;
+
+namespace Discord
{
public struct Overwrite
{
/// Gets the unique identifier for the object this overwrite is targeting.
public ulong TargetId { get; }
/// Gets the type of object this overwrite is targeting.
+ [ModelStringEnum]
public PermissionTarget TargetType { get; }
/// Gets the permissions associated with this overwrite entry.
public OverwritePermissions Permissions { get; }
diff --git a/src/Discord.Net.Core/Entities/Users/UserStatus.cs b/src/Discord.Net.Core/Entities/Users/UserStatus.cs
index 7d02fe68c..5f9ce9df5 100644
--- a/src/Discord.Net.Core/Entities/Users/UserStatus.cs
+++ b/src/Discord.Net.Core/Entities/Users/UserStatus.cs
@@ -5,13 +5,13 @@ namespace Discord
public enum UserStatus
{
Offline,
- [ModelEnum("online")]
+ [ModelEnumValue("online")]
Online,
- [ModelEnum("idle")]
+ [ModelEnumValue("idle")]
Idle,
- [ModelEnum("idle", EnumValueType.WriteOnly)]
+ [ModelEnumValue("idle", EnumValueType.WriteOnly)]
AFK,
- [ModelEnum("dnd")]
+ [ModelEnumValue("dnd")]
DoNotDisturb,
Invisible,
}
diff --git a/src/Discord.Net.Rest/API/Common/Presence.cs b/src/Discord.Net.Rest/API/Common/Presence.cs
index 68dae302a..c6c7d3436 100644
--- a/src/Discord.Net.Rest/API/Common/Presence.cs
+++ b/src/Discord.Net.Rest/API/Common/Presence.cs
@@ -10,6 +10,7 @@ namespace Discord.API
[ModelProperty("guild_id")]
public Optional GuildId { get; set; }
[ModelProperty("status")]
+ [ModelStringEnum]
public UserStatus Status { get; set; }
[ModelProperty("game")]
public Game Game { get; set; }
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index 5574afaa8..c708df258 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -191,7 +191,7 @@ namespace Discord.API
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
- if (_formatters.TryDequeue(out var data))
+ if (!_formatters.TryDequeue(out var data))
data = new ArrayFormatter(128, SymbolTable.InvariantUtf8);
try
{
@@ -240,7 +240,7 @@ namespace Discord.API
options.BucketId = AuthTokenType == TokenType.User ? ClientBucket.Get(clientBucket).Id : bucketId;
options.IsClientBucket = AuthTokenType == TokenType.User;
- if (_formatters.TryDequeue(out var data))
+ if (!_formatters.TryDequeue(out var data))
data = new ArrayFormatter(128, SymbolTable.InvariantUtf8);
try
{
@@ -1168,13 +1168,12 @@ namespace Discord.API
throw new InvalidOperationException("Client is not logged in.");
}
protected static double ToMilliseconds(Stopwatch stopwatch) => Math.Round((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2);
- protected ReadOnlyBuffer SerializeJson(ArrayFormatter data, object value)
+ protected ReadOnlyBuffer SerializeJson(ArrayFormatter data, T value)
{
_serializer.Write(data, value);
return new ReadOnlyBuffer(data.Formatted.Array, 0, data.Formatted.Count);
}
protected T DeserializeJson(ReadOnlyBuffer data)
- where T : class, new()
{
return _serializer.Read(data);
}
diff --git a/src/Discord.Net.Rest/Serialization/Json/Converters/EntityOrIdPropertyConverter.cs b/src/Discord.Net.Rest/Serialization/Json/Converters/EntityOrIdPropertyConverter.cs
index c25302c18..640de4016 100644
--- a/src/Discord.Net.Rest/Serialization/Json/Converters/EntityOrIdPropertyConverter.cs
+++ b/src/Discord.Net.Rest/Serialization/Json/Converters/EntityOrIdPropertyConverter.cs
@@ -12,19 +12,19 @@ namespace Discord.Serialization.Json.Converters
_innerConverter = innerConverter;
}
- public EntityOrId Read(PropertyMap map, ref JsonReader reader, bool isTopLevel)
+ public EntityOrId Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel)
{
if (isTopLevel)
reader.Read();
if (reader.ValueType == JsonValueType.Number)
return new EntityOrId(reader.ParseUInt64());
- return new EntityOrId(_innerConverter.Read(map, ref reader, false));
+ return new EntityOrId(_innerConverter.Read(map, model, ref reader, false));
}
- public void Write(PropertyMap map, ref JsonWriter writer, EntityOrId value, bool isTopLevel)
+ public void Write(PropertyMap map, object model, ref JsonWriter writer, EntityOrId value, bool isTopLevel)
{
if (value.Object != null)
- _innerConverter.Write(map, ref writer, value.Object, isTopLevel);
+ _innerConverter.Write(map, model, ref writer, value.Object, isTopLevel);
else
{
if (isTopLevel)
diff --git a/src/Discord.Net.Rest/Serialization/Json/Converters/ImagePropertyConverter.cs b/src/Discord.Net.Rest/Serialization/Json/Converters/ImagePropertyConverter.cs
index 6d28136aa..a5687b16d 100644
--- a/src/Discord.Net.Rest/Serialization/Json/Converters/ImagePropertyConverter.cs
+++ b/src/Discord.Net.Rest/Serialization/Json/Converters/ImagePropertyConverter.cs
@@ -5,7 +5,7 @@ namespace Discord.Serialization.Json.Converters
{
internal class ImagePropertyConverter : IJsonPropertyConverter
{
- public API.Image Read(PropertyMap map, ref JsonReader reader, bool isTopLevel)
+ public API.Image Read(PropertyMap map, 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 void Write(PropertyMap map, ref JsonWriter writer, API.Image value, bool isTopLevel)
+ public void Write(PropertyMap map, object model, ref JsonWriter writer, API.Image value, bool isTopLevel)
{
string str;
if (value.Stream != null)
diff --git a/src/Discord.Net.Rest/Serialization/Json/Converters/Int53PropertyConverter.cs b/src/Discord.Net.Rest/Serialization/Json/Converters/Int53PropertyConverter.cs
index d59fd1610..3b9fe89a6 100644
--- a/src/Discord.Net.Rest/Serialization/Json/Converters/Int53PropertyConverter.cs
+++ b/src/Discord.Net.Rest/Serialization/Json/Converters/Int53PropertyConverter.cs
@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters
{
internal class Int53PropertyConverter : IJsonPropertyConverter
{
- public long Read(PropertyMap map, ref JsonReader reader, bool isTopLevel)
+ public long Read(PropertyMap map, 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 void Write(PropertyMap map, ref JsonWriter writer, long value, bool isTopLevel)
+ public void Write(PropertyMap map, object model, ref JsonWriter writer, long value, bool isTopLevel)
{
if (isTopLevel)
writer.WriteAttribute(map.Key, value);
diff --git a/src/Discord.Net.Rest/Serialization/Json/Converters/OptionalPropertyConverter.cs b/src/Discord.Net.Rest/Serialization/Json/Converters/OptionalPropertyConverter.cs
index 06609fbbd..4a5218a34 100644
--- a/src/Discord.Net.Rest/Serialization/Json/Converters/OptionalPropertyConverter.cs
+++ b/src/Discord.Net.Rest/Serialization/Json/Converters/OptionalPropertyConverter.cs
@@ -11,13 +11,13 @@ namespace Discord.Serialization.Json.Converters
_innerConverter = innerConverter;
}
- public Optional Read(PropertyMap map, ref JsonReader reader, bool isTopLevel)
- => new Optional(_innerConverter.Read(map, ref reader, isTopLevel));
+ public Optional Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel)
+ => new Optional(_innerConverter.Read(map, model, ref reader, isTopLevel));
- public void Write(PropertyMap map, ref JsonWriter writer, Optional value, bool isTopLevel)
+ public void Write(PropertyMap map, object model, ref JsonWriter writer, Optional value, bool isTopLevel)
{
if (value.IsSpecified)
- _innerConverter.Write(map, ref writer, value.Value, isTopLevel);
+ _innerConverter.Write(map, model, ref writer, value.Value, isTopLevel);
}
}
}
diff --git a/src/Discord.Net.Rest/Serialization/Json/Converters/UInt53PropertyConverter.cs b/src/Discord.Net.Rest/Serialization/Json/Converters/UInt53PropertyConverter.cs
index fa35ff711..9664fc3a2 100644
--- a/src/Discord.Net.Rest/Serialization/Json/Converters/UInt53PropertyConverter.cs
+++ b/src/Discord.Net.Rest/Serialization/Json/Converters/UInt53PropertyConverter.cs
@@ -4,7 +4,7 @@ namespace Discord.Serialization.Json.Converters
{
internal class UInt53PropertyConverter : IJsonPropertyConverter
{
- public ulong Read(PropertyMap map, ref JsonReader reader, bool isTopLevel)
+ public ulong Read(PropertyMap map, 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 void Write(PropertyMap map, ref JsonWriter writer, ulong value, bool isTopLevel)
+ public void Write(PropertyMap map, object model, ref JsonWriter writer, ulong value, bool isTopLevel)
{
if (isTopLevel)
writer.WriteAttribute(map.Key, value);
diff --git a/src/Discord.Net.Rest/Serialization/ModelSelectorGroups.cs b/src/Discord.Net.Rest/Serialization/ModelSelectorGroups.cs
new file mode 100644
index 000000000..f35d99c0d
--- /dev/null
+++ b/src/Discord.Net.Rest/Serialization/ModelSelectorGroups.cs
@@ -0,0 +1,11 @@
+namespace Discord.Serialization
+{
+ public static class ModelSelectorGroups
+ {
+ public const string GatewayFrame = nameof(GatewayFrame);
+ public const string GatewayDispatchFrame = nameof(GatewayDispatchFrame);
+ public const string VoiceFrame = nameof(VoiceFrame);
+ public const string VoiceDispatchFrame = nameof(VoiceDispatchFrame);
+ public const string RpcFrame = nameof(RpcFrame);
+ }
+}
diff --git a/src/Discord.Net.Rpc/API/RpcFrame.cs b/src/Discord.Net.Rpc/API/RpcFrame.cs
index 0bdd9f809..621ced976 100644
--- a/src/Discord.Net.Rpc/API/RpcFrame.cs
+++ b/src/Discord.Net.Rpc/API/RpcFrame.cs
@@ -14,7 +14,9 @@ namespace Discord.API.Rpc
public Optional Event { get; set; }
[ModelProperty("data")]
public Optional> Data { get; set; }
+
[ModelProperty("args")]
+ [ModelSelector(ModelSelectorGroups.RpcFrame, nameof(Event))]
public object Args { get; set; }
}
}
diff --git a/src/Discord.Net.Rpc/DiscordRpcApiClient.cs b/src/Discord.Net.Rpc/DiscordRpcApiClient.cs
index 34eb1efd3..5ff89f71e 100644
--- a/src/Discord.Net.Rpc/DiscordRpcApiClient.cs
+++ b/src/Discord.Net.Rpc/DiscordRpcApiClient.cs
@@ -5,6 +5,7 @@ using Discord.Net.Rest;
using Discord.Net.WebSockets;
using Discord.Rpc;
using Discord.Serialization;
+using Discord.Serialization.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -41,11 +42,11 @@ namespace Discord.API
}
public Task SetResultAsync(ReadOnlyBuffer data)
{
- return Promise.TrySetResultAsync(Serializer.Json.Read(data));
+ return Promise.TrySetResultAsync(DiscordJsonSerializer.Global.Read(data));
}
public Task SetExceptionAsync(ReadOnlyBuffer data)
{
- var error = Serializer.Json.Read(data);
+ var error = DiscordJsonSerializer.Global.Read(data);
return Promise.TrySetExceptionAsync(new RpcException(error.Code, error.Message));
}
}
@@ -231,12 +232,12 @@ namespace Discord.API
try
{
var guid = Guid.NewGuid();
- payload = new API.Rpc.RpcFrame { Cmd = cmd, Event = evt, Args = SerializeJson(data1, payload), Nonce = guid };
+ var frame = new API.Rpc.RpcFrame { Cmd = cmd, Event = evt, Args = SerializeJson(data1, payload), Nonce = guid };
var requestTracker = new RpcRequest(options);
_requests[guid] = requestTracker;
- await RequestQueue.SendAsync(new WebSocketRequest(_webSocketClient, null, SerializeJson(data2, payload), true, options)).ConfigureAwait(false);
+ await RequestQueue.SendAsync(new WebSocketRequest(_webSocketClient, null, SerializeJson(data2, frame), true, options)).ConfigureAwait(false);
await _sentRpcMessageEvent.InvokeAsync(cmd).ConfigureAwait(false);
return await requestTracker.Promise.Task.ConfigureAwait(false);
}
diff --git a/src/Discord.Net.Rpc/DiscordRpcClient.cs b/src/Discord.Net.Rpc/DiscordRpcClient.cs
index 2615972f9..b208e4f40 100644
--- a/src/Discord.Net.Rpc/DiscordRpcClient.cs
+++ b/src/Discord.Net.Rpc/DiscordRpcClient.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using Discord.Serialization;
+using Discord.Serialization.Json;
namespace Discord.Rpc
{
@@ -37,7 +38,7 @@ namespace Discord.Rpc
_authorizeLock = new SemaphoreSlim(1, 1);
_rpcLogger = LogManager.CreateLogger("RPC");
- _serializer = new Serializer(SerializationFormat.Json);
+ _serializer = DiscordJsonSerializer.Global.CreateScope();
_serializer.Error += ex =>
{
_rpcLogger.WarningAsync("Serializer Error", ex).GetAwaiter().GetResult();
diff --git a/src/Discord.Net.Serialization/EnumValueAttribute.cs b/src/Discord.Net.Serialization/Attributes/ModelEnumValueAttribute.cs
similarity index 71%
rename from src/Discord.Net.Serialization/EnumValueAttribute.cs
rename to src/Discord.Net.Serialization/Attributes/ModelEnumValueAttribute.cs
index 8b5e235f0..3cdcd3601 100644
--- a/src/Discord.Net.Serialization/EnumValueAttribute.cs
+++ b/src/Discord.Net.Serialization/Attributes/ModelEnumValueAttribute.cs
@@ -10,12 +10,12 @@ namespace Discord.Serialization
}
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
- public class ModelEnumAttribute : Attribute
+ public class ModelEnumValueAttribute : Attribute
{
public string Key { get; }
public EnumValueType Type { get; }
- public ModelEnumAttribute(string key, EnumValueType type = EnumValueType.ReadWrite)
+ public ModelEnumValueAttribute(string key, EnumValueType type = EnumValueType.ReadWrite)
{
Key = key;
Type = type;
diff --git a/src/Discord.Net.Serialization/ModelPropertyAttribute.cs b/src/Discord.Net.Serialization/Attributes/ModelPropertyAttribute.cs
similarity index 72%
rename from src/Discord.Net.Serialization/ModelPropertyAttribute.cs
rename to src/Discord.Net.Serialization/Attributes/ModelPropertyAttribute.cs
index 338c7a857..6a33371e1 100644
--- a/src/Discord.Net.Serialization/ModelPropertyAttribute.cs
+++ b/src/Discord.Net.Serialization/Attributes/ModelPropertyAttribute.cs
@@ -8,7 +8,9 @@ namespace Discord.Serialization
public string Key { get; }
public bool ExcludeNull { get; set; }
- public ModelPropertyAttribute(string key = null)
+ public ModelPropertyAttribute()
+ : this(null) { }
+ public ModelPropertyAttribute(string key)
{
Key = key;
}
diff --git a/src/Discord.Net.Serialization/Attributes/ModelSelectorAttribute.cs b/src/Discord.Net.Serialization/Attributes/ModelSelectorAttribute.cs
new file mode 100644
index 000000000..895093f1c
--- /dev/null
+++ b/src/Discord.Net.Serialization/Attributes/ModelSelectorAttribute.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Discord.Serialization
+{
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
+ public class ModelSelectorAttribute : Attribute
+ {
+ public string SelectorProperty { get; }
+ public string SelectorGroup { get; }
+
+ public ModelSelectorAttribute(string selectorProperty, string selectorGroup)
+ {
+ SelectorProperty = selectorProperty;
+ SelectorGroup = selectorGroup;
+ }
+ }
+}
diff --git a/src/Discord.Net.Serialization/Attributes/ModelStringEnumAttribute.cs b/src/Discord.Net.Serialization/Attributes/ModelStringEnumAttribute.cs
new file mode 100644
index 000000000..9c88a23ae
--- /dev/null
+++ b/src/Discord.Net.Serialization/Attributes/ModelStringEnumAttribute.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Discord.Serialization
+{
+ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
+ public class ModelStringEnumAttribute : Attribute
+ {
+ }
+}
diff --git a/src/Discord.Net.Serialization/ConverterCollection.cs b/src/Discord.Net.Serialization/ConverterCollection.cs
index e2d8f0eb7..c1a0efa81 100644
--- a/src/Discord.Net.Serialization/ConverterCollection.cs
+++ b/src/Discord.Net.Serialization/ConverterCollection.cs
@@ -17,14 +17,20 @@ namespace Discord.Serialization
private static readonly TypeInfo _serializerType = typeof(Serializer).GetTypeInfo();
private readonly Serializer _serializer;
- private readonly ConcurrentDictionary _cache = new ConcurrentDictionary();
- private readonly Dictionary _types = new Dictionary();
- private readonly Dictionary _mappedGenericTypes = new Dictionary();
- private readonly ConverterTypeCollection _genericTypes = new ConverterTypeCollection();
+ private readonly ConcurrentDictionary _cache;
+ private readonly Dictionary _types;
+ private readonly Dictionary _mappedGenericTypes;
+ private readonly ConverterTypeCollection _genericTypes;
+ private readonly ConcurrentDictionary> _selectorGroups;
internal ConverterCollection(Serializer serializer)
{
_serializer = serializer;
+ _cache = new ConcurrentDictionary();
+ _types = new Dictionary();
+ _mappedGenericTypes = new Dictionary();
+ _genericTypes = new ConverterTypeCollection();
+ _selectorGroups = new ConcurrentDictionary>();
}
public void Add(Type type, Type converterType)
@@ -66,15 +72,22 @@ namespace Discord.Serialization
_mappedGenericTypes.Add(openType, converters = new ConverterTypeCollection());
converters.Conditionals.Add((condition, openConverterType));
}
-
+
+ public void AddSelector(string groupKey, Type keyType, object keyValue, Type converterType)
+ {
+ var group = GetSelectorGroup(keyType, groupKey);
+ group.AddDynamicConverter(keyValue, converterType);
+ }
+
public object Get(Type type, PropertyInfo propInfo = null)
{
- if (!_cache.TryGetValue(type, out var result))
+ if (propInfo == null) //Can only cache top-level due to attribute influences
{
- object converter = Create(type, propInfo);
- result = _cache.GetOrAdd(type, converter);
+ if (_cache.TryGetValue(type, out var result))
+ return result;
+ return _cache.GetOrAdd(type, Create(type, propInfo));
}
- return result;
+ return Create(type, propInfo);
}
private object Create(Type type, PropertyInfo propInfo)
{
@@ -108,7 +121,7 @@ namespace Discord.Serialization
converterType = converterType.MakeGenericType(type);
var converterTypeInfo = converterType.GetTypeInfo();
- var constructors = converterTypeInfo.DeclaredConstructors.ToArray();
+ var constructors = converterTypeInfo.DeclaredConstructors.Where(x => !x.IsStatic).ToArray();
if (constructors.Length == 0)
throw new SerializationException($"{converterType.Name} is missing a constructor");
if (constructors.Length != 1)
@@ -148,5 +161,17 @@ namespace Discord.Serialization
return converters.DefaultConverterType;
return null;
}
+
+ public ISelectorGroup GetSelectorGroup(Type keyType, string groupKey)
+ {
+ var keyGroup = GetSelectorKeyGroup(keyType);
+ if (keyGroup.TryGetValue(groupKey, out var selectorGroup))
+ return selectorGroup;
+ return CreateSelectorGroup(keyType, keyGroup, groupKey);
+ }
+ private ISelectorGroup CreateSelectorGroup(Type keyType, ConcurrentDictionary keyGroup, string groupKey)
+ => keyGroup.GetOrAdd(groupKey, Activator.CreateInstance(typeof(SelectorGroup<>).MakeGenericType(keyType)) as ISelectorGroup);
+ private ConcurrentDictionary GetSelectorKeyGroup(Type keyType)
+ => _selectorGroups.GetOrAdd(keyType, _ => new ConcurrentDictionary());
}
}
diff --git a/src/Discord.Net.Serialization/EnumMap.cs b/src/Discord.Net.Serialization/EnumMap.cs
index 80aaef942..6c1d1a806 100644
--- a/src/Discord.Net.Serialization/EnumMap.cs
+++ b/src/Discord.Net.Serialization/EnumMap.cs
@@ -16,9 +16,12 @@ namespace Discord.Serialization
{
public static readonly EnumMap Instance = new EnumMap();
- private readonly BufferDictionary _keyToValue;
+ private readonly Dictionary _keyToValue;
+ private readonly BufferDictionary _utf8KeyToValue;
+ private readonly Dictionary _intToValue;
+
private readonly Dictionary _valueToKey;
- private readonly Dictionary> _valueToUtf8Key;
+ private readonly Dictionary _valueToInt;
public EnumMap()
{
@@ -26,50 +29,104 @@ namespace Discord.Serialization
if (!typeInfo.IsEnum)
throw new InvalidOperationException($"{typeInfo.Name} is not an Enum");
- _keyToValue = new BufferDictionary();
+ _keyToValue = new Dictionary();
+ _utf8KeyToValue = new BufferDictionary();
+ _intToValue = new Dictionary();
+
_valueToKey = new Dictionary();
- _valueToUtf8Key = new Dictionary>();
+ _valueToInt = new Dictionary();
foreach (T val in Enum.GetValues(typeof(T)).OfType())
{
var fieldInfo = typeInfo.GetDeclaredField(Enum.GetName(typeof(T), val));
- var attr = fieldInfo.GetCustomAttribute();
+ var attr = fieldInfo.GetCustomAttribute();
if (attr != null)
{
- var key = new ReadOnlyBuffer(new Utf8String(attr.Key).Bytes.ToArray());
+ string key = attr.Key;
+ var keyBuffer = new ReadOnlyBuffer(new Utf8String(attr.Key).Bytes.ToArray());
if (attr.Type != EnumValueType.WriteOnly)
- _keyToValue.Add(key, val);
- if (attr.Type != EnumValueType.ReadOnly)
{
- _valueToUtf8Key.Add(val, key);
- _valueToKey.Add(val, attr.Key);
+ _keyToValue.Add(key, val);
+ _utf8KeyToValue.Add(keyBuffer, val);
}
+ if (attr.Type != EnumValueType.ReadOnly)
+ _valueToKey.Add(val, key);
}
+
+ var underlyingType = Enum.GetUnderlyingType(typeof(T));
+ long baseVal;
+ if (underlyingType == typeof(sbyte))
+ baseVal = (sbyte)(ValueType)val;
+ else if (underlyingType == typeof(short))
+ baseVal = (short)(ValueType)val;
+ else if (underlyingType == typeof(int))
+ baseVal = (int)(ValueType)val;
+ else if (underlyingType == typeof(long))
+ baseVal = (long)(ValueType)val;
+ else if (underlyingType == typeof(byte))
+ baseVal = (byte)(ValueType)val;
+ else if (underlyingType == typeof(ushort))
+ baseVal = (ushort)(ValueType)val;
+ else if (underlyingType == typeof(uint))
+ baseVal = (uint)(ValueType)val;
+ else if (underlyingType == typeof(ulong))
+ baseVal = (long)(ulong)(ValueType)val;
+ else
+ throw new SerializationException($"Unsupported underlying enum type: {underlyingType.Name}");
+
+ _intToValue.Add(baseVal, val);
+ _valueToInt.Add(val, baseVal);
}
}
-
- public T GetValue(ReadOnlyBuffer key)
+
+ public T FromKey(ReadOnlyBuffer key)
{
- if (_keyToValue.TryGetValue(key, out var value))
+ if (_utf8KeyToValue.TryGetValue(key, out var value))
return value;
throw new SerializationException($"Unknown enum key: {new Utf8String(key.Span).ToString()}");
}
- public T GetValue(ReadOnlySpan key)
+ public T FromKey(ReadOnlySpan key)
{
- if (_keyToValue.TryGetValue(key, out var value))
+ if (_utf8KeyToValue.TryGetValue(key, out var value))
return value;
throw new SerializationException($"Unknown enum key: {new Utf8String(key).ToString()}");
}
- public string GetKey(T value)
+ public string ToUtf16Key(T value)
{
if (_valueToKey.TryGetValue(value, out var key))
return key;
throw new SerializationException($"Unknown enum value: {value}");
}
- public ReadOnlyBuffer GetUtf8Key(T value)
+
+ public T FromInt64(ReadOnlyBuffer intBuffer)
+ => FromInt64(intBuffer.Span);
+ public T FromInt64(ReadOnlySpan intBuffer)
{
- if (_valueToUtf8Key.TryGetValue(value, out var key))
- return key;
+ long intValue = intBuffer.ParseInt64();
+ if (_intToValue.TryGetValue(intValue, out var value))
+ return value;
+ throw new SerializationException($"Unknown enum value: {intValue}");
+ }
+ public long ToInt64(T value)
+ {
+ if (_valueToInt.TryGetValue(value, out var intValue))
+ return intValue;
+ throw new SerializationException($"Unknown enum value: {value}");
+ }
+
+ public T FromUInt64(ReadOnlyBuffer intBuffer)
+ => FromUInt64(intBuffer.Span);
+ public T FromUInt64(ReadOnlySpan intBuffer)
+ {
+ ulong intValue = intBuffer.ParseUInt64();
+ if (_intToValue.TryGetValue((long)intValue, out var value))
+ return value;
+ throw new SerializationException($"Unknown enum value: {intValue}");
+ }
+ public ulong ToUInt64(T value)
+ {
+ if (_valueToInt.TryGetValue(value, out var intValue))
+ return (ulong)intValue;
throw new SerializationException($"Unknown enum value: {value}");
}
}
diff --git a/src/Discord.Net.Serialization/Extensions/JsonReaderExtensions.cs b/src/Discord.Net.Serialization/Extensions/JsonReaderExtensions.cs
index 84b094724..9993c2e1b 100644
--- a/src/Discord.Net.Serialization/Extensions/JsonReaderExtensions.cs
+++ b/src/Discord.Net.Serialization/Extensions/JsonReaderExtensions.cs
@@ -29,7 +29,7 @@ namespace Discord.Serialization
public static Guid ParseGuid(this JsonReader reader) => reader.Value.ParseGuid();
}
- public static class JsonUtils
+ public static class JsonReaderUtils
{
public static void Skip(ref JsonReader reader)
{
diff --git a/src/Discord.Net.Serialization/Json/Converters/Collections.cs b/src/Discord.Net.Serialization/Json/Converters/Collections.cs
index b0096b860..9dcf3b373 100644
--- a/src/Discord.Net.Serialization/Json/Converters/Collections.cs
+++ b/src/Discord.Net.Serialization/Json/Converters/Collections.cs
@@ -3,7 +3,7 @@ using System.Text.Json;
namespace Discord.Serialization.Json.Converters
{
- internal class ListPropertyConverter : IJsonPropertyConverter>
+ public class ListPropertyConverter : IJsonPropertyConverter>
{
private readonly IJsonPropertyConverter _innerConverter;
@@ -12,25 +12,25 @@ namespace Discord.Serialization.Json.Converters
_innerConverter = innerConverter;
}
- public List Read(PropertyMap map, ref JsonReader reader, bool isTopLevel)
+ public List Read(PropertyMap map, object model, ref JsonReader reader, bool isTopLevel)
{
if ((isTopLevel && !reader.Read()) || reader.TokenType != JsonTokenType.StartArray)
throw new SerializationException("Bad input, expected StartArray");
var list = new List();
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
- list.Add(_innerConverter.Read(map, ref reader, false));
+ list.Add(_innerConverter.Read(map, model, ref reader, false));
return list;
}
- public void Write(PropertyMap map, ref JsonWriter writer, List value, bool isTopLevel)
+ public void Write(PropertyMap map, object model, ref JsonWriter writer, List value, bool isTopLevel)
{
if (isTopLevel)
writer.WriteArrayStart(map.Key);
else
writer.WriteArrayStart();
for (int i = 0; i < value.Count; i++)
- _innerConverter.Write(map, ref writer, value[i], false);
+ _innerConverter.Write(map, model, ref writer, value[i], false);
writer.WriteArrayEnd();
}
}
diff --git a/src/Discord.Net.Serialization/Json/Converters/Dynamic.cs b/src/Discord.Net.Serialization/Json/Converters/Dynamic.cs
new file mode 100644
index 000000000..bba1bf0c2
--- /dev/null
+++ b/src/Discord.Net.Serialization/Json/Converters/Dynamic.cs
@@ -0,0 +1,35 @@
+using System.Text.Json;
+
+namespace Discord.Serialization.Json.Converters
+{
+ //TODO: Only supports cases where the key arrives first
+ public class DynamicPropertyConverter : IJsonPropertyConverter