using Jint.Collections;
using Jint.Native.Function;
using Jint.Native.Object;
using Jint.Native.Symbol;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;
namespace Jint.Native.ArrayBuffer;
///
/// https://tc39.es/ecma262/#sec-properties-of-the-arraybuffer-constructor
///
internal sealed class ArrayBufferConstructor : Constructor
{
private static readonly JsString _functionName = new("ArrayBuffer");
internal ArrayBufferConstructor(
Engine engine,
Realm realm,
FunctionPrototype functionPrototype,
ObjectPrototype objectPrototype)
: base(engine, realm, _functionName)
{
_prototype = functionPrototype;
PrototypeObject = new ArrayBufferPrototype(engine, this, objectPrototype);
_length = new PropertyDescriptor(1, PropertyFlag.Configurable);
_prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
}
private ArrayBufferPrototype PrototypeObject { get; }
protected override void Initialize()
{
const PropertyFlag lengthFlags = PropertyFlag.Configurable;
var properties = new PropertyDictionary(1, checkExistingKeys: false)
{
["isView"] = new PropertyDescriptor(new PropertyDescriptor(new ClrFunction(Engine, "isView", IsView, 1, lengthFlags), PropertyFlag.Configurable | PropertyFlag.Writable)),
};
SetProperties(properties);
var symbols = new SymbolDictionary(1)
{
[GlobalSymbolRegistry.Species] = new GetSetPropertyDescriptor(get: new ClrFunction(Engine, "get [Symbol.species]", Species, 0, lengthFlags), set: Undefined,PropertyFlag.Configurable),
};
SetSymbols(symbols);
}
///
/// https://tc39.es/ecma262/#sec-arraybuffer.isview
///
private static JsValue IsView(JsValue thisObject, JsValue[] arguments)
{
var arg = arguments.At(0);
return arg is JsDataView or JsTypedArray;
}
///
/// https://tc39.es/ecma262/#sec-get-arraybuffer-@@species
///
private static JsValue Species(JsValue thisObject, JsValue[] arguments)
{
return thisObject;
}
public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
{
if (newTarget.IsUndefined())
{
ExceptionHelper.ThrowTypeError(_realm);
}
var length = arguments.At(0);
var options = arguments.At(1);
var byteLength = TypeConverter.ToIndex(_realm, length);
var requestedMaxByteLength = options.GetArrayBufferMaxByteLengthOption();
return AllocateArrayBuffer(newTarget, byteLength, requestedMaxByteLength);
}
///
/// https://tc39.es/ecma262/#sec-allocatearraybuffer
///
internal JsArrayBuffer AllocateArrayBuffer(JsValue constructor, ulong byteLength, uint? maxByteLength = null)
{
var allocatingResizableBuffer = maxByteLength != null;
if (allocatingResizableBuffer && byteLength > maxByteLength)
{
ExceptionHelper.ThrowRangeError(_realm);
}
var obj = OrdinaryCreateFromConstructor(
constructor,
static intrinsics => intrinsics.ArrayBuffer.PrototypeObject,
static (engine, _, state) => new JsArrayBuffer(engine, state!.Item1),
new Tuple(maxByteLength));
var block = byteLength > 0 ? JsArrayBuffer.CreateByteDataBlock(_realm, byteLength) : System.Array.Empty();
obj._arrayBufferData = block;
return obj;
}
}