using Jint.Native.Object;
using Jint.Runtime;
namespace Jint.Native.Function;
///
/// https://tc39.es/ecma262/#sec-bound-function-exotic-objects
///
public sealed class BindFunction : ObjectInstance, IConstructor, ICallable
{
private readonly Realm _realm;
public BindFunction(Engine engine,
Realm realm,
ObjectInstance? proto,
ObjectInstance targetFunction,
JsValue boundThis,
JsValue[] boundArgs)
: base(engine, ObjectClass.Function)
{
_realm = realm;
_prototype = proto;
BoundTargetFunction = targetFunction;
BoundThis = boundThis;
BoundArguments = boundArgs;
}
///
/// The wrapped function object.
///
public JsValue BoundTargetFunction { get; }
///
/// The value that is always passed as the this value when calling the wrapped function.
///
public JsValue BoundThis { get; }
///
/// A list of values whose elements are used as the first arguments to any call to the wrapped function.
///
public JsValue[] BoundArguments { get; }
JsValue ICallable.Call(JsValue thisObject, params JsCallArguments arguments)
{
var f = BoundTargetFunction as Function;
if (f is null)
{
Throw.TypeError(_realm);
}
var args = CreateArguments(arguments);
var value = f.Call(BoundThis, args);
_engine._jsValueArrayPool.ReturnArray(args);
return value;
}
ObjectInstance IConstructor.Construct(JsCallArguments arguments, JsValue newTarget)
{
var target = BoundTargetFunction as IConstructor;
if (target is null)
{
Throw.TypeError(_realm);
}
var args = CreateArguments(arguments);
if (ReferenceEquals(this, newTarget))
{
newTarget = BoundTargetFunction;
}
var value = target.Construct(args, newTarget);
_engine._jsValueArrayPool.ReturnArray(args);
return value;
}
internal override bool OrdinaryHasInstance(JsValue v)
{
var f = BoundTargetFunction as Function;
if (f is null)
{
Throw.TypeError(_realm);
}
return f.OrdinaryHasInstance(v);
}
private JsValue[] CreateArguments(JsCallArguments arguments)
{
var combined = _engine._jsValueArrayPool.RentArray(BoundArguments.Length + arguments.Length);
System.Array.Copy(BoundArguments, combined, BoundArguments.Length);
System.Array.Copy(arguments, 0, combined, BoundArguments.Length, arguments.Length);
return combined;
}
internal override bool IsConstructor => BoundTargetFunction.IsConstructor;
public override string ToString() => "function () { [native code] }";
}