PorygonSharp/PorygonSharp/UserData/UserDataFunctionField.cs

65 lines
2.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using PorygonSharp.EvalValues;
using PorygonSharp.Utilities;
namespace PorygonSharp.UserData
{
internal class UserDataFunctionField : UserDataField
{
public readonly IntPtr MethodPtr;
private readonly List<CallerDelegate> _callers;
public UserDataFunctionField(MethodInfo method, IntPtr methodPtr)
{
_getter = ptr =>
{
var funcPtr = Marshal.GetFunctionPointerForDelegate(_callers[0]);
var val = EvalValueCreator.FunctionEvalValue(funcPtr, ptr);
for (var i = 1; i < _callers.Count; i++)
{
funcPtr = Marshal.GetFunctionPointerForDelegate(_callers[i]);
RegisterFunctionEvalValueOption(val.GetPointer(), funcPtr, ptr);
}
return val.GetPointer();
};
MethodPtr = methodPtr;
_callers = new List<CallerDelegate>(){CreateCaller(method)};
}
private CallerDelegate CreateCaller(MethodInfo method)
{
var parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray();
return (parent, scriptOptions, parameters, size) =>
{
var evaluatedParameters = new object[size];
for (var i = 0; i < size; i++)
{
var eval = new EvalValue(parameters[i]);
evaluatedParameters[i] = Caster.Cast(eval, parameterTypes[i]);
}
var parentObj = GCHandle.FromIntPtr(parent).Target;
try
{
var result = method.Invoke(parentObj, evaluatedParameters);
return new UserDataReturnValue(EvalValueCreator.CreateValue(result)).GetPointer();
}
catch (Exception e)
{
return new UserDataReturnValue(e.ToString()).GetPointer();
}
};
}
internal void RegisterOption(MethodInfo method)
{
_callers.Add(CreateCaller(method));
}
[DllImport("PorygonLang", EntryPoint = "RegisterFunctionEvalValueOption",CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr RegisterFunctionEvalValueOption(IntPtr val, IntPtr func, IntPtr obj);
}
}