using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using Jint.Native;
using Jint.Native.Function;
using Jint.Runtime.Descriptors;
namespace Jint.Runtime.Interop;
///
/// Wraps a CLR method into a JS function.
///
public sealed class ClrFunction : Function, IEquatable
{
internal readonly JsCallDelegate _func;
private readonly bool _bubbleExceptions;
public ClrFunction(
Engine engine,
string name,
JsCallDelegate func,
int length = 0,
PropertyFlag lengthFlags = PropertyFlag.AllForbidden)
: base(engine, engine.Realm, JsString.CachedCreate(name))
{
_func = func;
_prototype = engine._originalIntrinsics.Function.PrototypeObject;
_length = lengthFlags == PropertyFlag.AllForbidden
? PropertyDescriptor.AllForbiddenDescriptor.ForNumber(length)
: new PropertyDescriptor(JsNumber.Create(length), lengthFlags);
_bubbleExceptions = _engine.Options.Interop.ExceptionHandler == Options.InteropOptions._defaultExceptionHandler;
}
protected internal override JsValue Call(JsValue thisObject, JsCallArguments arguments) => _bubbleExceptions ? _func(thisObject, arguments) : CallSlow(thisObject, arguments);
[MethodImpl(MethodImplOptions.NoInlining)]
private JsValue CallSlow(JsValue thisObject, JsCallArguments arguments)
{
try
{
return _func(thisObject, arguments);
}
catch (Exception e) when (e is not JavaScriptException)
{
if (_engine.Options.Interop.ExceptionHandler(e))
{
Throw.JavaScriptException(_realm.Intrinsics.Error, e.Message);
}
else
{
ExceptionDispatchInfo.Capture(e).Throw();
}
return Undefined;
}
}
public override bool Equals(JsValue? other) => Equals(other as ClrFunction);
public override bool Equals(object? obj) => Equals(obj as ClrFunction);
public bool Equals(ClrFunction? other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
if (_func == other._func)
{
return true;
}
return false;
}
public override int GetHashCode() => _func.GetHashCode();
}