using Jint.Native.Object;
using Jint.Native.Symbol;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;
namespace Jint.Native.FinalizationRegistry;
///
/// https://tc39.es/ecma262/#sec-properties-of-the-finalization-registry-prototype-object
///
internal sealed class FinalizationRegistryPrototype : Prototype
{
private readonly FinalizationRegistryConstructor _constructor;
public FinalizationRegistryPrototype(
Engine engine,
Realm realm,
FinalizationRegistryConstructor constructor,
ObjectPrototype objectPrototype) : base(engine, realm)
{
_constructor = constructor;
_prototype = objectPrototype;
}
protected override void Initialize()
{
const PropertyFlag PropertyFlags = PropertyFlag.NonEnumerable;
var properties = new PropertyDictionary(4, checkExistingKeys: false)
{
[KnownKeys.Constructor] = new PropertyDescriptor(_constructor, PropertyFlag.NonEnumerable),
["register"] = new PropertyDescriptor(new ClrFunction(Engine, "register", Register, 2, PropertyFlag.Configurable), PropertyFlags),
["unregister"] = new PropertyDescriptor(new ClrFunction(Engine, "unregister", Unregister, 1, PropertyFlag.Configurable), PropertyFlags),
};
SetProperties(properties);
var symbols = new SymbolDictionary(1) { [GlobalSymbolRegistry.ToStringTag] = new("FinalizationRegistry", PropertyFlag.Configurable) };
SetSymbols(symbols);
}
///
/// https://tc39.es/ecma262/#sec-finalization-registry.prototype.register
///
private JsValue Register(JsValue thisObject, JsCallArguments arguments)
{
var finalizationRegistry = AssertFinalizationRegistryInstance(thisObject);
var target = arguments.At(0);
var heldValue = arguments.At(1);
var unregisterToken = arguments.At(2);
if (!target.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
{
Throw.TypeError(_realm, "target must be an object or symbol");
}
if (SameValue(target, heldValue))
{
Throw.TypeError(_realm, "target and holdings must not be same");
}
if (!unregisterToken.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
{
if (!unregisterToken.IsUndefined())
{
Throw.TypeError(_realm, unregisterToken + " must be an object");
}
}
var cell = new Cell(target, heldValue, unregisterToken);
finalizationRegistry.AddCell(cell);
return Undefined;
}
///
/// https://tc39.es/ecma262/#sec-finalization-registry.prototype.unregister
///
private JsValue Unregister(JsValue thisObject, JsCallArguments arguments)
{
var finalizationRegistry = AssertFinalizationRegistryInstance(thisObject);
var unregisterToken = arguments.At(0);
if (!unregisterToken.CanBeHeldWeakly(_engine.GlobalSymbolRegistry))
{
Throw.TypeError(_realm, unregisterToken + " must be an object or symbol");
}
return finalizationRegistry.Remove(unregisterToken);
}
private FinalizationRegistryInstance AssertFinalizationRegistryInstance(JsValue thisObject)
{
if (thisObject is FinalizationRegistryInstance finalizationRegistryInstance)
{
return finalizationRegistryInstance;
}
Throw.TypeError(_realm, "object must be a FinalizationRegistry");
return default;
}
}