Support implicit and explicit casting
This commit is contained in:
parent
c1ed9b1eb6
commit
d36d091d28
|
@ -1,133 +1,52 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using PorygonSharp.UserData;
|
using PorygonSharp.UserData;
|
||||||
|
|
||||||
namespace PorygonSharp.ScriptType
|
namespace PorygonSharp.ScriptType
|
||||||
{
|
{
|
||||||
internal static class ScriptType
|
public class ScriptType
|
||||||
{
|
{
|
||||||
internal static IntPtr? GetScriptType(Type t)
|
private readonly IntPtr _ptr;
|
||||||
{
|
|
||||||
if (t.IsEnum && !t.IsGenericParameter)
|
|
||||||
{
|
|
||||||
if (UserDataHandler.IsTypeRegistered(t))
|
|
||||||
return UserDataHandler.CreateUserDataType(t);
|
|
||||||
return CreateNumericScriptType(true, false);
|
|
||||||
}
|
|
||||||
var typeCode = Type.GetTypeCode(t);
|
|
||||||
switch (typeCode)
|
|
||||||
{
|
|
||||||
case TypeCode.Boolean:
|
|
||||||
return CreateScriptType(TypeClass.Bool);
|
|
||||||
case TypeCode.Byte:
|
|
||||||
case TypeCode.SByte:
|
|
||||||
case TypeCode.Int16:
|
|
||||||
case TypeCode.Int32:
|
|
||||||
case TypeCode.Int64:
|
|
||||||
case TypeCode.UInt16:
|
|
||||||
case TypeCode.UInt32:
|
|
||||||
case TypeCode.UInt64:
|
|
||||||
return CreateNumericScriptType(true, false);
|
|
||||||
case TypeCode.Decimal:
|
|
||||||
case TypeCode.Double:
|
|
||||||
case TypeCode.Single:
|
|
||||||
return CreateNumericScriptType(true, true);
|
|
||||||
case TypeCode.Char:
|
|
||||||
case TypeCode.String:
|
|
||||||
return CreateStringScriptType(false, 0);
|
|
||||||
case TypeCode.Object:
|
|
||||||
if (t == typeof(void))
|
|
||||||
{
|
|
||||||
return CreateScriptType(TypeClass.Nil);
|
|
||||||
}
|
|
||||||
if (UserDataHandler.IsTypeRegistered(t))
|
|
||||||
{
|
|
||||||
return UserDataHandler.CreateUserDataType(t);
|
|
||||||
}
|
|
||||||
if (typeof(IList).IsAssignableFrom(t))
|
|
||||||
{
|
|
||||||
return CreateUserDataListType(t);
|
|
||||||
}
|
|
||||||
if (typeof(IDictionary).IsAssignableFrom(t))
|
|
||||||
{
|
|
||||||
return CreateUserDataDictionaryType(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
var attr = t.GetCustomAttribute<Attributes.PorygonUserdataAttribute>();
|
public ScriptType(IntPtr ptr)
|
||||||
if (attr != null)
|
{
|
||||||
{
|
_ptr = ptr;
|
||||||
UserDataHandler.RegisterType(attr.Identifier, t);
|
}
|
||||||
return UserDataHandler.CreateUserDataType(t);
|
|
||||||
}
|
public TypeClass GetTypeClass()
|
||||||
return null;
|
{
|
||||||
|
return GetTypeClass(_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetUserDataType()
|
||||||
|
{
|
||||||
|
return GetScriptTypeUserData(_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Type ResolveType()
|
||||||
|
{
|
||||||
|
var c = GetTypeClass();
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case TypeClass.Number: return typeof(long);
|
||||||
|
case TypeClass.Bool: return typeof(bool);
|
||||||
|
case TypeClass.String: return typeof(string);
|
||||||
|
case TypeClass.UserData:
|
||||||
|
var id = GetUserDataType();
|
||||||
|
var t = UserDataHandler.ReverseLookup[id];
|
||||||
|
return t.Type;
|
||||||
default:
|
default:
|
||||||
return null;
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IntPtr? GetFunctionScriptType(MethodInfo info)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var returnType = GetScriptType(info.ReturnType);
|
|
||||||
if (!returnType.HasValue)
|
|
||||||
return null;
|
|
||||||
var parameters = info.GetParameters();
|
|
||||||
var parameterFuncs = new IntPtr[parameters.Length];
|
|
||||||
for (var index = 0; index < parameters.Length; index++)
|
|
||||||
{
|
|
||||||
var parameter = parameters[index];
|
|
||||||
var parameterType = GetScriptType(parameter.ParameterType);
|
|
||||||
if (!parameterType.HasValue)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
parameterFuncs[index] = parameterType.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreateUserDataFunctionScriptType(returnType.Value, parameterFuncs, parameters.Length);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return IntPtr.Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IntPtr? CreateUserDataListType(Type t)
|
|
||||||
{
|
|
||||||
var keyType = CreateNumericScriptType(true, false);
|
|
||||||
var valType = t.IsArray ? t.GetElementType() : t.GenericTypeArguments[0];
|
|
||||||
var valueType = GetScriptType(valType);
|
|
||||||
if (valueType.HasValue)
|
|
||||||
return CreateCollectionType(keyType, valueType.Value);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IntPtr? CreateUserDataDictionaryType(Type t)
|
|
||||||
{
|
|
||||||
var keyType = GetScriptType(t.GenericTypeArguments[0]);
|
|
||||||
var valueType = GetScriptType(t.GenericTypeArguments[1]);
|
|
||||||
if (keyType.HasValue && valueType.HasValue)
|
|
||||||
return CreateCollectionType(keyType.Value, valueType.Value);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "CreateScriptType", CallingConvention = CallingConvention.Cdecl)]
|
|
||||||
private static extern IntPtr CreateScriptType(TypeClass t);
|
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "CreateNumericScriptType", CallingConvention = CallingConvention.Cdecl)]
|
|
||||||
internal static extern IntPtr CreateNumericScriptType(bool isAware, bool isFloat);
|
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "CreateStringScriptType", CallingConvention = CallingConvention.Cdecl)]
|
|
||||||
private static extern IntPtr CreateStringScriptType(bool knownAtBind, uint hash);
|
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "CreateUserDataFunctionScriptType", CallingConvention = CallingConvention.Cdecl)]
|
|
||||||
private static extern IntPtr CreateUserDataFunctionScriptType(IntPtr returnType, IntPtr[] parameters, int parameterCount);
|
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "CreateCollectionType", CallingConvention = CallingConvention.Cdecl)]
|
|
||||||
private static extern IntPtr CreateCollectionType(IntPtr keyType, IntPtr valueType);
|
[DllImport("PorygonLang", EntryPoint = "GetTypeClass", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern TypeClass GetTypeClass(IntPtr t);
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "GetScriptTypeUserData", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern uint GetScriptTypeUserData(IntPtr t);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using PorygonSharp.UserData;
|
||||||
|
|
||||||
|
namespace PorygonSharp.ScriptType
|
||||||
|
{
|
||||||
|
internal static class ScriptTypeHandler
|
||||||
|
{
|
||||||
|
internal static IntPtr? GetScriptType(Type t)
|
||||||
|
{
|
||||||
|
if (t.IsEnum && !t.IsGenericParameter)
|
||||||
|
{
|
||||||
|
if (UserDataHandler.IsTypeRegistered(t))
|
||||||
|
return UserDataHandler.CreateUserDataType(t);
|
||||||
|
return CreateNumericScriptType(true, false);
|
||||||
|
}
|
||||||
|
var typeCode = Type.GetTypeCode(t);
|
||||||
|
switch (typeCode)
|
||||||
|
{
|
||||||
|
case TypeCode.Boolean:
|
||||||
|
return CreateScriptType(TypeClass.Bool);
|
||||||
|
case TypeCode.Byte:
|
||||||
|
case TypeCode.SByte:
|
||||||
|
case TypeCode.Int16:
|
||||||
|
case TypeCode.Int32:
|
||||||
|
case TypeCode.Int64:
|
||||||
|
case TypeCode.UInt16:
|
||||||
|
case TypeCode.UInt32:
|
||||||
|
case TypeCode.UInt64:
|
||||||
|
return CreateNumericScriptType(true, false);
|
||||||
|
case TypeCode.Decimal:
|
||||||
|
case TypeCode.Double:
|
||||||
|
case TypeCode.Single:
|
||||||
|
return CreateNumericScriptType(true, true);
|
||||||
|
case TypeCode.Char:
|
||||||
|
case TypeCode.String:
|
||||||
|
return CreateStringScriptType(false, 0);
|
||||||
|
case TypeCode.Object:
|
||||||
|
if (t == typeof(void))
|
||||||
|
{
|
||||||
|
return CreateScriptType(TypeClass.Nil);
|
||||||
|
}
|
||||||
|
if (UserDataHandler.IsTypeRegistered(t))
|
||||||
|
{
|
||||||
|
return UserDataHandler.CreateUserDataType(t);
|
||||||
|
}
|
||||||
|
if (typeof(IList).IsAssignableFrom(t))
|
||||||
|
{
|
||||||
|
return CreateUserDataListType(t);
|
||||||
|
}
|
||||||
|
if (typeof(IDictionary).IsAssignableFrom(t))
|
||||||
|
{
|
||||||
|
return CreateUserDataDictionaryType(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
var attr = t.GetCustomAttribute<Attributes.PorygonUserdataAttribute>();
|
||||||
|
if (attr != null)
|
||||||
|
{
|
||||||
|
UserDataHandler.RegisterType(attr.Identifier, t);
|
||||||
|
return UserDataHandler.CreateUserDataType(t);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static IntPtr? GetFunctionScriptType(MethodInfo info)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var returnType = GetScriptType(info.ReturnType);
|
||||||
|
if (!returnType.HasValue)
|
||||||
|
return null;
|
||||||
|
var parameters = info.GetParameters();
|
||||||
|
var parameterFuncs = new IntPtr[parameters.Length];
|
||||||
|
for (var index = 0; index < parameters.Length; index++)
|
||||||
|
{
|
||||||
|
var parameter = parameters[index];
|
||||||
|
var parameterType = GetScriptType(parameter.ParameterType);
|
||||||
|
if (!parameterType.HasValue)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
parameterFuncs[index] = parameterType.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateUserDataFunctionScriptType(returnType.Value, parameterFuncs, parameters.Length);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr? CreateUserDataListType(Type t)
|
||||||
|
{
|
||||||
|
var keyType = CreateNumericScriptType(true, false);
|
||||||
|
var valType = t.IsArray ? t.GetElementType() : t.GenericTypeArguments[0];
|
||||||
|
var valueType = GetScriptType(valType);
|
||||||
|
if (valueType.HasValue)
|
||||||
|
return CreateCollectionType(keyType, valueType.Value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr? CreateUserDataDictionaryType(Type t)
|
||||||
|
{
|
||||||
|
var keyType = GetScriptType(t.GenericTypeArguments[0]);
|
||||||
|
var valueType = GetScriptType(t.GenericTypeArguments[1]);
|
||||||
|
if (keyType.HasValue && valueType.HasValue)
|
||||||
|
return CreateCollectionType(keyType.Value, valueType.Value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "CreateScriptType", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr CreateScriptType(TypeClass t);
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "CreateNumericScriptType", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern IntPtr CreateNumericScriptType(bool isAware, bool isFloat);
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "CreateStringScriptType", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr CreateStringScriptType(bool knownAtBind, uint hash);
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "CreateUserDataFunctionScriptType", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr CreateUserDataFunctionScriptType(IntPtr returnType, IntPtr[] parameters, int parameterCount);
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "CreateCollectionType", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr CreateCollectionType(IntPtr keyType, IntPtr valueType);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using PorygonSharp.EvalValues;
|
using PorygonSharp.EvalValues;
|
||||||
|
using PorygonSharp.HelperLibraries;
|
||||||
using PorygonSharp.Utilities;
|
using PorygonSharp.Utilities;
|
||||||
|
|
||||||
namespace PorygonSharp
|
namespace PorygonSharp
|
||||||
|
@ -10,7 +11,7 @@ namespace PorygonSharp
|
||||||
public static void RegisterStaticVariable(string name, object o)
|
public static void RegisterStaticVariable(string name, object o)
|
||||||
{
|
{
|
||||||
var type = o.GetType();
|
var type = o.GetType();
|
||||||
var scriptType = ScriptType.ScriptType.GetScriptType(type);
|
var scriptType = ScriptType.ScriptTypeHandler.GetScriptType(type);
|
||||||
var hash = name.ScriptHash();
|
var hash = name.ScriptHash();
|
||||||
var value = EvalValueCreator.CreateValue(o);
|
var value = EvalValueCreator.CreateValue(o);
|
||||||
if (!scriptType.HasValue)
|
if (!scriptType.HasValue)
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using PorygonSharp.Utilities;
|
||||||
|
|
||||||
namespace PorygonSharp.UserData
|
namespace PorygonSharp.UserData
|
||||||
{
|
{
|
||||||
|
@ -6,10 +11,155 @@ namespace PorygonSharp.UserData
|
||||||
{
|
{
|
||||||
public readonly Dictionary<uint, UserDataField> Fields = new Dictionary<uint, UserDataField>();
|
public readonly Dictionary<uint, UserDataField> Fields = new Dictionary<uint, UserDataField>();
|
||||||
public uint Id { get; }
|
public uint Id { get; }
|
||||||
|
public Type Type { get; }
|
||||||
|
private readonly Dictionary<Type, MethodInfo> _implicitCasts;
|
||||||
|
private readonly Dictionary<Type, MethodInfo> _explicitCasts;
|
||||||
|
|
||||||
public UserData(uint id)
|
private delegate bool IsCastableDelegate(IntPtr scriptType, bool isExplicit);
|
||||||
|
private delegate IntPtr CastDelegate(IntPtr obj, IntPtr scriptType);
|
||||||
|
|
||||||
|
// ReSharper disable PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
private readonly IsCastableDelegate _isCastableFunc;
|
||||||
|
private readonly CastDelegate _castFunc;
|
||||||
|
// ReSharper restore PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
|
||||||
|
private const BindingFlags BindingFlags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance |
|
||||||
|
System.Reflection.BindingFlags.FlattenHierarchy | System.Reflection.BindingFlags.Static;
|
||||||
|
|
||||||
|
public UserData(uint id, Type type)
|
||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
|
Type = type;
|
||||||
|
|
||||||
|
_implicitCasts = type.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
||||||
|
.Where(mi => string.Equals(mi.Name, "op_Implicit"))
|
||||||
|
.ToDictionary(x => x.ReturnType, x => x);
|
||||||
|
_explicitCasts = type.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
||||||
|
.Where(mi => string.Equals(mi.Name, "op_Explicit"))
|
||||||
|
.ToDictionary(x => x.ReturnType, x => x);
|
||||||
|
|
||||||
|
_isCastableFunc = IsCastable;
|
||||||
|
_castFunc = Cast;
|
||||||
|
|
||||||
|
SetIsCastableFunc(id, Marshal.GetFunctionPointerForDelegate(_isCastableFunc));
|
||||||
|
SetCastFunc(id, Marshal.GetFunctionPointerForDelegate(_castFunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void RegisterFields()
|
||||||
|
{
|
||||||
|
var fields = Type.GetFields(BindingFlags);
|
||||||
|
foreach (var field in fields)
|
||||||
|
{
|
||||||
|
RegisterField(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = Type.GetProperties(BindingFlags);
|
||||||
|
foreach (var property in properties)
|
||||||
|
{
|
||||||
|
RegisterProperty(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
var methods = Type.GetMethods(BindingFlags);
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
RegisterFunction(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterField(FieldInfo field)
|
||||||
|
{
|
||||||
|
var scriptType = ScriptType.ScriptTypeHandler.GetScriptType(field.FieldType);
|
||||||
|
if (!scriptType.HasValue)
|
||||||
|
return;
|
||||||
|
var fieldName = field.Name.ScriptHash();
|
||||||
|
if (Fields.ContainsKey(fieldName))
|
||||||
|
return;
|
||||||
|
var fieldData = new UserDataField(field);
|
||||||
|
var userDataField = CreateUserDataField(scriptType.Value, fieldData.GetGetterPointer(),
|
||||||
|
fieldData.GetSetterPointer());
|
||||||
|
|
||||||
|
RegisterUserDataField(Id, fieldName, userDataField);
|
||||||
|
Fields.Add(fieldName, fieldData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterProperty(PropertyInfo property)
|
||||||
|
{
|
||||||
|
var scriptType = ScriptType.ScriptTypeHandler.GetScriptType(property.PropertyType);
|
||||||
|
if (!scriptType.HasValue)
|
||||||
|
return;
|
||||||
|
var fieldName = property.Name.ScriptHash();
|
||||||
|
if (Fields.ContainsKey(fieldName))
|
||||||
|
return;
|
||||||
|
var fieldData = new UserDataField(property);
|
||||||
|
var userDataField = CreateUserDataField(scriptType.Value, fieldData.GetGetterPointer(),
|
||||||
|
fieldData.GetSetterPointer());
|
||||||
|
|
||||||
|
RegisterUserDataField(Id, fieldName, userDataField);
|
||||||
|
Fields.Add(fieldName, fieldData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterFunction(MethodInfo method)
|
||||||
|
{
|
||||||
|
var type = ScriptType.ScriptTypeHandler.GetFunctionScriptType(method);
|
||||||
|
if (type == IntPtr.Zero || !type.HasValue)
|
||||||
|
return;
|
||||||
|
var fieldName = method.Name.ScriptHash();
|
||||||
|
if (Fields.ContainsKey(fieldName))
|
||||||
|
return;
|
||||||
|
var fieldData = new UserDataField(method);
|
||||||
|
var userDataField = CreateUserDataField(type.Value, fieldData.GetGetterPointer(), IntPtr.Zero);
|
||||||
|
|
||||||
|
RegisterUserDataField(Id, fieldName, userDataField);
|
||||||
|
Fields.Add(fieldName, fieldData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsCastable(IntPtr scriptTypePtr, bool isExplicit)
|
||||||
|
{
|
||||||
|
var scriptType = new ScriptType.ScriptType(scriptTypePtr);
|
||||||
|
var expectedType = scriptType.ResolveType();
|
||||||
|
if (expectedType.IsAssignableFrom(Type))
|
||||||
|
return true;
|
||||||
|
if (_implicitCasts.ContainsKey(expectedType))
|
||||||
|
return true;
|
||||||
|
if (isExplicit && _explicitCasts.ContainsKey(expectedType))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr Cast(IntPtr objPtr, IntPtr typePtr)
|
||||||
|
{
|
||||||
|
var scriptType = new ScriptType.ScriptType(typePtr);
|
||||||
|
var expectedType = scriptType.ResolveType();
|
||||||
|
var obj = GCHandle.FromIntPtr(objPtr).Target;
|
||||||
|
var objType = obj.GetType();
|
||||||
|
if (expectedType.IsAssignableFrom(objType))
|
||||||
|
return objPtr;
|
||||||
|
if (_implicitCasts.TryGetValue(expectedType, out var func))
|
||||||
|
{
|
||||||
|
var castVal = func.Invoke(null, new[] {obj});
|
||||||
|
var handle = GCHandle.Alloc(castVal, GCHandleType.WeakTrackResurrection);
|
||||||
|
return GCHandle.ToIntPtr(handle);
|
||||||
|
}
|
||||||
|
if (_explicitCasts.TryGetValue(expectedType, out func))
|
||||||
|
{
|
||||||
|
var castVal = func.Invoke(null, new[] {obj});
|
||||||
|
var handle = GCHandle.Alloc(castVal, GCHandleType.WeakTrackResurrection);
|
||||||
|
return GCHandle.ToIntPtr(handle);
|
||||||
|
}
|
||||||
|
throw new Exception("Invalid cast kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "RegisterUserDataField", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern void RegisterUserDataField(uint hashId, uint fieldId, IntPtr field);
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "CreateUserDataField", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
internal static extern IntPtr CreateUserDataField(IntPtr type, IntPtr getter, IntPtr setter);
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "SetIsCastableFunc", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern void SetIsCastableFunc(uint id, IntPtr isCastableFunc);
|
||||||
|
|
||||||
|
[DllImport("PorygonLang", EntryPoint = "SetCastFunc", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern void SetCastFunc(uint id, IntPtr castFunc);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using PorygonSharp.Attributes;
|
using PorygonSharp.Attributes;
|
||||||
|
@ -13,7 +11,7 @@ namespace PorygonSharp.UserData
|
||||||
public static class UserDataHandler
|
public static class UserDataHandler
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<Type, UserData> UserDataLookup = new ConcurrentDictionary<Type, UserData>();
|
private static readonly ConcurrentDictionary<Type, UserData> UserDataLookup = new ConcurrentDictionary<Type, UserData>();
|
||||||
private static readonly ConcurrentDictionary<uint, UserData> ReverseLookup = new ConcurrentDictionary<uint, UserData>();
|
internal static readonly ConcurrentDictionary<uint, UserData> ReverseLookup = new ConcurrentDictionary<uint, UserData>();
|
||||||
|
|
||||||
|
|
||||||
public static void RegisterAssembly(Assembly assembly)
|
public static void RegisterAssembly(Assembly assembly)
|
||||||
|
@ -43,29 +41,10 @@ namespace PorygonSharp.UserData
|
||||||
if (UserDataLookup.ContainsKey(type))
|
if (UserDataLookup.ContainsKey(type))
|
||||||
return;
|
return;
|
||||||
RegisterUserDataType(hash);
|
RegisterUserDataType(hash);
|
||||||
var ud = new UserData(hash);
|
var ud = new UserData(hash, type);
|
||||||
UserDataLookup.TryAdd(type, ud);
|
UserDataLookup.TryAdd(type, ud);
|
||||||
ReverseLookup.TryAdd(hash, ud);
|
ReverseLookup.TryAdd(hash, ud);
|
||||||
}
|
ud.RegisterFields();
|
||||||
|
|
||||||
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance |
|
|
||||||
BindingFlags.FlattenHierarchy | BindingFlags.Static;
|
|
||||||
var fields = type.GetFields(bindingFlags);
|
|
||||||
foreach (var field in fields)
|
|
||||||
{
|
|
||||||
RegisterField(field, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
var properties = type.GetProperties(bindingFlags);
|
|
||||||
foreach (var property in properties)
|
|
||||||
{
|
|
||||||
RegisterProperty(property, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
var methods = type.GetMethods(bindingFlags);
|
|
||||||
foreach (var method in methods)
|
|
||||||
{
|
|
||||||
RegisterFunction(method, hash);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +56,7 @@ namespace PorygonSharp.UserData
|
||||||
if (UserDataLookup.ContainsKey(type))
|
if (UserDataLookup.ContainsKey(type))
|
||||||
return;
|
return;
|
||||||
RegisterUserDataType(hash);
|
RegisterUserDataType(hash);
|
||||||
var ud = new UserData(hash);
|
var ud = new UserData(hash, type);
|
||||||
UserDataLookup.TryAdd(type, ud);
|
UserDataLookup.TryAdd(type, ud);
|
||||||
ReverseLookup.TryAdd(hash, ud);
|
ReverseLookup.TryAdd(hash, ud);
|
||||||
}
|
}
|
||||||
|
@ -88,67 +67,14 @@ namespace PorygonSharp.UserData
|
||||||
var fieldData = new UserDataField(getter, null);
|
var fieldData = new UserDataField(getter, null);
|
||||||
var valueName = Enum.GetName(type, value);
|
var valueName = Enum.GetName(type, value);
|
||||||
var fieldName = valueName.ScriptHash();
|
var fieldName = valueName.ScriptHash();
|
||||||
var t = ScriptType.ScriptType.CreateNumericScriptType(true, false);
|
var t = ScriptType.ScriptTypeHandler.CreateNumericScriptType(true, false);
|
||||||
RegisterUserDataField(hash, fieldName,
|
UserData.RegisterUserDataField(hash, fieldName,
|
||||||
CreateUserDataField(t, fieldData.GetGetterPointer(), IntPtr.Zero));
|
UserData.CreateUserDataField(t, fieldData.GetGetterPointer(), IntPtr.Zero));
|
||||||
ReverseLookup[hash].Fields[fieldName] = fieldData;
|
ReverseLookup[hash].Fields[fieldName] = fieldData;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RegisterField(FieldInfo field, uint typeHash)
|
|
||||||
{
|
|
||||||
var scriptType = ScriptType.ScriptType.GetScriptType(field.FieldType);
|
|
||||||
if (!scriptType.HasValue)
|
|
||||||
return;
|
|
||||||
if (!ReverseLookup.TryGetValue(typeHash, out var userData))
|
|
||||||
return;
|
|
||||||
var fieldName = field.Name.ScriptHash();
|
|
||||||
if (userData.Fields.ContainsKey(fieldName))
|
|
||||||
return;
|
|
||||||
var fieldData = new UserDataField(field);
|
|
||||||
var userDataField = CreateUserDataField(scriptType.Value, fieldData.GetGetterPointer(),
|
|
||||||
fieldData.GetSetterPointer());
|
|
||||||
|
|
||||||
RegisterUserDataField(typeHash, fieldName, userDataField);
|
|
||||||
userData.Fields.Add(fieldName, fieldData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RegisterProperty(PropertyInfo property, uint typeHash)
|
|
||||||
{
|
|
||||||
var scriptType = ScriptType.ScriptType.GetScriptType(property.PropertyType);
|
|
||||||
if (!scriptType.HasValue)
|
|
||||||
return;
|
|
||||||
if (!ReverseLookup.TryGetValue(typeHash, out var userData))
|
|
||||||
return;
|
|
||||||
var fieldName = property.Name.ScriptHash();
|
|
||||||
if (userData.Fields.ContainsKey(fieldName))
|
|
||||||
return;
|
|
||||||
var fieldData = new UserDataField(property);
|
|
||||||
var userDataField = CreateUserDataField(scriptType.Value, fieldData.GetGetterPointer(),
|
|
||||||
fieldData.GetSetterPointer());
|
|
||||||
|
|
||||||
RegisterUserDataField(typeHash, fieldName, userDataField);
|
|
||||||
userData.Fields.Add(fieldName, fieldData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RegisterFunction(MethodInfo method, uint typeHash)
|
|
||||||
{
|
|
||||||
|
|
||||||
var type = ScriptType.ScriptType.GetFunctionScriptType(method);
|
|
||||||
if (type == IntPtr.Zero || !type.HasValue)
|
|
||||||
return;
|
|
||||||
if (!ReverseLookup.TryGetValue(typeHash, out var userData))
|
|
||||||
return;
|
|
||||||
var fieldName = method.Name.ScriptHash();
|
|
||||||
if (userData.Fields.ContainsKey(fieldName))
|
|
||||||
return;
|
|
||||||
var fieldData = new UserDataField(method);
|
|
||||||
var userDataField = CreateUserDataField(type.Value, fieldData.GetGetterPointer(), IntPtr.Zero);
|
|
||||||
|
|
||||||
RegisterUserDataField(typeHash, fieldName, userDataField);
|
|
||||||
userData.Fields.Add(fieldName, fieldData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint GetTypeId(Type t)
|
public static uint GetTypeId(Type t)
|
||||||
{
|
{
|
||||||
|
@ -188,12 +114,6 @@ namespace PorygonSharp.UserData
|
||||||
[DllImport("PorygonLang", EntryPoint = "RegisterUserDataType", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("PorygonLang", EntryPoint = "RegisterUserDataType", CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern void RegisterUserDataType(uint hashId);
|
private static extern void RegisterUserDataType(uint hashId);
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "RegisterUserDataField", CallingConvention = CallingConvention.Cdecl)]
|
|
||||||
private static extern void RegisterUserDataField(uint hashId, uint fieldId, IntPtr field);
|
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "CreateUserDataField", CallingConvention = CallingConvention.Cdecl)]
|
|
||||||
private static extern IntPtr CreateUserDataField(IntPtr type, IntPtr getter, IntPtr setter);
|
|
||||||
|
|
||||||
[DllImport("PorygonLang", EntryPoint = "GetUserDataFieldCount", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("PorygonLang", EntryPoint = "GetUserDataFieldCount", CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern int GetUserDataFieldCount(uint hashId);
|
private static extern int GetUserDataFieldCount(uint hashId);
|
||||||
|
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue