mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-09 04:19:42 -05:00
Merge pull request #189 from dwango/fix_dictionary_deserializer
Fix dictionary deserializer
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#pragma warning disable 0649
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -138,18 +139,59 @@ namespace UniJSON
|
||||
DeserializeValue(new List<int> { 1 }, "[1]");
|
||||
//DeserializeValue(new object[] { null, 1, "a" }, "[null,1,\"a\"]");
|
||||
|
||||
DeserializeValue(new Dictionary<string, object> { }, "{}");
|
||||
DeserializeValue(new Dictionary<string, object> { { "a", 1 } }, "{\"a\":1}");
|
||||
DeserializeValue(new Dictionary<string, object> { { "a",
|
||||
new Dictionary<string, object>{
|
||||
} } }, "{\"a\":{}}");
|
||||
|
||||
DeserializeValue(new Point { X = 1 }, "{\"X\":1,\"Y\":0}");
|
||||
|
||||
DeserializeValue(HogeFuga.Fuga, "1");
|
||||
|
||||
DeserializeValue(new EnumTest(), "{\"EnumDefault\":0,\"EnumAsInt\":0,\"EnumAsString\":\"Hoge\",\"EnumAsLowerString\":\"hoge\"}");
|
||||
}
|
||||
|
||||
class DictionaryValue: IEquatable<DictionaryValue>
|
||||
{
|
||||
public Dictionary<string, object> Dict = new Dictionary<string, object>();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var rhs = obj as DictionaryValue;
|
||||
if (rhs != null)
|
||||
{
|
||||
return Equals(rhs);
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(DictionaryValue other)
|
||||
{
|
||||
if(Dict==null && other.Dict == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if(Dict==null || other.Dict==null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Dict.OrderBy(x => x.Key).SequenceEqual(other.Dict.OrderBy(x => x.Key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JsonDictionaryDeserializerTest()
|
||||
{
|
||||
DeserializeValue(new Dictionary<string, object> { }, "{}");
|
||||
DeserializeValue(new Dictionary<string, object> { { "a", 1 } }, "{\"a\":1}");
|
||||
DeserializeValue(new Dictionary<string, object> { { "a",
|
||||
new Dictionary<string, object>{
|
||||
} } }, "{\"a\":{}}");
|
||||
|
||||
// fix dictionary member deserialization
|
||||
DeserializeValue(new DictionaryValue(), "{\"Dict\": {}}");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
53
Assets/VRM/UniJSON/Scripts/GenericConstructor.cs
Normal file
53
Assets/VRM/UniJSON/Scripts/GenericConstructor.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
namespace UniJSON
|
||||
{
|
||||
struct GenericConstructor<T, U>
|
||||
where T : IListTreeItem, IValue<T>
|
||||
{
|
||||
static V[] ArrayCreator<V>(ListTreeNode<T> src)
|
||||
{
|
||||
if (!src.IsArray())
|
||||
{
|
||||
throw new ArgumentException("value is not array");
|
||||
}
|
||||
var count = src.GetArrayCount();
|
||||
return new V[count];
|
||||
}
|
||||
|
||||
static Func<ListTreeNode<T>, U> GetCreator()
|
||||
{
|
||||
var t = typeof(U);
|
||||
if (t.IsArray)
|
||||
{
|
||||
var mi = typeof(GenericConstructor<T, U>).GetMethod("ArrayCreator",
|
||||
BindingFlags.NonPublic | BindingFlags.Static);
|
||||
var g = mi.MakeGenericMethod(t.GetElementType());
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(g);
|
||||
}
|
||||
|
||||
{
|
||||
return _s =>
|
||||
{
|
||||
return Activator.CreateInstance<U>();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
delegate U Creator(ListTreeNode<T> src);
|
||||
|
||||
static Creator s_creator;
|
||||
|
||||
public U Create(ListTreeNode<T> src)
|
||||
{
|
||||
if (s_creator == null)
|
||||
{
|
||||
var d = GetCreator();
|
||||
s_creator = new Creator(d);
|
||||
}
|
||||
return s_creator(src);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/VRM/UniJSON/Scripts/GenericConstructor.cs.meta
Normal file
12
Assets/VRM/UniJSON/Scripts/GenericConstructor.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6121925cab5acc54bbb0e0e213783394
|
||||
timeCreated: 1549447177
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
256
Assets/VRM/UniJSON/Scripts/GenericDeserializer.cs
Normal file
256
Assets/VRM/UniJSON/Scripts/GenericDeserializer.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
|
||||
namespace UniJSON
|
||||
{
|
||||
public static class GenericDeserializer<T, U>
|
||||
where T : IListTreeItem, IValue<T>
|
||||
{
|
||||
static V[] GenericArrayDeserializer<V>(ListTreeNode<T> s)
|
||||
{
|
||||
if (!s.IsArray())
|
||||
{
|
||||
throw new ArgumentException("not array: " + s.Value.ValueType);
|
||||
}
|
||||
var u = new V[s.GetArrayCount()];
|
||||
int i = 0;
|
||||
foreach (var x in s.ArrayItems())
|
||||
{
|
||||
x.Deserialize(ref u[i++]);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
static List<V> GenericListDeserializer<V>(ListTreeNode<T> s)
|
||||
{
|
||||
if (!s.IsArray())
|
||||
{
|
||||
throw new ArgumentException("not array: " + s.Value.ValueType);
|
||||
}
|
||||
var u = new List<V>(s.GetArrayCount());
|
||||
foreach (var x in s.ArrayItems())
|
||||
{
|
||||
var e = default(V);
|
||||
x.Deserialize(ref e);
|
||||
u.Add(e);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
static object DefaultDictionaryDeserializer(ListTreeNode<T> s)
|
||||
{
|
||||
switch (s.Value.ValueType)
|
||||
{
|
||||
case ValueNodeType.Object:
|
||||
{
|
||||
var u = new Dictionary<string, object>();
|
||||
foreach (var kv in s.ObjectItems())
|
||||
{
|
||||
//var e = default(object);
|
||||
//kv.Value.Deserialize(ref e);
|
||||
u.Add(kv.Key.GetString(), DefaultDictionaryDeserializer(kv.Value));
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
case ValueNodeType.Null:
|
||||
return null;
|
||||
|
||||
case ValueNodeType.Boolean:
|
||||
return s.GetBoolean();
|
||||
|
||||
case ValueNodeType.Integer:
|
||||
return s.GetInt32();
|
||||
|
||||
case ValueNodeType.Number:
|
||||
return s.GetDouble();
|
||||
|
||||
case ValueNodeType.String:
|
||||
return s.GetString();
|
||||
|
||||
default:
|
||||
throw new NotImplementedException(s.Value.ValueType.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize Dictionary only string key
|
||||
/// </summary>
|
||||
/// <typeparam name="V"></typeparam>
|
||||
/// <param name="s"></param>
|
||||
/// <returns></returns>
|
||||
static Dictionary<string, V> DictionaryDeserializer<V>(ListTreeNode<T> s)
|
||||
{
|
||||
var d = new Dictionary<string, V>();
|
||||
foreach (var kv in s.ObjectItems())
|
||||
{
|
||||
var value = default(V);
|
||||
GenericDeserializer<T, V>.Deserialize(kv.Value, ref value);
|
||||
d.Add(kv.Key.GetString(), value);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
delegate void FieldSetter(ListTreeNode<T> s, object o);
|
||||
static FieldSetter GetFieldDeserializer<V>(FieldInfo fi)
|
||||
{
|
||||
return (s, o) =>
|
||||
{
|
||||
var u = default(V);
|
||||
s.Deserialize(ref u);
|
||||
fi.SetValue(o, u);
|
||||
};
|
||||
}
|
||||
|
||||
static Func<ListTreeNode<T>, U> GetDeserializer()
|
||||
{
|
||||
// primitive
|
||||
{
|
||||
var mi = typeof(ListTreeNode<T>).GetMethods().FirstOrDefault(x =>
|
||||
{
|
||||
if (!x.Name.StartsWith("Get"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!x.Name.EndsWith(typeof(U).Name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var parameters = x.GetParameters();
|
||||
if (parameters.Length != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.ReturnType != typeof(U))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (mi != null)
|
||||
{
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(mi);
|
||||
}
|
||||
}
|
||||
|
||||
var target = typeof(U);
|
||||
|
||||
if (target.IsArray)
|
||||
{
|
||||
var mi = typeof(GenericDeserializer<T, U>).GetMethod("GenericArrayDeserializer",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var g = mi.MakeGenericMethod(target.GetElementType());
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(g);
|
||||
}
|
||||
|
||||
if (target.IsGenericType)
|
||||
{
|
||||
if (target.GetGenericTypeDefinition() == typeof(List<>))
|
||||
{
|
||||
var mi = typeof(GenericDeserializer<T, U>).GetMethod("GenericListDeserializer",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var g = mi.MakeGenericMethod(target.GetGenericArguments());
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(g);
|
||||
}
|
||||
|
||||
if (target == typeof(Dictionary<string, object>))
|
||||
{
|
||||
|
||||
var mi = typeof(GenericDeserializer<T, U>).GetMethod("DefaultDictionaryDeserializer",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(mi);
|
||||
}
|
||||
else
|
||||
if (target.GetGenericTypeDefinition() == typeof(Dictionary<,>) &&
|
||||
target.GetGenericArguments()[0] == typeof(string))
|
||||
{
|
||||
var mi = typeof(GenericDeserializer<T, U>).GetMethod("DictionaryDeserializer",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var g = mi.MakeGenericMethod(target.GetGenericArguments()[1]);
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(g);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var schema = JsonSchema.FromType<U>();
|
||||
return s =>
|
||||
{
|
||||
var t = default(U);
|
||||
schema.Validator.Deserialize(s, ref t);
|
||||
return t;
|
||||
};
|
||||
}
|
||||
|
||||
#if false
|
||||
if (target.IsEnum)
|
||||
{
|
||||
var value = Expression.Parameter(typeof(int), "value");
|
||||
var cast = Expression.Convert(value, target);
|
||||
var func = Expression.Lambda(cast, value);
|
||||
var compiled = (Func<int, T>)func.Compile();
|
||||
return s =>
|
||||
{
|
||||
return compiled(s.GetInt32());
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
var fields = target.GetFields(BindingFlags.Instance | BindingFlags.Public);
|
||||
var fieldDeserializers = fields.ToDictionary(x => Utf8String.From(x.Name), x =>
|
||||
{
|
||||
var mi = typeof(GenericDeserializer<S, T>).GetMethod("GetFieldDeserializer",
|
||||
BindingFlags.Static|BindingFlags.NonPublic);
|
||||
var g = mi.MakeGenericMethod(x.FieldType);
|
||||
return (FieldSetter)g.Invoke(null, new object[] { x });
|
||||
});
|
||||
|
||||
return (S s) =>
|
||||
{
|
||||
if (!s.IsMap())
|
||||
{
|
||||
throw new ArgumentException(s.ValueType.ToString());
|
||||
}
|
||||
|
||||
var t = (object)default(GenericCreator<S, T>).Create(s);
|
||||
foreach(var kv in s.ObjectItems())
|
||||
{
|
||||
FieldSetter setter;
|
||||
if (fieldDeserializers.TryGetValue(kv.Key, out setter))
|
||||
{
|
||||
setter(kv.Value, t);
|
||||
}
|
||||
}
|
||||
return (T)t;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public delegate U Deserializer(ListTreeNode<T> node);
|
||||
|
||||
public static Deserializer s_deserializer;
|
||||
|
||||
public static void Deserialize(ListTreeNode<T> node, ref U value)
|
||||
{
|
||||
if (s_deserializer == null)
|
||||
{
|
||||
var d = GetDeserializer();
|
||||
s_deserializer = new Deserializer(d);
|
||||
}
|
||||
value = s_deserializer(node);
|
||||
}
|
||||
|
||||
public static void SetCustomDeserializer(Deserializer deserializer)
|
||||
{
|
||||
s_deserializer = deserializer;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/VRM/UniJSON/Scripts/GenericDeserializer.cs.meta
Normal file
12
Assets/VRM/UniJSON/Scripts/GenericDeserializer.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74625bf2a3d6bc64d9d92b08221a8a3d
|
||||
timeCreated: 1549450914
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -276,7 +276,7 @@ namespace UniJSON
|
||||
public void Deserialize<U, V>(ListTreeNode<U> src, ref V dst)
|
||||
where U : IListTreeItem, IValue<U>
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
src.Deserialize(ref dst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,280 +8,10 @@ namespace UniJSON
|
||||
{
|
||||
public static class ListTreeNodeDeserializerExtensions
|
||||
{
|
||||
struct GenericCreator<T, U>
|
||||
where T : IListTreeItem, IValue<T>
|
||||
{
|
||||
static V[] ArrayCreator<V>(ListTreeNode<T> src)
|
||||
{
|
||||
if (!src.IsArray())
|
||||
{
|
||||
throw new ArgumentException("value is not array");
|
||||
}
|
||||
var count = src.GetArrayCount();
|
||||
return new V[count];
|
||||
}
|
||||
|
||||
static Func<ListTreeNode<T>, U> GetCreator()
|
||||
{
|
||||
var t = typeof(U);
|
||||
if (t.IsArray)
|
||||
{
|
||||
var mi = typeof(GenericCreator<T, U>).GetMethod("ArrayCreator",
|
||||
BindingFlags.NonPublic | BindingFlags.Static);
|
||||
var g = mi.MakeGenericMethod(t.GetElementType());
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(g);
|
||||
}
|
||||
|
||||
{
|
||||
return _s =>
|
||||
{
|
||||
return Activator.CreateInstance<U>();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
delegate U Creator(ListTreeNode<T> src);
|
||||
|
||||
static Creator s_creator;
|
||||
|
||||
public U Create(ListTreeNode<T> src)
|
||||
{
|
||||
if (s_creator == null)
|
||||
{
|
||||
var d = GetCreator();
|
||||
s_creator = new Creator(d);
|
||||
}
|
||||
return s_creator(src);
|
||||
}
|
||||
}
|
||||
|
||||
static object DictionaryDeserializer<T>(ListTreeNode<T> s)
|
||||
where T : IListTreeItem, IValue<T>
|
||||
{
|
||||
switch (s.Value.ValueType)
|
||||
{
|
||||
case ValueNodeType.Object:
|
||||
{
|
||||
var u = new Dictionary<string, object>();
|
||||
foreach (var kv in s.ObjectItems())
|
||||
{
|
||||
//var e = default(object);
|
||||
//kv.Value.Deserialize(ref e);
|
||||
u.Add(kv.Key.GetString(), DictionaryDeserializer(kv.Value));
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
case ValueNodeType.Null:
|
||||
return null;
|
||||
|
||||
case ValueNodeType.Boolean:
|
||||
return s.GetBoolean();
|
||||
|
||||
case ValueNodeType.Integer:
|
||||
return s.GetInt32();
|
||||
|
||||
case ValueNodeType.Number:
|
||||
return s.GetDouble();
|
||||
|
||||
case ValueNodeType.String:
|
||||
return s.GetString();
|
||||
|
||||
default:
|
||||
throw new NotImplementedException(s.Value.ValueType.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void Deserialize<T, U>(this ListTreeNode<T> self, ref U value)
|
||||
where T : IListTreeItem, IValue<T>
|
||||
{
|
||||
GenericDeserializer<T, U>.Deserialize(self, ref value);
|
||||
}
|
||||
}
|
||||
|
||||
public static class GenericDeserializer<T, U>
|
||||
where T : IListTreeItem, IValue<T>
|
||||
{
|
||||
static V[] GenericArrayDeserializer<V>(ListTreeNode<T> s)
|
||||
{
|
||||
if (!s.IsArray())
|
||||
{
|
||||
throw new ArgumentException("not array: " + s.Value.ValueType);
|
||||
}
|
||||
var u = new V[s.GetArrayCount()];
|
||||
int i = 0;
|
||||
foreach (var x in s.ArrayItems())
|
||||
{
|
||||
x.Deserialize(ref u[i++]);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
static List<V> GenericListDeserializer<V>(ListTreeNode<T> s)
|
||||
{
|
||||
if (!s.IsArray())
|
||||
{
|
||||
throw new ArgumentException("not array: " + s.Value.ValueType);
|
||||
}
|
||||
var u = new List<V>(s.GetArrayCount());
|
||||
foreach (var x in s.ArrayItems())
|
||||
{
|
||||
var e = default(V);
|
||||
x.Deserialize(ref e);
|
||||
u.Add(e);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
delegate void FieldSetter(ListTreeNode<T> s, object o);
|
||||
static FieldSetter GetFieldDeserializer<V>(FieldInfo fi)
|
||||
{
|
||||
return (s, o) =>
|
||||
{
|
||||
var u = default(V);
|
||||
s.Deserialize(ref u);
|
||||
fi.SetValue(o, u);
|
||||
};
|
||||
}
|
||||
|
||||
static Func<ListTreeNode<T>, U> GetDeserializer()
|
||||
{
|
||||
// primitive
|
||||
{
|
||||
var mi = typeof(ListTreeNode<T>).GetMethods().FirstOrDefault(x =>
|
||||
{
|
||||
if (!x.Name.StartsWith("Get"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!x.Name.EndsWith(typeof(U).Name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var parameters = x.GetParameters();
|
||||
if (parameters.Length != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.ReturnType != typeof(U))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (mi != null)
|
||||
{
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(mi);
|
||||
}
|
||||
}
|
||||
|
||||
var target = typeof(U);
|
||||
|
||||
if (target.IsArray)
|
||||
{
|
||||
var mi = typeof(GenericDeserializer<T, U>).GetMethod("GenericArrayDeserializer",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var g = mi.MakeGenericMethod(target.GetElementType());
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(g);
|
||||
}
|
||||
|
||||
if (target.IsGenericType)
|
||||
{
|
||||
if (target.GetGenericTypeDefinition() == typeof(List<>))
|
||||
{
|
||||
var mi = typeof(GenericDeserializer<T, U>).GetMethod("GenericListDeserializer",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var g = mi.MakeGenericMethod(target.GetGenericArguments());
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(g);
|
||||
}
|
||||
|
||||
if (target.GetGenericTypeDefinition() == typeof(Dictionary<,>) &&
|
||||
target.GetGenericArguments()[0] == typeof(string))
|
||||
{
|
||||
var mi = typeof(ListTreeNodeDeserializerExtensions).GetMethod("DictionaryDeserializer",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var g = mi.MakeGenericMethod(typeof(T));
|
||||
return GenericInvokeCallFactory.StaticFunc<ListTreeNode<T>, U>(g);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var schema = JsonSchema.FromType<U>();
|
||||
return s =>
|
||||
{
|
||||
var t = default(U);
|
||||
schema.Validator.Deserialize(s, ref t);
|
||||
return t;
|
||||
};
|
||||
}
|
||||
|
||||
#if false
|
||||
if (target.IsEnum)
|
||||
{
|
||||
var value = Expression.Parameter(typeof(int), "value");
|
||||
var cast = Expression.Convert(value, target);
|
||||
var func = Expression.Lambda(cast, value);
|
||||
var compiled = (Func<int, T>)func.Compile();
|
||||
return s =>
|
||||
{
|
||||
return compiled(s.GetInt32());
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
var fields = target.GetFields(BindingFlags.Instance | BindingFlags.Public);
|
||||
var fieldDeserializers = fields.ToDictionary(x => Utf8String.From(x.Name), x =>
|
||||
{
|
||||
var mi = typeof(GenericDeserializer<S, T>).GetMethod("GetFieldDeserializer",
|
||||
BindingFlags.Static|BindingFlags.NonPublic);
|
||||
var g = mi.MakeGenericMethod(x.FieldType);
|
||||
return (FieldSetter)g.Invoke(null, new object[] { x });
|
||||
});
|
||||
|
||||
return (S s) =>
|
||||
{
|
||||
if (!s.IsMap())
|
||||
{
|
||||
throw new ArgumentException(s.ValueType.ToString());
|
||||
}
|
||||
|
||||
var t = (object)default(GenericCreator<S, T>).Create(s);
|
||||
foreach(var kv in s.ObjectItems())
|
||||
{
|
||||
FieldSetter setter;
|
||||
if (fieldDeserializers.TryGetValue(kv.Key, out setter))
|
||||
{
|
||||
setter(kv.Value, t);
|
||||
}
|
||||
}
|
||||
return (T)t;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public delegate U Deserializer(ListTreeNode<T> node);
|
||||
|
||||
public static Deserializer s_deserializer;
|
||||
|
||||
public static void Deserialize(ListTreeNode<T> node, ref U value)
|
||||
{
|
||||
if (s_deserializer == null)
|
||||
{
|
||||
var d = GetDeserializer();
|
||||
s_deserializer = new Deserializer(d);
|
||||
}
|
||||
value = s_deserializer(node);
|
||||
}
|
||||
|
||||
public static void SetCustomDeserializer(Deserializer deserializer)
|
||||
{
|
||||
s_deserializer = deserializer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,10 +219,32 @@ namespace VRM
|
||||
[Test]
|
||||
public void MaterialTest()
|
||||
{
|
||||
var model = new glTF_VRM_Material();
|
||||
var model = new glTF_VRM_Material
|
||||
{
|
||||
floatProperties = new Dictionary<string, float>
|
||||
{
|
||||
{"float", 1.0f}
|
||||
},
|
||||
vectorProperties = new Dictionary<string, float[]>
|
||||
{
|
||||
{"vector", new float[]{0, 1, 2, 3 }}
|
||||
},
|
||||
textureProperties = new Dictionary<string, int>
|
||||
{
|
||||
{"texture", 0}
|
||||
},
|
||||
keywordMap = new Dictionary<string, bool>
|
||||
{
|
||||
{"keyword", true}
|
||||
},
|
||||
tagMap = new Dictionary<string, string>
|
||||
{
|
||||
{"tag", "map"}
|
||||
},
|
||||
};
|
||||
|
||||
var json = model.ToJson();
|
||||
Assert.AreEqual(@"{""renderQueue"":-1,""floatProperties"":{},""vectorProperties"":{},""textureProperties"":{},""keywordMap"":{},""tagMap"":{}}", json);
|
||||
Assert.AreEqual(@"{""renderQueue"":-1,""floatProperties"":{""float"":1},""vectorProperties"":{""vector"":[0,1,2,3]},""textureProperties"":{""texture"":0},""keywordMap"":{""keyword"":true},""tagMap"":{""tag"":""map""}}", json);
|
||||
Debug.Log(json);
|
||||
|
||||
var c = new JsonSchemaValidationContext("")
|
||||
@@ -231,7 +253,12 @@ namespace VRM
|
||||
};
|
||||
var json2 = JsonSchema.FromType<glTF_VRM_Material>().Serialize(model, c);
|
||||
// NOTE: New serializer outputs values which will not be used...
|
||||
Assert.AreEqual(json,json2);
|
||||
Assert.AreEqual(json, json2);
|
||||
|
||||
// deserialize
|
||||
var deserialized = default(glTF_VRM_Material);
|
||||
json.ParseAsJson().Deserialize(ref deserialized);
|
||||
Assert.AreEqual(1, deserialized.floatProperties.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
Reference in New Issue
Block a user