@@ -27,7 +27,7 @@ namespace Discord.API | |||
[JsonProperty("mention_everyone")] | |||
public Optional<bool> MentionEveryone { get; set; } | |||
[JsonProperty("mentions")] | |||
public Optional<ObjectOrId<User>[]> UserMentions { get; set; } | |||
public Optional<EntityOrId<User>[]> UserMentions { get; set; } | |||
[JsonProperty("mention_roles")] | |||
public Optional<ulong[]> RoleMentions { get; set; } | |||
[JsonProperty("attachments")] | |||
@@ -1,16 +1,16 @@ | |||
namespace Discord.API | |||
{ | |||
public struct ObjectOrId<T> | |||
public struct EntityOrId<T> | |||
{ | |||
public ulong Id { get; } | |||
public T Object { get; } | |||
public ObjectOrId(ulong id) | |||
public EntityOrId(ulong id) | |||
{ | |||
Id = id; | |||
Object = default(T); | |||
} | |||
public ObjectOrId(T obj) | |||
public EntityOrId(T obj) | |||
{ | |||
Id = 0; | |||
Object = obj; |
@@ -1,28 +1,38 @@ | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Globalization; | |||
namespace Discord.Net.Converters | |||
{ | |||
internal class UInt64ArrayConverter : JsonConverter | |||
internal class ArrayConverter<T> : JsonConverter | |||
{ | |||
public static readonly UInt64ArrayConverter Instance = new UInt64ArrayConverter(); | |||
public static ArrayConverter<T> Instance; | |||
private readonly JsonConverter _innerConverter; | |||
public override bool CanConvert(Type objectType) => true; | |||
public override bool CanRead => true; | |||
public override bool CanWrite => true; | |||
public ArrayConverter(JsonConverter innerConverter) | |||
{ | |||
_innerConverter = innerConverter; | |||
} | |||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | |||
{ | |||
var result = new List<ulong>(); | |||
var result = new List<T>(); | |||
if (reader.TokenType == JsonToken.StartArray) | |||
{ | |||
reader.Read(); | |||
while (reader.TokenType != JsonToken.EndArray) | |||
{ | |||
ulong id = ulong.Parse((string)reader.Value, NumberStyles.None, CultureInfo.InvariantCulture); | |||
result.Add(id); | |||
T obj; | |||
if (_innerConverter != null) | |||
obj = (T)_innerConverter.ReadJson(reader, typeof(T), null, serializer); | |||
else | |||
obj = serializer.Deserialize<T>(reader); | |||
result.Add(obj); | |||
reader.Read(); | |||
} | |||
} | |||
@@ -33,9 +43,15 @@ namespace Discord.Net.Converters | |||
if (value != null) | |||
{ | |||
writer.WriteStartArray(); | |||
var a = (ulong[])value; | |||
var a = (T[])value; | |||
for (int i = 0; i < a.Length; i++) | |||
writer.WriteValue(a[i].ToString(CultureInfo.InvariantCulture)); | |||
{ | |||
if (_innerConverter != null) | |||
_innerConverter.WriteJson(writer, a[i], serializer); | |||
else | |||
serializer.Serialize(writer, a[i], typeof(T)); | |||
} | |||
writer.WriteEndArray(); | |||
} | |||
else |
@@ -23,7 +23,7 @@ namespace Discord.Net.Converters | |||
if (propInfo != null) | |||
{ | |||
JsonConverter converter; | |||
var type = propInfo.PropertyType; | |||
Type type = propInfo.PropertyType; | |||
Type genericType = type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : null; | |||
if (genericType == typeof(Optional<>)) | |||
@@ -37,29 +37,7 @@ namespace Discord.Net.Converters | |||
var shouldSerializeDelegate = (Func<object, Delegate, bool>)shouldSerialize.CreateDelegate(typeof(Func<object, Delegate, bool>)); | |||
property.ShouldSerialize = x => shouldSerializeDelegate(x, getterDelegate); | |||
var converterType = typeof(OptionalConverter<>).MakeGenericType(innerTypeOutput).GetTypeInfo(); | |||
var instanceField = converterType.GetDeclaredField("Instance"); | |||
converter = instanceField.GetValue(null) as JsonConverter; | |||
if (converter == null) | |||
{ | |||
var innerConverter = GetConverter(propInfo, innerTypeOutput); | |||
converter = converterType.DeclaredConstructors.First().Invoke(new object[] { innerConverter }) as JsonConverter; | |||
instanceField.SetValue(null, converter); | |||
} | |||
} | |||
else if (genericType == typeof(ObjectOrId<>)) | |||
{ | |||
var innerTypeOutput = type.GenericTypeArguments[0]; | |||
var converterType = typeof(ObjectOrIdConverter<>).MakeGenericType(innerTypeOutput).GetTypeInfo(); | |||
var instanceField = converterType.GetDeclaredField("Instance"); | |||
converter = instanceField.GetValue(null) as JsonConverter; | |||
if (converter == null) | |||
{ | |||
var innerConverter = GetConverter(propInfo, innerTypeOutput); | |||
converter = converterType.DeclaredConstructors.First().Invoke(new object[] { innerConverter }) as JsonConverter; | |||
instanceField.SetValue(null, converter); | |||
} | |||
converter = MakeGenericConverter(propInfo, typeof(OptionalConverter<>), innerTypeOutput); | |||
} | |||
else | |||
converter = GetConverter(propInfo, type); | |||
@@ -75,9 +53,18 @@ namespace Discord.Net.Converters | |||
return property; | |||
} | |||
private JsonConverter GetConverter(MemberInfo member, Type type, TypeInfo typeInfo = null) | |||
private static JsonConverter GetConverter(PropertyInfo propInfo, Type type, TypeInfo typeInfo = null, int depth = 0) | |||
{ | |||
bool hasInt53 = member.GetCustomAttribute<Int53Attribute>() != null; | |||
if (type.IsArray) | |||
return MakeGenericConverter(propInfo, typeof(ArrayConverter<>), type.GetElementType()); | |||
if (type.IsConstructedGenericType) | |||
{ | |||
Type genericType = type.GetGenericTypeDefinition(); | |||
if (genericType == typeof(EntityOrId<>)) | |||
return MakeGenericConverter(propInfo, typeof(UInt64EntityOrIdConverter<>), type.GenericTypeArguments[0]); | |||
} | |||
bool hasInt53 = propInfo.GetCustomAttribute<Int53Attribute>() != null; | |||
//Primitives | |||
if (!hasInt53) | |||
@@ -100,10 +87,6 @@ namespace Discord.Net.Converters | |||
if (typeInfo == null) typeInfo = type.GetTypeInfo(); | |||
//Primitives | |||
if (!hasInt53 && typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEnumerable<ulong>))) | |||
return UInt64ArrayConverter.Instance; | |||
//Entities | |||
if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEntity<ulong>))) | |||
return UInt64EntityConverter.Instance; | |||
@@ -117,5 +100,19 @@ namespace Discord.Net.Converters | |||
{ | |||
return (getter as Func<TOwner, Optional<TValue>>)((TOwner)owner).IsSpecified; | |||
} | |||
private static JsonConverter MakeGenericConverter(PropertyInfo propInfo, Type converterType, Type innerType) | |||
{ | |||
var genericType = converterType.MakeGenericType(innerType).GetTypeInfo(); | |||
var instanceField = genericType.GetDeclaredField("Instance"); | |||
var converter = instanceField.GetValue(null) as JsonConverter; | |||
if (converter == null) | |||
{ | |||
var innerConverter = GetConverter(propInfo, innerType); | |||
converter = genericType.DeclaredConstructors.First().Invoke(new object[] { innerConverter }) as JsonConverter; | |||
instanceField.SetValue(null, converter); | |||
} | |||
return converter; | |||
} | |||
} | |||
} |
@@ -4,9 +4,9 @@ using System; | |||
namespace Discord.Net.Converters | |||
{ | |||
internal class ObjectOrIdConverter<T> : JsonConverter | |||
internal class UInt64EntityOrIdConverter<T> : JsonConverter | |||
{ | |||
internal static ObjectOrIdConverter<T> Instance; | |||
public static UInt64EntityOrIdConverter<T> Instance; | |||
private readonly JsonConverter _innerConverter; | |||
@@ -14,7 +14,7 @@ namespace Discord.Net.Converters | |||
public override bool CanRead => true; | |||
public override bool CanWrite => false; | |||
public ObjectOrIdConverter(JsonConverter innerConverter) | |||
public UInt64EntityOrIdConverter(JsonConverter innerConverter) | |||
{ | |||
_innerConverter = innerConverter; | |||
} | |||
@@ -25,9 +25,14 @@ namespace Discord.Net.Converters | |||
{ | |||
case JsonToken.String: | |||
case JsonToken.Integer: | |||
return new ObjectOrId<T>(ulong.Parse(reader.ReadAsString())); | |||
return new EntityOrId<T>(ulong.Parse(reader.ReadAsString())); | |||
default: | |||
return new ObjectOrId<T>(serializer.Deserialize<T>(reader)); | |||
T obj; | |||
if (_innerConverter != null) | |||
obj = (T)_innerConverter.ReadJson(reader, typeof(T), null, serializer); | |||
else | |||
obj = serializer.Deserialize<T>(reader); | |||
return new EntityOrId<T>(obj); | |||
} | |||
} | |||