diff --git a/node-zigar-addon/src/addon.js.txt b/node-zigar-addon/src/addon.js.txt index 59b5eb86..f440df8f 100644 --- a/node-zigar-addon/src/addon.js.txt +++ b/node-zigar-addon/src/addon.js.txt @@ -5,8 +5,8 @@ " const SLOTS = Symbol('slots');\n" " const PARENT = Symbol('parent');\n" " const NAME = Symbol('name');\n" +" const CLASS = Symbol('class');\n" " const TAG = Symbol('tag');\n" -" const ITEMS = Symbol('items');\n" " const PROPS = Symbol('props');\n" " const GETTER = Symbol('getter');\n" " const SETTER = Symbol('setter');\n" @@ -426,12 +426,12 @@ " const process = function(value) {\n" " const normalizer = value?.[NORMALIZER];\n" " if (normalizer) {\n" -" if (value instanceof Error) {\n" -" return { error: value.message };\n" -" } \n" " let result = map.get(value);\n" " if (result === undefined) {\n" " result = normalizer.call(value, process, options);\n" +" if (typeof(result?.toJSON) === 'function') {\n" +" result = result.toJSON();\n" +" } \n" " map.set(value, result);\n" " }\n" " return result;\n" @@ -1322,9 +1322,7 @@ " members: [ member ],\n" " },\n" " } = structure;\n" -" const { get: getIndex, set: setIndex } = getDescriptor(member, env);\n" -" // get the enum descriptor instead of the int/uint descriptor\n" -" const { get, set } = getDescriptor({ ...member, type: MemberType.EnumerationItem, structure }, env);\n" +" const { get, set } = getDescriptor(member, env);\n" " const expected = [ 'string', 'number', 'tagged union' ];\n" " const propApplier = createPropertyApplier(structure);\n" " const initializer = function(arg) {\n" @@ -1338,17 +1336,19 @@ " };\n" " const alternateCaster = function(arg) {\n" " if (typeof(arg) === 'string' || typeof(arg) === 'number' || typeof(arg) === 'bigint') {\n" -" const items = constructor[ITEMS];\n" -" let item = items[arg];\n" +" let item = constructor[arg];\n" " if (!item) {\n" " if (constructor[MORE] && typeof(arg) !== 'string') {\n" " // create the item on-the-fly when enum is non-exhaustive\n" -" item = items[arg] = new constructor(undefined); \n" -" setIndex.call(item, arg);\n" -" defineProperties(item, { [NAME]: { value: `${arg}` } });\n" +" item = new constructor(undefined);\n" +" debugger; \n" +" set.call(item, arg, 'number');\n" +" appendEnumeration(constructor, `${arg}`, item);\n" " }\n" " }\n" " return item;\n" +" } else if (arg instanceof constructor) {\n" +" return arg;\n" " } else if (arg?.[TAG] instanceof constructor) {\n" " // a tagged union, return the active tag\n" " return arg[TAG];\n" @@ -1361,7 +1361,7 @@ " const constructor = structure.constructor = createConstructor(structure, { initializer, alternateCaster }, env);\n" " const typedArray = structure.typedArray = getTypedArrayClass(member);\n" " const toPrimitive = function(hint) {\n" -" return (hint === 'string') ? this.$[NAME] : getIndex.call(this);\n" +" return (hint === 'string') ? this.$[NAME] : get.call(this, 'number');\n" " };\n" " const instanceDescriptors = {\n" " $: { get, set },\n" @@ -1378,7 +1378,6 @@ " const staticDescriptors = {\n" " [ALIGN]: { value: align },\n" " [SIZE]: { value: byteSize },\n" -" [ITEMS]: { value: {} },\n" " };\n" " return attachDescriptors(constructor, instanceDescriptors, staticDescriptors);\n" " }\n" @@ -1386,6 +1385,25 @@ " return cb(this.$[NAME]);\n" " }\n" "\n" +" function appendEnumeration(enumeration, name, item) {\n" +" if (name !== undefined) {\n" +" // enum can have static variables \n" +" if (item instanceof enumeration) {\n" +" // attach name to item so tagged union code can quickly find it\n" +" defineProperties(item, { [NAME]: { value: name } }); \n" +" // call toPrimitive directly since enum can be bigint or number\n" +" const index = item[Symbol.toPrimitive]();\n" +" defineProperties(enumeration, {\n" +" [index]: { value: item },\n" +" [name]: { value: item },\n" +" }); \n" +" }\n" +" } else {\n" +" // non-exhaustive enum\n" +" defineProperties(enumeration, { [MORE]: { value: true } });\n" +" }\n" +" }\n" +"\n" " function defineErrorUnion(structure, env) {\n" " const {\n" " byteSize,\n" @@ -1396,18 +1414,17 @@ " const { get: getValue, set: setValue } = getDescriptor(members[0], env);\n" " const { get: getError, set: setError } = getDescriptor(members[1], env);\n" " const get = function() {\n" -" const error = getError.call(this, true);\n" -" if (error) {\n" -" throw error;\n" +" const errNum = getError.call(this, 'number');\n" +" if (errNum) {\n" +" throw getError.call(this);\n" " } else {\n" " return getValue.call(this);\n" " }\n" " };\n" " const isValueVoid = members[0].type === MemberType.Void;\n" -" const acceptAny = members[1].structure.name === 'anyerror';\n" -" const TargetError = (acceptAny) ? getGlobalErrorSet() : members[1].structure.constructor;\n" +" const errorSet = members[1].structure.constructor;\n" " const isChildActive = function() {\n" -" return !getError.call(this, true);\n" +" return !getError.call(this, 'number');\n" " };\n" " const clearValue = function() {\n" " this[RESETTER]();\n" @@ -1423,33 +1440,26 @@ " this[POINTER_VISITOR](copyPointer, { vivificate: true, source: arg });\n" " }\n" " }\n" -" } else if (arg instanceof TargetError) {\n" +" } else if (arg instanceof errorSet[CLASS] && errorSet(arg)) {\n" " setError.call(this, arg);\n" " clearValue.call(this);\n" " } else if (arg !== undefined || isValueVoid) {\n" " try {\n" " // call setValue() first, in case it throws\n" " setValue.call(this, arg);\n" -" setError.call(this, 0, true);\n" +" setError.call(this, 0, 'number');\n" " } catch (err) {\n" " if (arg instanceof Error) {\n" " // we give setValue a chance to see if the error is actually an acceptable value\n" " // now is time to throw an error\n" " throwNotInErrorSet(structure);\n" +" } else if (isErrorJSON(arg)) {\n" +" setError.call(this, arg);\n" +" clearValue.call(this);\n" " } else if (arg && typeof(arg) === 'object') {\n" -" try {\n" -" if (propApplier.call(this, arg) === 0) {\n" -" throw err;\n" -" }\n" -" } catch (err) {\n" -" const { error } = arg;\n" -" if (typeof(error) === 'string') {\n" -" setError.call(this, error);\n" -" clearValue.call(this);\n" -" } else {\n" -" throw err;\n" -" } \n" -" } \n" +" if (propApplier.call(this, arg) === 0) {\n" +" throw err;\n" +" }\n" " } else {\n" " throw err;\n" " }\n" @@ -1585,86 +1595,6 @@ " return attachDescriptors(constructor, instanceDescriptors, staticDescriptors);\n" " }\n" "\n" -" function definePrimitive(structure, env) {\n" -" const {\n" -" byteSize,\n" -" align,\n" -" instance: { members: [ member ] },\n" -" } = structure;\n" -" const { get, set } = getDescriptor(member, env);\n" -" const propApplier = createPropertyApplier(structure);\n" -" const initializer = function(arg) {\n" -" if (arg instanceof constructor) {\n" -" this[COPIER](arg);\n" -" } else {\n" -" if (arg && typeof(arg) === 'object') {\n" -" if (propApplier.call(this, arg) === 0) {\n" -" const type = getPrimitiveType(member);\n" -" throwInvalidInitializer(structure, type, arg);\n" -" }\n" -" } else if (arg !== undefined) {\n" -" set.call(this, arg);\n" -" }\n" -" }\n" -" };\n" -" const constructor = structure.constructor = createConstructor(structure, { initializer }, env);\n" -" const typedArray = structure.typedArray = getTypedArrayClass(member);\n" -" const instanceDescriptors = {\n" -" $: { get, set },\n" -" dataView: getDataViewDescriptor(structure),\n" -" base64: getBase64Descriptor(structure),\n" -" typedArray: typedArray && getTypedArrayDescriptor(structure),\n" -" valueOf: { value: getValueOf },\n" -" toJSON: { value: convertToJSON },\n" -" delete: { value: getDestructor(env) },\n" -" [Symbol.toPrimitive]: { value: get },\n" -" [COPIER]: { value: getMemoryCopier(byteSize) },\n" -" [NORMALIZER]: { value: normalizeValue },\n" -" };\n" -" const staticDescriptors = {\n" -" [COMPAT]: { value: getCompatibleTags(structure) },\n" -" [ALIGN]: { value: align },\n" -" [SIZE]: { value: byteSize },\n" -" };\n" -" return attachDescriptors(constructor, instanceDescriptors, staticDescriptors);\n" -" }\n" -" function getIntRange(member) {\n" -" const { type, bitSize } = member;\n" -" const signed = (type === MemberType.Int);\n" -" let magBits = (signed) ? bitSize - 1 : bitSize;\n" -" if (bitSize <= 32) {\n" -" const max = 2 ** magBits - 1;\n" -" const min = (signed) ? -(2 ** magBits) : 0;\n" -" return { min, max };\n" -" } else {\n" -" magBits = BigInt(magBits);\n" -" const max = 2n ** magBits - 1n;\n" -" const min = (signed) ? -(2n ** magBits) : 0n;\n" -" return { min, max };\n" -" }\n" -" }\n" -"\n" -" function getPrimitiveClass({ type, bitSize }) {\n" -" if (type === MemberType.Int || type === MemberType.Uint) {\n" -" if (bitSize <= 32) {\n" -" return Number;\n" -" } else {\n" -" return BigInt;\n" -" }\n" -" } else if (type === MemberType.Float) {\n" -" return Number;\n" -" } else if (type === MemberType.Bool) {\n" -" return Boolean;\n" -" }\n" -" }\n" -"\n" -" function getPrimitiveType(member) {\n" -" const Primitive = getPrimitiveClass(member);\n" -" if (Primitive) {\n" -" return typeof(Primitive(0));\n" -" }\n" -" }\n" -"\n" " function defineSlice(structure, env) {\n" " const {\n" " align,\n" @@ -2204,10 +2134,12 @@ "\n" " function useErrorSet() {\n" " factories$2[StructureType.ErrorSet] = defineErrorSet;\n" +" useErrorSetTransform();\n" " }\n" "\n" " function useEnumeration() {\n" " factories$2[StructureType.Enumeration] = defineEnumerationShape;\n" +" useEnumerationTransform();\n" " }\n" "\n" " function useOptional() {\n" @@ -2216,6 +2148,7 @@ "\n" " function usePointer() {\n" " factories$2[StructureType.Pointer] = definePointer;\n" +" useUint();\n" " }\n" "\n" " function useSlice() {\n" @@ -2550,88 +2483,84 @@ " }\n" " }\n" "\n" -" function defineErrorSet(structure, env) {\n" +" function definePrimitive(structure, env) {\n" " const {\n" " byteSize,\n" " align,\n" " instance: { members: [ member ] },\n" " } = structure;\n" -" const { get: getIndex } = getDescriptor(member, env);\n" -" // get the error descriptor instead of the int/uint descriptor\n" -" const { get, set } = getDescriptor({ ...member, type: MemberType.Error, structure }, env);\n" -" const expected = [ 'string', 'number' ];\n" +" const { get, set } = getDescriptor(member, env);\n" " const propApplier = createPropertyApplier(structure);\n" " const initializer = function(arg) {\n" -" if (arg && typeof(arg) === 'object') {\n" -" try {\n" +" if (arg instanceof constructor) {\n" +" this[COPIER](arg);\n" +" } else {\n" +" if (arg && typeof(arg) === 'object') {\n" " if (propApplier.call(this, arg) === 0) {\n" -" throwInvalidInitializer(structure, expected, arg);\n" -" } \n" -" } catch (err) {\n" -" const { error } = arg;\n" -" if (typeof(error) === 'string') {\n" -" set.call(this, error);\n" -" } else {\n" -" throw err;\n" +" const type = getPrimitiveType(member);\n" +" throwInvalidInitializer(structure, type, arg);\n" " }\n" +" } else if (arg !== undefined) {\n" +" set.call(this, arg);\n" " }\n" -" } else if (arg !== undefined) {\n" -" set.call(this, arg);\n" -" }\n" -" };\n" -" const alternateCaster = function(arg) {\n" -" if (typeof(arg) === 'number' || typeof(arg) === 'string') {\n" -" return constructor[ITEMS][arg];\n" -" } else if (!getDataView(structure, arg, env)) {\n" -" throwInvalidInitializer(structure, expected, arg);\n" -" } else {\n" -" return false;\n" " }\n" " };\n" -" const constructor = structure.constructor = createConstructor(structure, { initializer, alternateCaster }, env);\n" -" Object.setPrototypeOf(constructor.prototype, globalErrorSet.prototype);\n" +" const constructor = structure.constructor = createConstructor(structure, { initializer }, env);\n" " const typedArray = structure.typedArray = getTypedArrayClass(member);\n" -" const getMessage = function() { return this.$.message; };\n" -" const toStringTag = function() { return 'Error' };\n" -" const toPrimitive = function(hint) {\n" -" if (hint === 'string') {\n" -" return Error.prototype.toString.call(this, hint);\n" -" } else {\n" -" return getIndex.call(this);\n" -" }\n" -" };\n" " const instanceDescriptors = {\n" " $: { get, set },\n" -" message: { get: getMessage },\n" " dataView: getDataViewDescriptor(structure),\n" " base64: getBase64Descriptor(structure),\n" " typedArray: typedArray && getTypedArrayDescriptor(structure),\n" " valueOf: { value: getValueOf },\n" " toJSON: { value: convertToJSON },\n" " delete: { value: getDestructor(env) },\n" -" // ensure that libraries that rely on the string tag for type detection will\n" -" // correctly identify the object as an error\n" -" [Symbol.toStringTag]: { get: toStringTag },\n" -" [Symbol.toPrimitive]: { value: toPrimitive },\n" +" [Symbol.toPrimitive]: { value: get },\n" " [COPIER]: { value: getMemoryCopier(byteSize) },\n" -" [NORMALIZER]: { value: get },\n" +" [NORMALIZER]: { value: normalizeValue },\n" " };\n" " const staticDescriptors = {\n" +" [COMPAT]: { value: getCompatibleTags(structure) },\n" " [ALIGN]: { value: align },\n" " [SIZE]: { value: byteSize },\n" -" [ITEMS]: { value: {} },\n" " };\n" " return attachDescriptors(constructor, instanceDescriptors, staticDescriptors);\n" " }\n" -" let globalErrorSet;\n" +" function getIntRange(member) {\n" +" const { type, bitSize } = member;\n" +" const signed = (type === MemberType.Int);\n" +" let magBits = (signed) ? bitSize - 1 : bitSize;\n" +" if (bitSize <= 32) {\n" +" const max = 2 ** magBits - 1;\n" +" const min = (signed) ? -(2 ** magBits) : 0;\n" +" return { min, max };\n" +" } else {\n" +" magBits = BigInt(magBits);\n" +" const max = 2n ** magBits - 1n;\n" +" const min = (signed) ? -(2n ** magBits) : 0n;\n" +" return { min, max };\n" +" }\n" +" }\n" "\n" -" function createGlobalErrorSet() {\n" -" globalErrorSet = function() {};\n" -" Object.setPrototypeOf(globalErrorSet.prototype, Error.prototype);\n" +" function getPrimitiveClass({ type, bitSize }) {\n" +" if (type === MemberType.Int || type === MemberType.Uint) {\n" +" if (bitSize <= 32) {\n" +" return Number;\n" +" } else {\n" +" return BigInt;\n" +" }\n" +" } else if (type === MemberType.Float) {\n" +" return Number;\n" +" } else if (type === MemberType.Bool) {\n" +" return Boolean;\n" +" }\n" " }\n" "\n" -" function getGlobalErrorSet() {\n" -" return globalErrorSet;\n" +" function getPrimitiveType(member) {\n" +" const Primitive = getPrimitiveClass(member);\n" +" if (Primitive) {\n" +" return typeof(Primitive(0));\n" +" }\n" " }\n" "\n" " const MemberType = {\n" @@ -2640,15 +2569,13 @@ " Int: 2,\n" " Uint: 3,\n" " Float: 4,\n" -" EnumerationItem: 5,\n" -" Error: 6,\n" -" Object: 7,\n" -" Type: 8,\n" -" Comptime: 9,\n" -" Static: 10,\n" -" Literal: 11,\n" -" Null: 12,\n" -" Undefined: 13,\n" +" Object: 5,\n" +" Type: 6,\n" +" Comptime: 7,\n" +" Static: 8,\n" +" Literal: 9,\n" +" Null: 10,\n" +" Undefined: 11,\n" " };\n" "\n" " function isReadOnly(type) {\n" @@ -2684,14 +2611,6 @@ " factories$1[MemberType.Float] = getFloatDescriptor;\n" " }\n" "\n" -" function useEnumerationItem() {\n" -" factories$1[MemberType.EnumerationItem] = getEnumerationItemDescriptor;\n" -" }\n" -"\n" -" function useError() {\n" -" factories$1[MemberType.Error] = getErrorDescriptor;\n" -" }\n" -"\n" " function useObject() {\n" " factories$1[MemberType.Object] = getObjectDescriptor;\n" " }\n" @@ -2720,6 +2639,16 @@ " factories$1[MemberType.Undefined] = getUndefinedDescriptor;\n" " }\n" "\n" +" const transformers = {};\n" +"\n" +" function useEnumerationTransform() {\n" +" transformers[StructureType.Enumeration] = transformEnumerationDescriptor;\n" +" }\n" +"\n" +" function useErrorSetTransform() {\n" +" transformers[StructureType.ErrorSet] = transformErrorSetDescriptor;\n" +" }\n" +"\n" " function isByteAligned({ bitOffset, bitSize, byteSize }) {\n" " return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0;\n" " }\n" @@ -2729,6 +2658,12 @@ " return f(member, env);\n" " }\n" "\n" +" function transformDescriptor(descriptor, member) {\n" +" const { structure } = member;\n" +" const t = transformers[structure?.type];\n" +" return (t) ? t(descriptor, structure) : descriptor;\n" +" }\n" +"\n" " function getVoidDescriptor(member, env) {\n" " const { runtimeSafety } = env;\n" " return {\n" @@ -2767,12 +2702,14 @@ "\n" " function getIntDescriptor(member, env) {\n" " const getDataViewAccessor = addRuntimeCheck(env, getNumericAccessor);\n" -" return getDescriptorUsing(member, env, getDataViewAccessor)\n" +" const descriptor = getDescriptorUsing(member, env, getDataViewAccessor);\n" +" return transformDescriptor(descriptor, member);\n" " }\n" "\n" " function getUintDescriptor(member, env) {\n" " const getDataViewAccessor = addRuntimeCheck(env, getNumericAccessor);\n" -" return getDescriptorUsing(member, env, getDataViewAccessor)\n" +" const descriptor = getDescriptorUsing(member, env, getDataViewAccessor);\n" +" return transformDescriptor(descriptor, member);\n" " }\n" "\n" " function addRuntimeCheck(env, getDataViewAccessor) {\n" @@ -2798,92 +2735,83 @@ " return getDescriptorUsing(member, env, getNumericAccessor)\n" " }\n" "\n" -" function getValueDescriptor(member, env) {\n" -" // enum can be int or uint--need the type from the structure\n" -" const { type, structure } = member.structure.instance.members[0];\n" -" // combine that with the offset/size\n" -" const valueMember = { ...member, type, structure };\n" -" return getDescriptor(valueMember, env);\n" -" }\n" -"\n" -" function getEnumerationItemDescriptor(member, env) {\n" -" const { structure } = member;\n" -" const { get: getValue, set: setValue } = getValueDescriptor(member, env);\n" +" function transformEnumerationDescriptor(int, structure) { \n" " const findEnum = function(value) {\n" " const { constructor } = structure;\n" " // the enumeration constructor returns the object for the int value\n" -" const item = (value instanceof constructor) ? value : constructor(value);\n" +" const item = constructor(value);\n" " if (!item) {\n" " throwEnumExpected(structure, value);\n" " }\n" " return item\n" " };\n" " return {\n" -" get: (getValue.length === 0) \n" -" ? function getEnum() {\n" -" const value = getValue.call(this);\n" +" get: (int.get.length === 0) \n" +" ? function getEnum(hint) {\n" +" const value = int.get.call(this);\n" +" if (hint === 'number') {\n" +" return value;\n" +" }\n" " return findEnum(value);\n" " }\n" " : function getEnumElement(index) {\n" -" const value = getValue.call(this, index);\n" +" const value = int.get.call(this, index);\n" " return findEnum(value);\n" " },\n" -" set: (setValue.length === 1) \n" -" ? function setEnum(value) {\n" -" // call Symbol.toPrimitive directly as enum can be bigint or number\n" -" const item = findEnum(value);\n" -" setValue.call(this, item[Symbol.toPrimitive]());\n" +" set: (int.set.length === 1) \n" +" ? function setEnum(value, hint) {\n" +" if (hint !== 'number') {\n" +" const item = findEnum(value);\n" +" // call Symbol.toPrimitive directly as enum can be bigint or number\n" +" value = item[Symbol.toPrimitive]();\n" +" }\n" +" int.set.call(this, value);\n" " }\n" " : function setEnumElement(index, value) {\n" " const item = findEnum(value);\n" -" setValue.call(this, index, item[Symbol.toPrimitive]());\n" +" int.set.call(this, index, item[Symbol.toPrimitive]());\n" " },\n" " };\n" " }\n" "\n" -" function getErrorDescriptor(member, env) {\n" -" const { structure } = member;\n" -" const { name } = structure;\n" -" const { get: getValue, set: setValue } = getValueDescriptor(member, env); \n" -" const acceptAny = name === 'anyerror';\n" -" const globalErrorSet = getGlobalErrorSet();\n" -" const findError = function(value, allowZero = false) {\n" +" function transformErrorSetDescriptor(int, structure) {\n" +" const findError = function(value) {\n" " const { constructor } = structure;\n" -" let item;\n" -" if (value === 0 && allowZero) {\n" -" return;\n" -" } else if (value instanceof Error) {\n" -" if (value instanceof (acceptAny ? globalErrorSet : constructor)) {\n" -" item = value;\n" -" } else {\n" +" const item = constructor(value);\n" +" if (!item) {\n" +" if (value instanceof Error) {\n" " throwNotInErrorSet(structure);\n" -" }\n" -" } else {\n" -" item = acceptAny ? globalErrorSet[value] : constructor(value);\n" -" if (!item) {\n" +" } else {\n" " throwErrorExpected(structure, value);\n" -" } \n" -" }\n" +" }\n" +" } \n" " return item\n" " };\n" " return {\n" -" get: (getValue.length === 0) \n" -" ? function getError(allowZero) {\n" -" const value = getValue.call(this);\n" -" return findError(value, allowZero);\n" +" get: (int.get.length === 0) \n" +" ? function getError(hint) {\n" +" const value = int.get.call(this);\n" +" if (hint === 'number') {\n" +" return value;\n" +" }\n" +" return findError(value);\n" " }\n" " : function getErrorElement(index) {\n" -" const value = getValue.call(this, index);\n" -" return findError(value, false);\n" +" const value = int.get.call(this, index);\n" +" return findError(value);\n" " },\n" -" set: (setValue.length === 1) \n" -" ? function setError(value, allowZero) {\n" -" const item = findError(value, allowZero);\n" -" setValue.call(this, Number(item ?? 0));\n" +" set: (int.set.length === 1) \n" +" ? function setError(value, hint) {\n" +" if (hint !== 'number') {\n" +" const item = findError(value);\n" +" value = Number(item);\n" +" }\n" +" int.set.call(this, value);\n" " }\n" " : function setError(index, value) {\n" -" const item = findError(value, false);\n" -" setValue.call(this, index, Number(item));\n" +" const item = findError(value);\n" +" value = Number(item);\n" +" int.set.call(this, index, value);\n" " },\n" " };\n" " }\n" @@ -3019,8 +2947,6 @@ " useInt();\n" " useUint();\n" " useFloat();\n" -" useEnumerationItem();\n" -" useError();\n" " useObject();\n" " useType();\n" " useComptime();\n" @@ -3028,6 +2954,126 @@ " useLiteral();\n" " }\n" "\n" +" let currentGlobalSet;\n" +" let currentErrorClass;\n" +"\n" +" function defineErrorSet(structure, env) {\n" +" const {\n" +" name,\n" +" byteSize,\n" +" align,\n" +" instance: { members: [ member ] },\n" +" } = structure;\n" +" if (!currentErrorClass) {\n" +" currentErrorClass = class ZigError extends ZigErrorBase {};\n" +" currentGlobalSet = defineErrorSet({ ...structure, name: 'anyerror' }, env);\n" +" } \n" +" if (currentGlobalSet && name === 'anyerror') {\n" +" structure.constructor = currentGlobalSet;\n" +" structure.typedArray = getTypedArrayClass(member);\n" +" return currentGlobalSet;\n" +" }\n" +" const errorClass = currentErrorClass;\n" +" const { get, set } = getDescriptor(member, env);\n" +" const expected = [ 'string', 'number' ];\n" +" const propApplier = createPropertyApplier(structure);\n" +" const initializer = function(arg) {\n" +" if (arg instanceof constructor[CLASS]) {\n" +" set.call(this, arg);\n" +" } else if (arg && typeof(arg) === 'object' && !isErrorJSON(arg)) {\n" +" if (propApplier.call(this, arg) === 0) {\n" +" throwInvalidInitializer(structure, expected, arg);\n" +" } \n" +" } else if (arg !== undefined) {\n" +" set.call(this, arg);\n" +" }\n" +" };\n" +" const alternateCaster = function(arg) {\n" +" if (typeof(arg) === 'number' || typeof(arg) === 'string') {\n" +" return constructor[arg];\n" +" } else if (arg instanceof constructor[CLASS]) {\n" +" return constructor[Number(arg)];\n" +" } else if (isErrorJSON(arg)) {\n" +" return constructor[`Error: ${arg.error}`];\n" +" } else if (!getDataView(structure, arg, env)) {\n" +" throwInvalidInitializer(structure, expected, arg);\n" +" } else {\n" +" return false;\n" +" }\n" +" };\n" +" // items are inserted when static members get attached in static.js\n" +" const constructor = structure.constructor = createConstructor(structure, { initializer, alternateCaster }, env);\n" +" const typedArray = structure.typedArray = getTypedArrayClass(member);\n" +" const instanceDescriptors = {\n" +" $: { get, set },\n" +" dataView: getDataViewDescriptor(structure),\n" +" base64: getBase64Descriptor(structure),\n" +" typedArray: typedArray && getTypedArrayDescriptor(structure),\n" +" valueOf: { value: getValueOf },\n" +" toJSON: { value: convertToJSON },\n" +" delete: { value: getDestructor(env) },\n" +" [COPIER]: { value: getMemoryCopier(byteSize) },\n" +" [NORMALIZER]: { value: get },\n" +" };\n" +" const staticDescriptors = {\n" +" [ALIGN]: { value: align },\n" +" [SIZE]: { value: byteSize },\n" +" [CLASS]: { value: errorClass },\n" +" // the PROPS array is normally set in static.js; it needs to be set here for anyerror \n" +" // so we can add names to it as error sets are defined\n" +" [PROPS]: (name === 'anyerror') ? { value: [] } : undefined,\n" +" };\n" +" return attachDescriptors(constructor, instanceDescriptors, staticDescriptors);\n" +" }\n" +" function appendErrorSet(errorSet, name, es) {\n" +" // our Zig export code places error set instance into the static template, which we can't \n" +" // use since all errors need to have the same parent class; here we get the error number \n" +" // and create the actual error object if hasn't been created already for an earlier set\n" +" const number = es[GETTER]('number');\n" +" let error = currentGlobalSet[number];\n" +" if (!error) {\n" +" const errorClass = errorSet[CLASS];\n" +" error = new errorClass(name, number);\n" +" }\n" +" const string = String(error);\n" +" const descriptors = {\n" +" [number]: { value: error },\n" +" [string]: { value: error },\n" +" [name]: { value: error },\n" +" };\n" +" defineProperties(errorSet, descriptors);\n" +" defineProperties(currentGlobalSet, descriptors); \n" +" // add name to prop list\n" +" currentGlobalSet[PROPS].push(name);\n" +" }\n" +"\n" +" function resetGlobalErrorSet() {\n" +" currentErrorClass = currentGlobalSet = undefined;\n" +" }\n" +"\n" +" function isErrorJSON(arg) {\n" +" return typeof(arg) === 'object' && typeof(arg.error) === 'string' && Object.keys(arg).length === 1 ;\n" +" }\n" +"\n" +" class ZigErrorBase extends Error {\n" +" constructor(name, number) {\n" +" super(deanimalizeErrorName(name));\n" +" this.number = number;\n" +" }\n" +"\n" +" [Symbol.toPrimitive](hint) {\n" +" if (hint === 'string') {\n" +" return Error.prototype.toString.call(this, hint);\n" +" } else {\n" +" return this.number;\n" +" }\n" +" } \n" +"\n" +" toJSON() {\n" +" return { error: this.message };\n" +" }\n" +" }\n" +"\n" " function throwNoInitializer(structure) {\n" " const { name } = structure;\n" " throw new TypeError(`An initializer must be provided to the constructor of ${name}, even when the intended value is undefined`);\n" @@ -3071,7 +3117,10 @@ " function throwErrorExpected(structure, arg) {\n" " const { name } = structure;\n" " const type = typeof(arg);\n" -" if (type === 'string' || type === 'number') {\n" +" if (type === 'string' || type === 'number' || isErrorJSON(arg)) {\n" +" if (isErrorJSON(arg)) {\n" +" arg = `{ error: ${JSON.stringify(arg.error)} }`;\n" +" }\n" " throw new TypeError(`Error ${type} does not corresponds to any error in error set ${name}: ${arg}`);\n" " } else {\n" " throw new TypeError(`Error of the type ${name} expected, received ${arg}`);\n" @@ -3117,9 +3166,13 @@ " const acceptable = [];\n" " const primitive = getPrimitiveType(member);\n" " if (primitive) {\n" -" acceptable.push(`array of ${primitive}s`);\n" -" } else if (member.type === MemberType.EnumerationItem) {\n" -" acceptable.push(`array of enum items`);\n" +" let object;\n" +" switch (member.structure?.type) {\n" +" case StructureType.Enumeration: object = 'enum item'; break;\n" +" case StructureType.ErrorSet: object = 'error'; break;\n" +" default: object = primitive;\n" +" }\n" +" acceptable.push(`array of ${object}s`);\n" " } else {\n" " acceptable.push(`array of objects`);\n" " }\n" @@ -4102,9 +4155,6 @@ " constructor,\n" " static: { members, template },\n" " } = structure;\n" -" if (members.length === 0) {\n" -" return;\n" -" }\n" " const descriptors = {};\n" " for (const member of members) {\n" " descriptors[member.name] = getDescriptor(member, env);\n" @@ -4115,62 +4165,18 @@ " ...descriptors,\n" " [Symbol.iterator]: { value: getStructIterator },\n" " // static variables are objects stored in the static template's slots\n" -" [SLOTS]: { value: template[SLOTS] },\n" -" [PROPS]: { value: members.map(m => m.name) },\n" +" [SLOTS]: template ? { value: template[SLOTS] } : undefined,\n" +" // anyerror would have props already\n" +" [PROPS]: !constructor[PROPS] ? { value: members.map(m => m.name) } : undefined,\n" " [NORMALIZER]: { value: normalizeStruct },\n" " });\n" " if (type === StructureType.Enumeration) {\n" -" const enums = constructor[ITEMS];\n" " for (const { name, slot } of members) {\n" -" if (name !== undefined) {\n" -" // place item in hash to facilitate lookup, \n" -" const item = constructor[SLOTS][slot];\n" -" if (item instanceof constructor) {\n" -" // attach name to item so tagged union code can quickly find it\n" -" defineProperties(item, { [NAME]: { value: name } }); \n" -" const index = item[Symbol.toPrimitive]();\n" -" enums[index] = enums[name] = item; \n" -" } \n" -" } else {\n" -" // non-exhaustive enum\n" -" defineProperties(constructor, { [MORE]: { value: true } });\n" -" }\n" +" appendEnumeration(constructor, name, constructor[SLOTS][slot]);\n" " }\n" " } else if (type === StructureType.ErrorSet) {\n" -" const allErrors = getGlobalErrorSet();\n" -" const errors = constructor[ITEMS];\n" " for (const { name, slot } of members) {\n" -" let error = constructor[SLOTS][slot];\n" -" const index = Number(error);\n" -" const previous = allErrors[index];\n" -" if (previous) {\n" -" if (!(previous instanceof constructor)) {\n" -" // error already exists in a previously defined set\n" -" // see if we should make that set a subclass or superclass of this one\n" -" const otherSet = previous.constructor;\n" -" const otherErrors = Object.values(otherSet[SLOTS]);\n" -" const errorIndices = Object.values(constructor[SLOTS]).map(e => Number(e));\n" -" if (otherErrors.every(e => errorIndices.includes(Number(e)))) {\n" -" // this set contains the all errors of the other one, so it's a superclass\n" -" Object.setPrototypeOf(otherSet.prototype, constructor.prototype);\n" -" } else {\n" -" // make this set a subclass of the other\n" -" Object.setPrototypeOf(constructor.prototype, otherSet.prototype);\n" -" for (const otherError of otherErrors) {\n" -" if (errorIndices.includes(Number(otherError))) {\n" -" // this set should be this error object's class\n" -" Object.setPrototypeOf(otherError, constructor.prototype);\n" -" }\n" -" }\n" -" }\n" -" }\n" -" error = constructor[SLOTS][slot] = previous; \n" -" } else {\n" -" // set error message (overriding prototype) and add to hash\n" -" defineProperties(error, { message: { value: deanimalizeErrorName(name) } });\n" -" allErrors[index] = allErrors[error.message] = allErrors[`${error}`] = error;\n" -" }\n" -" errors[index] = errors[error.message] = errors[`${error}`] = error;\n" +" appendErrorSet(constructor, name, constructor[SLOTS][slot]);\n" " }\n" " }\n" " }\n" @@ -4519,7 +4525,7 @@ " omitFunctions = false,\n" " omitVariables = isElectron(),\n" " } = options;\n" -" createGlobalErrorSet();\n" +" resetGlobalErrorSet();\n" " const thunkId = this.getFactoryThunk();\n" " const ArgStruct = this.defineFactoryArgStruct();\n" " const args = new ArgStruct([ { omitFunctions, omitVariables } ]);\n" @@ -4672,7 +4678,7 @@ " return placeholder.structure;\n" " }\n" " };\n" -" createGlobalErrorSet();\n" +" resetGlobalErrorSet();\n" " const objectPlaceholders = new Map();\n" " for (const structure of structures) {\n" " // recreate the actual template using the provided placeholder\n" diff --git a/node-zigar/test/sample-modules/node-zigar-addon/linux.x64.node b/node-zigar/test/sample-modules/node-zigar-addon/linux.x64.node index 455bf8d3..25881c12 100755 Binary files a/node-zigar/test/sample-modules/node-zigar-addon/linux.x64.node and b/node-zigar/test/sample-modules/node-zigar-addon/linux.x64.node differ diff --git a/node-zigar/test/zig-samples/with-config/lib/node-zigar-addon/linux.x64.node b/node-zigar/test/zig-samples/with-config/lib/node-zigar-addon/linux.x64.node index 455bf8d3..25881c12 100755 Binary files a/node-zigar/test/zig-samples/with-config/lib/node-zigar-addon/linux.x64.node and b/node-zigar/test/zig-samples/with-config/lib/node-zigar-addon/linux.x64.node differ diff --git a/zigar-compiler/dist/index.cjs b/zigar-compiler/dist/index.cjs index 63f1dfd8..47543453 100644 --- a/zigar-compiler/dist/index.cjs +++ b/zigar-compiler/dist/index.cjs @@ -9,219 +9,113 @@ var url = require('url'); var crypto = require('crypto'); var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; -const MEMORY$8 = Symbol('memory'); -const SLOTS$8 = Symbol('slots'); -const PARENT$8 = Symbol('parent'); -const NAME$8 = Symbol('name'); -const TAG$8 = Symbol('tag'); -const ITEMS$8 = Symbol('items'); -const PROPS$8 = Symbol('props'); -const GETTER$8 = Symbol('getter'); -const SETTER$8 = Symbol('setter'); -const ELEMENT_GETTER$8 = Symbol('elementGetter'); -const ELEMENT_SETTER$8 = Symbol('elementSetter'); -const LOCATION_GETTER$8 = Symbol('addressGetter'); -const LOCATION_SETTER$8 = Symbol('addressSetter'); -const TARGET_GETTER$8 = Symbol('targetGetter'); -const TARGET_SETTER$8 = Symbol('targetSetter'); -const FIXED_LOCATION$8 = Symbol('fixedLocation'); -const PROP_GETTERS$8 = Symbol('propGetters'); -const PROP_SETTERS$8 = Symbol('propSetters'); -const ALL_KEYS$8 = Symbol('allKeys'); -const LENGTH$8 = Symbol('length'); -const PROXY$8 = Symbol('proxy'); -const COMPAT$8 = Symbol('compat'); -const SIZE$8 = Symbol('size'); -const ALIGN$8 = Symbol('align'); -const ARRAY$8 = Symbol('array'); -const POINTER$8 = Symbol('pointer'); -const CONST$8 = Symbol('const'); -const CONST_PROTOTYPE$8 = Symbol('constProto'); -const COPIER$8 = Symbol('copier'); -const RESETTER$8 = Symbol('resetter'); -const NORMALIZER$8 = Symbol('normalizer'); -const VIVIFICATOR$8 = Symbol('vivificator'); -const POINTER_VISITOR$8 = Symbol('pointerVisitor'); -const ENVIRONMENT$8 = Symbol('environment'); +const MEMORY$a = Symbol('memory'); +const SLOTS$a = Symbol('slots'); +const PARENT$a = Symbol('parent'); +const NAME$a = Symbol('name'); +const CLASS$2 = Symbol('class'); +const PROPS$a = Symbol('props'); +const GETTER$a = Symbol('getter'); +const SETTER$a = Symbol('setter'); +const LOCATION_GETTER$a = Symbol('addressGetter'); +const FIXED_LOCATION$a = Symbol('fixedLocation'); +const SIZE$a = Symbol('size'); +const ALIGN$a = Symbol('align'); +const POINTER$a = Symbol('pointer'); +const CONST$a = Symbol('const'); +const COPIER$a = Symbol('copier'); +const NORMALIZER$a = Symbol('normalizer'); +const VIVIFICATOR$a = Symbol('vivificator'); +const POINTER_VISITOR$a = Symbol('pointerVisitor'); +const ENVIRONMENT$a = Symbol('environment'); const ATTRIBUTES = Symbol('attributes'); -const MORE$8 = Symbol('more'); - -function getDestructor$8(env) { - return function() { - const dv = this[MEMORY$8]; - this[MEMORY$8] = null; - if (this[SLOTS$8]) { - this[SLOTS$8] = {}; - } - env.releaseFixedView(dv); - }; -} - -function getBitAlignFunction$8(bitPos, bitSize, toAligned) { - if (bitPos + bitSize <= 8) { - const mask = (2 ** bitSize) - 1; - if (toAligned) { - // from single byte - return function(dest, src, offset) { - const n = src.getUint8(offset); - const b = (n >> bitPos) & mask; - dest.setUint8(0, b); - }; - } else { - // to single byte - const destMask = 0xFF ^ (mask << bitPos); - return function(dest, src, offset) { - const n = src.getUint8(0); - const d = dest.getUint8(offset); - const b = (d & destMask) | ((n & mask) << bitPos); - dest.setUint8(offset, b); - }; - } - } else { - const leadBits = 8 - bitPos; - const leadMask = (2 ** leadBits) - 1; - if (toAligned) { - const trailBits = bitSize % 8; - const trailMask = (2 ** trailBits) - 1; - return function(dest, src, offset) { - let i = offset, j = 0; - let n = src.getUint8(i++), b; - let bitBuf = (n >> bitPos) & leadMask; - let bitCount = leadBits; - let remaining = bitSize; - do { - if (remaining > bitCount) { - n = src.getUint8(i++); - bitBuf = bitBuf | (n << bitCount); - //bitCount += 8; - } - b = (remaining >= 8) ? bitBuf & 0xFF : bitBuf & trailMask; - dest.setUint8(j++, b); - bitBuf >>= 8; - //bitCount -= 8; - remaining -= 8; - } while (remaining > 0); - } - } else { - const trailBits = (bitSize - leadBits) % 8; - const trailMask = (2 ** trailBits) - 1; - const destMask1 = 0xFF ^ (leadMask << bitPos); - const destMask2 = 0xFF ^ trailMask; - return function(dest, src, offset) { - let i = 0, j = offset; - // preserve bits ahead of bitPos - let d = dest.getUint8(j), n, b; - let bitBuf = d & destMask1; - let bitCount = bitPos; - let remaining = bitSize + bitCount; - do { - if (remaining > bitCount) { - n = src.getUint8(i++); - bitBuf = bitBuf | (n << bitCount); - bitCount += 8; - } - if (remaining >= 8) { - b = bitBuf & 0xFF; - } else { - // preserve bits at the destination sitting behind the trailing bits - d = dest.getUint8(j); - b = (d & destMask2) | (bitBuf & trailMask); - } - dest.setUint8(j++, b); - bitBuf >>= 8; - bitCount -= 8; - remaining -= 8; - } while (remaining > 0); - } - } - } -} +const MORE$a = Symbol('more'); -function getMemoryCopier$8(size, multiple = false) { - const copy = getCopyFunction$8(size, multiple); +function getMemoryCopier$a(size, multiple = false) { + const copy = getCopyFunction$a(size, multiple); return function(target) { /* WASM-ONLY */ - restoreMemory$8.call(this); - restoreMemory$8.call(target); + restoreMemory$a.call(this); + restoreMemory$a.call(target); /* WASM-ONLY-END */ - const src = target[MEMORY$8]; - const dest = this[MEMORY$8]; + const src = target[MEMORY$a]; + const dest = this[MEMORY$a]; copy(dest, src); }; } -function getCopyFunction$8(size, multiple = false) { +function getCopyFunction$a(size, multiple = false) { if (!multiple) { - const copier = copiers$8[size]; + const copier = copiers$a[size]; if (copier) { return copier; } } - if (!(size & 0x07)) return copy8x$8; - if (!(size & 0x03)) return copy4x$8; - if (!(size & 0x01)) return copy2x$8; - return copy1x$8; + if (!(size & 0x07)) return copy8x$a; + if (!(size & 0x03)) return copy4x$a; + if (!(size & 0x01)) return copy2x$a; + return copy1x$a; } -const copiers$8 = { - 1: copy1$8, - 2: copy2$8, - 4: copy4$8, - 8: copy8$8, - 16: copy16$8, - 32: copy32$8, +const copiers$a = { + 1: copy1$a, + 2: copy2$a, + 4: copy4$a, + 8: copy8$a, + 16: copy16$a, + 32: copy32$a, }; -function copy1x$8(dest, src) { +function copy1x$a(dest, src) { for (let i = 0, len = dest.byteLength; i < len; i++) { dest.setInt8(i, src.getInt8(i)); } } -function copy2x$8(dest, src) { +function copy2x$a(dest, src) { for (let i = 0, len = dest.byteLength; i < len; i += 2) { dest.setInt16(i, src.getInt16(i, true), true); } } -function copy4x$8(dest, src) { +function copy4x$a(dest, src) { for (let i = 0, len = dest.byteLength; i < len; i += 4) { dest.setInt32(i, src.getInt32(i, true), true); } } -function copy8x$8(dest, src) { +function copy8x$a(dest, src) { for (let i = 0, len = dest.byteLength; i < len; i += 8) { dest.setInt32(i, src.getInt32(i, true), true); dest.setInt32(i + 4, src.getInt32(i + 4, true), true); } } -function copy1$8(dest, src) { +function copy1$a(dest, src) { dest.setInt8(0, src.getInt8(0)); } -function copy2$8(dest, src) { +function copy2$a(dest, src) { dest.setInt16(0, src.getInt16(0, true), true); } -function copy4$8(dest, src) { +function copy4$a(dest, src) { dest.setInt32(0, src.getInt32(0, true), true); } -function copy8$8(dest, src) { +function copy8$a(dest, src) { dest.setInt32(0, src.getInt32(0, true), true); dest.setInt32(4, src.getInt32(4, true), true); } -function copy16$8(dest, src) { +function copy16$a(dest, src) { dest.setInt32(0, src.getInt32(0, true), true); dest.setInt32(4, src.getInt32(4, true), true); dest.setInt32(8, src.getInt32(8, true), true); dest.setInt32(12, src.getInt32(12, true), true); } -function copy32$8(dest, src) { +function copy32$a(dest, src) { dest.setInt32(0, src.getInt32(0, true), true); dest.setInt32(4, src.getInt32(4, true), true); dest.setInt32(8, src.getInt32(8, true), true); @@ -232,117 +126,25 @@ function copy32$8(dest, src) { dest.setInt32(28, src.getInt32(28, true), true); } -function getMemoryResetter$8(offset, size) { - const reset = getResetFunction$8(size); - return function() { - /* WASM-ONLY */ - restoreMemory$8.call(this); - /* WASM-ONLY-END */ - const dest = this[MEMORY$8]; - reset(dest, offset, size); - }; -} - -function getResetFunction$8(size) { - const resetter = resetters$8[size]; - if (resetter) { - return resetter; - } - if (!(size & 0x07)) return reset8x$8; - if (!(size & 0x03)) return reset4x$8; - if (!(size & 0x01)) return reset2x$8; - return reset1x$8; -} - -const resetters$8 = { - 1: reset1$8, - 2: reset2$8, - 4: reset4$8, - 8: reset8$8, - 16: reset16$8, - 32: reset32$8, -}; - -function reset1x$8(dest, offset, size) { - for (let i = offset, limit = offset + size; i < limit; i++) { - dest.setInt8(i, 0); - } -} - -function reset2x$8(dest, offset, size) { - for (let i = offset, limit = offset + size; i < limit; i += 2) { - dest.setInt16(i, 0, true); - } -} - -function reset4x$8(dest, offset, size) { - for (let i = offset, limit = offset + size; i < limit; i += 4) { - dest.setInt32(i, 0, true); - } -} - -function reset8x$8(dest, offset, size) { - for (let i = offset, limit = offset + size; i < limit; i += 8) { - dest.setInt32(i, 0, true); - dest.setInt32(i + 4, 0, true); - } -} - -function reset1$8(dest, offset) { - dest.setInt8(offset, 0); -} - -function reset2$8(dest, offset) { - dest.setInt16(offset, 0, true); -} - -function reset4$8(dest, offset) { - dest.setInt32(offset, 0, true); -} - -function reset8$8(dest, offset) { - dest.setInt32(offset + 0, 0, true); - dest.setInt32(offset + 4, 0, true); -} - -function reset16$8(dest, offset) { - dest.setInt32(offset + 0, 0, true); - dest.setInt32(offset + 4, 0, true); - dest.setInt32(offset + 8, 0, true); - dest.setInt32(offset + 12, 0, true); -} - -function reset32$8(dest, offset) { - dest.setInt32(offset + 0, 0, true); - dest.setInt32(offset + 4, 0, true); - dest.setInt32(offset + 8, 0, true); - dest.setInt32(offset + 12, 0, true); - dest.setInt32(offset + 16, 0, true); - dest.setInt32(offset + 20, 0, true); - dest.setInt32(offset + 24, 0, true); - dest.setInt32(offset + 28, 0, true); -} - -function restoreMemory$8() { - const dv = this[MEMORY$8]; - const source = dv[MEMORY$8]; +function restoreMemory$a() { + const dv = this[MEMORY$a]; + const source = dv[MEMORY$a]; if (!source || dv.buffer.byteLength !== 0) { return false; } const { memory, address, len } = source; const newDV = new DataView(memory.buffer, address, len); - newDV[MEMORY$8] = source; - this[MEMORY$8] = newDV; + newDV[MEMORY$a] = source; + this[MEMORY$a] = newDV; return true; } -const decoders$8 = {}; -const encoders$8 = {}; +const decoders$a = {}; -function decodeText$8(arrays, encoding = 'utf-8') { - let decoder = decoders$8[encoding]; +function decodeText$a(arrays, encoding = 'utf-8') { + let decoder = decoders$a[encoding]; if (!decoder) { - decoder = decoders$8[encoding] = new TextDecoder(encoding); + decoder = decoders$a[encoding] = new TextDecoder(encoding); } let array; if (Array.isArray(arrays)) { @@ -367,46 +169,11 @@ function decodeText$8(arrays, encoding = 'utf-8') { return decoder.decode(array); } -function encodeText$8(text, encoding = 'utf-8') { - switch (encoding) { - case 'utf-16': { - const { length } = text; - const ta = new Uint16Array(length); - for (let i = 0; i < length; i++) { - ta[i] = text.charCodeAt(i); - } - return ta; - } - default: { - let encoder = encoders$8[encoding]; - if (!encoder) { - encoder = encoders$8[encoding] = new TextEncoder(); - } - return encoder.encode(text); - } - } -} - -function encodeBase64$8(dv) { - const ta = new Uint8Array(dv.buffer, dv.byteOffset, dv.byteLength); - const bstr = String.fromCharCode.apply(null, ta); - return btoa(bstr); -} - -function decodeBase64$8(str) { - const bstr = atob(str); - const ta = new Uint8Array(bstr.length); - for (let i = 0; i < ta.byteLength; i++) { - ta[i] = bstr.charCodeAt(i); - } - return new DataView(ta.buffer); -} - -function getValueOf$8() { +function getValueOf$a() { const map = new Map(); const options = { error: 'throw' }; const process = function(value) { - const normalizer = value?.[NORMALIZER$8]; + const normalizer = value?.[NORMALIZER$a]; if (normalizer) { let result = map.get(value); if (result === undefined) { @@ -421,26 +188,26 @@ function getValueOf$8() { return process(this); } -const INT_MAX$8 = BigInt(Number.MAX_SAFE_INTEGER); -const INT_MIN$8 = BigInt(Number.MIN_SAFE_INTEGER); +const INT_MAX$a = BigInt(Number.MAX_SAFE_INTEGER); +const INT_MIN$a = BigInt(Number.MIN_SAFE_INTEGER); -function convertToJSON$8() { +function convertToJSON$a() { const map = new Map(); const options = { error: 'return' }; const process = function(value) { - const normalizer = value?.[NORMALIZER$8]; + const normalizer = value?.[NORMALIZER$a]; if (normalizer) { - if (value instanceof Error) { - return { error: value.message }; - } let result = map.get(value); if (result === undefined) { result = normalizer.call(value, process, options); + if (typeof(result?.toJSON) === 'function') { + result = result.toJSON(); + } map.set(value, result); } return result; } else { - if (typeof(value) === 'bigint' && INT_MIN$8 <= value && value <= INT_MAX$8) { + if (typeof(value) === 'bigint' && INT_MIN$a <= value && value <= INT_MAX$a) { return Number(value); } return value; @@ -449,12 +216,7 @@ function convertToJSON$8() { return process(this); } -function normalizeValue$8(cb, options) { - const value = handleError$8(() => this.$, options); - return cb(value); -} - -function handleError$8(cb, options = {}) { +function handleError$a(cb, options = {}) { const { error = 'throw' } = options; try { return cb(); @@ -467,1051 +229,4544 @@ function handleError$8(cb, options = {}) { } } -function getDataViewDescriptor$8(structure, handlers = {}) { - return markAsSpecial$8({ - get() { - /* WASM-ONLY */ - restoreMemory$8.call(this); - /* WASM-ONLY-END */ - return this[MEMORY$8]; - }, - set(dv) { - checkDataView$8(dv); - setDataView$8.call(this, dv, structure, true, handlers); - }, - }); +function always$a() { + return true; } -function getBase64Descriptor$8(structure, handlers = {}) { - return markAsSpecial$8({ - get() { - return encodeBase64$8(this.dataView); - }, - set(str) { - if (typeof(str) !== 'string') { - throwTypeMismatch$8('string', str); - } - const dv = decodeBase64$8(str); - setDataView$8.call(this, dv, structure, false, handlers); - } - }); +function normalizeStruct$a(cb, options) { + const object = {}; + for (const [ name, value ] of getStructEntries$a.call(this, options)) { + object[name] = cb(value); + } + return object; } -function getStringDescriptor$8(structure, handlers = {}) { - const { sentinel, instance: { members }} = structure; - const { byteSize: charSize } = members[0]; - return markAsSpecial$8({ - get() { - const dv = this.dataView; - const TypedArray = (charSize === 1) ? Int8Array : Int16Array; - const ta = new TypedArray(dv.buffer, dv.byteOffset, this.length); - const s = decodeText$8(ta, `utf-${charSize * 8}`); - return (sentinel?.value === undefined) ? s : s.slice(0, -1); - }, - set(str) { - if (typeof(str) !== 'string') { - throwTypeMismatch$8('a string', str); - } - if (sentinel?.value !== undefined) { - if (str.charCodeAt(str.length - 1) !== sentinel.value) { - str = str + String.fromCharCode(sentinel.value); - } - } - const ta = encodeText$8(str, `utf-${charSize * 8}`); - const dv = new DataView(ta.buffer); - setDataView$8.call(this, dv, structure, false, handlers); - }, - }); +function getStructEntries$a(options) { + return { + [Symbol.iterator]: getStructEntriesIterator$a.bind(this, options), + length: this[PROPS$a].length, + }; } -function getTypedArrayDescriptor$8(structure, handlers = {}) { - const { typedArray } = structure; - return markAsSpecial$8({ - get() { - const dv = this.dataView; - const length = dv.byteLength / typedArray.BYTES_PER_ELEMENT; - return new typedArray(dv.buffer, dv.byteOffset, length); - }, - set(ta) { - if (!isTypedArray$8(ta, typedArray)) { - throwTypeMismatch$8(typedArray.name, ta); +function getStructIterator$a(options) { + const entries = getStructEntries$a.call(this, options); + return entries[Symbol.iterator](); +} + +function getStructEntriesIterator$a(options) { + const self = this; + const props = this[PROPS$a]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + value = [ current, handleError$a(() => self[current], options) ]; + done = false; + } else { + done = true; } - const dv = new DataView(ta.buffer, ta.byteOffset, ta.byteLength); - setDataView$8.call(this, dv, structure, true, handlers); + return { value, done }; }, - }); + }; +} + +function getChildVivificator$k(structure) { + const { instance: { members } } = structure; + const objectMembers = {}; + for (const member of members.filter(m => m.type === MemberType$a.Object)) { + objectMembers[member.slot] = member; + } + return function vivificateChild(slot, writable = true) { + const member = objectMembers[slot]; + const { bitOffset, byteSize, structure: { constructor } } = member; + const dv = this[MEMORY$a]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + (bitOffset >> 3); + let len = byteSize; + if (len === undefined) { + if (bitOffset & 7) { + throwNotOnByteBoundary$a(member); + } + len = member.bitSize >> 3; + } + const childDV = new DataView(dv.buffer, offset, len); + const object = this[SLOTS$a][slot] = constructor.call(PARENT$a, childDV, { writable }); + return object; + } } -function markAsSpecial$8({ get, set }) { - get.special = set.special = true; - return { get, set }; +function getPointerVisitor$k(structure, visitorOptions = {}) { + const { + isChildActive = always$a, + isChildMutable = always$a, + } = visitorOptions; + const { instance: { members } } = structure; + const pointerMembers = members.filter(m => m.structure.hasPointer); + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$a, + isMutable = always$a, + } = options; + const childOptions = { + ...options, + isActive: (object) => { + // make sure parent object is active, then check whether the child is active + return isActive(this) && isChildActive.call(this, object); + }, + isMutable: (object) => { + return isMutable(this) && isChildMutable.call(this, object); + }, + }; + for (const { slot } of pointerMembers) { + if (source) { + // when src is a the struct's template, most slots will likely be empty, + // since pointer fields aren't likely to have default values + const srcChild = source[SLOTS$a]?.[slot]; + if (!srcChild) { + continue; + } + childOptions.source = srcChild; + } + const child = this[SLOTS$a][slot] ?? (vivificate ? this[VIVIFICATOR$a](slot) : null); + if (child) { + child[POINTER_VISITOR$a](cb, childOptions); + } + } + }; } -function definePointer$8(structure, env) { +function defineArgStruct$a(structure, env) { const { byteSize, align, - instance: { members: [ member ] }, - isConst, + instance: { members }, + hasPointer, } = structure; - const { - runtimeSafety = true, - } = env; - const { structure: targetStructure } = member; - const { sentinel } = targetStructure; - const isTargetSlice = (targetStructure.type === StructureType$8.Slice); - const isTargetPointer = (targetStructure.type === StructureType$8.Pointer); - const hasLength = isTargetSlice && !sentinel; - const addressSize = (hasLength) ? byteSize / 2 : byteSize; - const { get: getAddress, set: setAddress } = getDescriptor$8({ - type: MemberType$8.Uint, - bitOffset: 0, - bitSize: addressSize * 8, - byteSize: addressSize, - structure: { byteSize: addressSize }, - }, env); - const { get: getLength, set: setLength } = (hasLength) ? getDescriptor$8({ - type: MemberType$8.Uint, - bitOffset: addressSize * 8, - bitSize: addressSize * 8, - byteSize: addressSize, - structure: { name: 'usize', byteSize: addressSize }, - }, env) : {}; - const updateTarget = function() { - const prevLocation = this[FIXED_LOCATION$8]; - if (prevLocation) { - const location = this[LOCATION_GETTER$8](); - if (location.address !== prevLocation.address || location.length !== prevLocation.length) { - const { constructor: Target } = targetStructure; - const dv = env.findMemory(location.address, location.length * Target[SIZE$8]); - const target = Target.call(ENVIRONMENT$8, dv, { writable: !isConst }); - this[SLOTS$8][0] = target; - this[FIXED_LOCATION$8] = location; + const hasObject = !!members.find(m => m.type === MemberType$a.Object); + const constructor = structure.constructor = function(args) { + const dv = env.allocateMemory(byteSize, align); + this[MEMORY$a] = dv; + if (hasObject) { + this[SLOTS$a] = {}; + } + initializer.call(this, args); + }; + const argNames = members.slice(0, -1).map(m => m.name); + const argCount = argNames.length; + const initializer = function(args) { + if (args.length !== argCount) { + throwArgumentCountMismatch$a(structure, args.length); + } + for (const [ index, name ] of argNames.entries()) { + try { + this[name] = args[index]; + } catch (err) { + rethrowArgumentError$a(structure, index, err); } - } + } }; - const getTargetObject = function() { - updateTarget.call(this); - return this[SLOTS$8][0] ?? throwNullPointer$8(); + const memberDescriptors = {}; + for (const member of members) { + memberDescriptors[member.name] = getDescriptor$a(member, env); + } + const isChildMutable = function(object) { + return (object === this.retval); }; - const setTargetObject = function(arg) { - if (env.inFixedMemory(this)) { - // the pointer sits in fixed memory--apply the change immediately - if (env.inFixedMemory(arg)) { - const loc = { - address: env.getViewAddress(arg[MEMORY$8]), - length: (hasLength) ? arg.length : 1 - }; - addressSetter.call(this, loc); - this[FIXED_LOCATION$8] = loc; - } else { - throwFixedMemoryTargetRequired$8(); - } - } - this[SLOTS$8][0] = arg; - }; - const getTarget = isValueExpected$8(targetStructure) - ? function() { - const target = getTargetObject.call(this); - return target[GETTER$8](); - } - : getTargetObject; - const setTarget = function(value) { - updateTarget.call(this); - const object = this[SLOTS$8][0] ?? throwNullPointer$8(); - return object[SETTER$8](value); - }; - const alternateCaster = function(arg, options) { - const Target = targetStructure.constructor; - if ((this === ENVIRONMENT$8 || this === PARENT$8) || arg instanceof constructor) { - // casting from buffer to pointer is allowed only if request comes from the runtime - // casting from writable to read-only is also allowed - return false; - } else if (isPointerOf$8(arg, Target)) { - // const/non-const casting - return new constructor(Target(arg['*'], { writable: !isConst }), options); - } else if (isTargetSlice) { - // allow casting to slice through constructor of its pointer - return new constructor(Target(arg), options); - } else { - throwNoCastingToPointer$8(); - } - }; - const finalizer = function() { - const handlers = (isTargetPointer) ? {} : proxyHandlers$h; - const proxy = new Proxy(this, handlers); - // hide the proxy so console wouldn't display a recursive structure - Object.defineProperty(this, PROXY$8, { value: proxy }); - return proxy; - }; - const initializer = function(arg) { - const Target = targetStructure.constructor; - if (isPointerOf$8(arg, Target)) { - // initialize with the other pointer'structure target - if (!isConst && arg.constructor.const) { - throwConstantConstraint$8(structure, arg); - } - arg = arg[SLOTS$8][0]; - } - if (arg instanceof Target) { - /* wasm-only */ - restoreMemory$8.call(arg); - /* wasm-only-end */ - if (isConst && !arg[CONST$8]) { - // create read-only version - arg = Target(arg, { writable: false }); - } else if (!isConst && arg[CONST$8]) { - throwReadOnlyTarget$8(structure); - } - } else if (isCompatible$8(arg, Target)) { - // autocast to target type - const dv = getDataView$8(targetStructure, arg, env); - arg = Target(dv, { writable: !isConst }); - } else if (arg !== undefined && !arg[MEMORY$8]) { - // autovivificate target object - const fixed = env.inFixedMemory(this); - const autoObj = new Target(arg, { writable: !isConst, fixed }); - if (runtimeSafety) { - // creation of a new slice using a typed array is probably - // not what the user wants; it's more likely that the intention - // is to point to the typed array but there's a mismatch (e.g. u32 vs i32) - if (targetStructure.typedArray && isBuffer$8(arg?.buffer)) { - warnImplicitArrayCreation$8(targetStructure, arg); - } - } - arg = autoObj; - } else if (arg !== undefined) { - throwInvalidPointerTarget$8(structure, arg); - } - this[TARGET_SETTER$8](arg); - }; - const constructor = structure.constructor = createConstructor$8(structure, { initializer, alternateCaster, finalizer }, env); - const addressSetter = function({ address, length }) { - setAddress.call(this, address); - setLength?.call(this, length); - }; - const addressGetter = function() { - const address = getAddress.call(this); - const length = (getLength) - ? getLength.call(this) - : (sentinel) - ? (address) ? env.findSentinel(address, sentinel.bytes) + 1 : 0 - : 1; - return { address, length }; - }; - const instanceDescriptors = { - '*': { get: getTarget, set: setTarget }, - '$': { get: getProxy$8, set: initializer }, - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - [TARGET_GETTER$8]: { value: getTargetObject }, - [TARGET_SETTER$8]: { value: setTargetObject }, - [LOCATION_GETTER$8]: { value: addressGetter }, - [LOCATION_SETTER$8]: { value: addressSetter }, - [POINTER_VISITOR$8]: { value: visitPointer$8 }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [VIVIFICATOR$8]: { value: throwNullPointer$8 }, - [NORMALIZER$8]: { value: normalizePointer$8 }, - [FIXED_LOCATION$8]: { value: undefined, writable: true }, - }; - const staticDescriptors = { - child: { get: () => targetStructure.constructor }, - const: { value: isConst }, - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, - }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); + defineProperties$a(constructor.prototype, { + ...memberDescriptors, + [COPIER$a]: { value: getMemoryCopier$a(byteSize) }, + [VIVIFICATOR$a]: hasObject && { value: getChildVivificator$k(structure) }, + [POINTER_VISITOR$a]: hasPointer && { value: getPointerVisitor$k(structure, { isChildMutable }) }, + }); + defineProperties$a(constructor, { + [ALIGN$a]: { value: align }, + [SIZE$a]: { value: byteSize }, + }); + return constructor; } -function normalizePointer$8(cb) { - let target; - try { - target = this['*']; - } catch (err) { - target = Symbol.for('inaccessible'); +function appendEnumeration$2(enumeration, name, item) { + if (name !== undefined) { + // enum can have static variables + if (item instanceof enumeration) { + // attach name to item so tagged union code can quickly find it + defineProperties$a(item, { [NAME$a]: { value: name } }); + // call toPrimitive directly since enum can be bigint or number + const index = item[Symbol.toPrimitive](); + defineProperties$a(enumeration, { + [index]: { value: item }, + [name]: { value: item }, + }); + } + } else { + // non-exhaustive enum + defineProperties$a(enumeration, { [MORE$a]: { value: true } }); } - return cb(target); } -function getProxy$8() { - return this[PROXY$8]; +function getPrimitiveClass$a({ type, bitSize }) { + if (type === MemberType$a.Int || type === MemberType$a.Uint) { + if (bitSize <= 32) { + return Number; + } else { + return BigInt; + } + } else if (type === MemberType$a.Float) { + return Number; + } else if (type === MemberType$a.Bool) { + return Boolean; + } } -function copyPointer$8({ source }) { - const target = source[SLOTS$8][0]; - if (target) { - this[TARGET_SETTER$8](target); - } +const StructureType$a = { + Primitive: 0, + Array: 1, + Struct: 2, + ExternStruct: 3, + PackedStruct: 4, + ArgStruct: 5, + ExternUnion: 6, + BareUnion: 7, + TaggedUnion: 8, + ErrorUnion: 9, + ErrorSet: 10, + Enumeration: 11, + Optional: 12, + Pointer: 13, + Slice: 14, + Vector: 15, + Opaque: 16, + Function: 17, +}; + +const factories$w = {}; + +function useArgStruct$a() { + factories$w[StructureType$a.ArgStruct] = defineArgStruct$a; } -function resetPointer$8({ isActive }) { - if (this[SLOTS$8][0] && !isActive(this)) { - this[SLOTS$8][0] = undefined; - } +function getStructureFactory(type) { + const f = factories$w[type]; + return f; } -function disablePointer$8() { - const disabledProp = { get: throwInaccessiblePointer$8, set: throwInaccessiblePointer$8 }; - const disabledFunc = { value: throwInaccessiblePointer$8 }; - defineProperties$8(this[POINTER$8], { - '*': disabledProp, - '$': disabledProp, - [GETTER$8]: disabledFunc, - [SETTER$8]: disabledFunc, - [TARGET_GETTER$8]: disabledFunc, - }); +function flagMemberUsage(member, features) { + const { type } = member; + switch (type) { + case MemberType$a.Bool: + features.useBool = true; + if (!isByteAligned$a(member)) { + features.useExtendedBool = true; + } + break; + case MemberType$a.Int: + features.useInt = true; + if(!isByteAligned$a(member) || !hasStandardIntSize(member)) { + features.useExtendedInt = true; + } + break; + case MemberType$a.Uint: + features.useUint = true; + if(!isByteAligned$a(member) || !hasStandardIntSize(member)) { + features.useExtendedUint = true; + } + break; + case MemberType$a.Float: + features.useFloat = true; + if (!isByteAligned$a(member) || !hasStandardFloatSize(member)) { + features.useExtendedFloat = true; + } + break; + case MemberType$a.Object: + features.useObject = true; + break; + case MemberType$a.Void: + features.useVoid = true; + break; + case MemberType$a.Null: + features.useNull = true; + break; + case MemberType$a.Undefined: + features.useUndefined = true; + break; + case MemberType$a.Type: + features.useType = true; + break; + case MemberType$a.Comptime: + features.useComptime = true; + break; + case MemberType$a.Static: + features.useStatic = true; + break; + case MemberType$a.Literal: + features.useLiteral = true; + break; + } } -function visitPointer$8(fn, options = {}) { - const { - source, - isActive = always$8, - isMutable = always$8, - } = options; - fn.call(this, { source, isActive, isMutable }); +function flagStructureUsage(structure, features) { + const { type } = structure; + const [ name ] = Object.entries(StructureType$a).find(a => a[1] === type); + features[`use${name}`] = true; + for (const members of [ structure.instance.members, structure.static.members ]) { + for (const member of members) { + flagMemberUsage(member, features); + } + } } -function isPointerOf$8(arg, Target) { - return (arg?.constructor?.child === Target && arg['*']); +function getFeaturesUsed(structures) { + const features = {}; + for (const structure of structures) { + flagStructureUsage(structure, features); + } + return Object.keys(features); } -const proxyHandlers$h = { - get(pointer, name) { - if (name === POINTER$8) { - return pointer; - } else if (name in pointer) { - return pointer[name]; - } else { - const target = pointer[TARGET_GETTER$8](); - return target[name]; - } - }, - set(pointer, name, value) { - if (name in pointer) { - pointer[name] = value; - } else { - const target = pointer[TARGET_GETTER$8](); - target[name] = value; - } - return true; - }, - deleteProperty(pointer, name) { - if (name in pointer) { - delete pointer[name]; - } else { - const target = pointer[TARGET_GETTER$8](); - delete target[name]; +function defineProperties$a(object, descriptors) { + for (const [ name, descriptor ] of Object.entries(descriptors)) { + if (descriptor) { + const { + set, + get, + value, + enumerable, + configurable = true, + writable = true, + } = descriptor; + Object.defineProperty(object, name, (get) + ? { get, set, configurable, enumerable } + : { value, configurable, enumerable, writable } + ); } - return true; - }, - has(pointer, name) { - if (name in pointer) { - return true; - } else { - const target = pointer[TARGET_GETTER$8](); - return name in target; + } + for (const symbol of Object.getOwnPropertySymbols(descriptors)) { + const descriptor = descriptors[symbol]; + if (descriptor) { + Object.defineProperty(object, symbol, descriptor); } - }, -}; - -function always$8() { - return true; -} - -function never$8() { - return false; + } } -function defineStructShape$8(structure, env) { - const { - byteSize, - align, - instance: { members }, - hasPointer, - } = structure; - const memberDescriptors = {}; - for (const member of members) { - const { get, set } = getDescriptor$8(member, env); - memberDescriptors[member.name] = { get, set, configurable: true, enumerable: true }; - if (member.isRequired && set) { - set.required = true; +function findAllObjects(structures, SLOTS) { + const list = []; + const found = new Map(); + const find = (object) => { + if (!object || found.get(object)) { + return; } - } - const hasObject = !!members.find(m => m.type === MemberType$8.Object); - const propApplier = createPropertyApplier$8(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$8](arg); - if (hasPointer) { - this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + found.set(object, true); + list.push(object); + if (object[SLOTS]) { + for (const child of Object.values(object[SLOTS])) { + find(child); } - } else if (arg && typeof(arg) === 'object') { - propApplier.call(this, arg); - } else if (arg !== undefined) { - throwInvalidInitializer$8(structure, 'object', arg); } }; - const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); - const instanceDescriptors = { - $: { get: getSelf$8, set: initializer }, - dataView: getDataViewDescriptor$8(structure), - base64: getBase64Descriptor$8(structure), - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - ...memberDescriptors, - [Symbol.iterator]: { value: getStructIterator$8 }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, - [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, always$8) }, - [NORMALIZER$8]: { value: normalizeStruct$8 }, - [PROPS$8]: { value: members.map(m => m.name) }, - }; - const staticDescriptors = { - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, + for (const structure of structures) { + find(structure.instance.template); + find(structure.static.template); + } + return list; +} + +let currentGlobalSet$2; + +function appendErrorSet(errorSet, name, es) { + // our Zig export code places error set instance into the static template, which we can't + // use since all errors need to have the same parent class; here we get the error number + // and create the actual error object if hasn't been created already for an earlier set + const number = es[GETTER$a]('number'); + let error = currentGlobalSet$2[number]; + if (!error) { + const errorClass = errorSet[CLASS$2]; + error = new errorClass(name, number); + } + const string = String(error); + const descriptors = { + [number]: { value: error }, + [string]: { value: error }, + [name]: { value: error }, }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); + defineProperties$a(errorSet, descriptors); + defineProperties$a(currentGlobalSet$2, descriptors); + // add name to prop list + currentGlobalSet$2[PROPS$a].push(name); } -function normalizeStruct$8(cb, options) { - const object = {}; - for (const [ name, value ] of getStructEntries$8.call(this, options)) { - object[name] = cb(value); +function resetGlobalErrorSet() { + currentGlobalSet$2 = undefined; +} + +function throwArgumentCountMismatch$a(structure, actual) { + const { name, instance: { members } } = structure; + const argCount = members.length - 1; + const s = (argCount !== 1) ? 's' : ''; + throw new Error(`${name} expects ${argCount} argument${s}, received ${actual}`); +} + +function rethrowArgumentError$a(structure, index, err) { + const { name, instance: { members } } = structure; + // Zig currently does not provide the argument name + const argName = `args[${index}]`; + const argCount = members.length - 1; + const prefix = (index !== 0) ? '..., ' : ''; + const suffix = (index !== argCount - 1) ? ', ...' : ''; + const argLabel = prefix + argName + suffix; + const newError = new err.constructor(`${name}(${argLabel}): ${err.message}`); + newError.stack = err.stack; + throw newError; +} + +function throwOutOfBound$a(member, index) { + const { name } = member; + throw new RangeError(`Index exceeds the size of ${name ?? 'array'}: ${index}`); +} + +function rethrowRangeError$a(member, index, err) { + if (err instanceof RangeError) { + throwOutOfBound$a(member, index); + } else { + throw err; } - return object; } -function getStructEntries$8(options) { - return { - [Symbol.iterator]: getStructEntriesIterator$8.bind(this, options), - length: this[PROPS$8].length, - }; +function throwNotOnByteBoundary$a(member) { + const { name, structure: { name: { struct }} } = member; + throw new TypeError(`Unable to create ${struct} as it is not situated on a byte boundary: ${name}`); } -function getStructIterator$8(options) { - const entries = getStructEntries$8.call(this, options); - return entries[Symbol.iterator](); +function throwZigError(name) { + throw new Error(deanimalizeErrorName$2(name)); } -function getStructEntriesIterator$8(options) { - const self = this; - const props = this[PROPS$8]; - let index = 0; - return { - next() { - let value, done; - if (index < props.length) { - const current = props[index++]; - value = [ current, handleError$8(() => self[current], options) ]; - done = false; +function deanimalizeErrorName$2(name) { + // deal with snake_case first + let s = name.replace(/_/g, ' '); + // then camelCase, using a try block in case Unicode regex fails + try { + s = s.replace(/(\p{Uppercase}+)(\p{Lowercase}*)/gu, (m0, m1, m2) => { + if (m1.length === 1) { + return ` ${m1.toLocaleLowerCase()}${m2}`; } else { - done = true; + if (m2) { + const acronym = m1.substring(0, m1.length - 1); + const letter = m1.charAt(m1.length - 1).toLocaleLowerCase(); + return ` ${acronym} ${letter}${m2}`; + } else { + return ` ${m1}`; + } } - return { value, done }; - }, - }; -} - -function getChildVivificator$h(structure) { - const { instance: { members } } = structure; - const objectMembers = {}; - for (const member of members.filter(m => m.type === MemberType$8.Object)) { - objectMembers[member.slot] = member; + }).trimStart(); + /* c8 ignore next 2 */ + } catch (err) { } - return function vivificateChild(slot, writable = true) { - const member = objectMembers[slot]; - const { bitOffset, byteSize, structure: { constructor } } = member; - const dv = this[MEMORY$8]; - const parentOffset = dv.byteOffset; - const offset = parentOffset + (bitOffset >> 3); - let len = byteSize; - if (len === undefined) { - if (bitOffset & 7) { - throwNotOnByteBoundary$8(member); + return s.charAt(0).toLocaleUpperCase() + s.substring(1); +} + +function getBoolAccessor$a(access, member) { + return cacheMethod$a(access, member, () => { + if (isByteAligned$a(member)) { + const { byteSize } = member; + const typeName = getTypeName$a({ type: MemberType$a.Int, bitSize: byteSize * 8 }); + if (access === 'get') { + const get = DataView.prototype[`get${typeName}`]; + return function(offset, littleEndian) { + return !!get.call(this, offset, littleEndian); + }; + } else { + const set = DataView.prototype[`set${typeName}`]; + const T = (byteSize > 4) ? 1n : 1; + const F = (byteSize > 4) ? 0n : 0; + return function(offset, value, littleEndian) { + set.call(this, offset, value ? T : F, littleEndian); + }; } - len = member.bitSize >> 3; + } else { + return getExtendedTypeAccessor$a(access, member); } - const childDV = new DataView(dv.buffer, offset, len); - const object = this[SLOTS$8][slot] = constructor.call(PARENT$8, childDV, { writable }); - return object; + }); +} + +const factories$v = {}; + +function getExtendedTypeAccessor$a(access, member) { + const f = factories$v[member.type]; + return f(access, member); +} + +function getTypeName$a(member) { + const { type, bitSize, byteSize } = member; + if (type === MemberType$a.Int) { + return `${bitSize <= 32 ? '' : 'Big' }Int${bitSize}`; + } else if (type === MemberType$a.Uint) { + return `${bitSize <= 32 ? '' : 'Big' }Uint${bitSize}`; + } else if (type === MemberType$a.Float) { + return `Float${bitSize}`; + } else if (type === MemberType$a.Bool) { + const boolSize = (byteSize !== undefined) ? byteSize * 8 : 1; + return `Bool${boolSize}`; + } else if (type === MemberType$a.Void) { + return `Null`; } } -function getPointerVisitor$h(structure, visitorOptions = {}) { - const { - isChildActive = always$8, - isChildMutable = always$8, - } = visitorOptions; - const { instance: { members } } = structure; - const pointerMembers = members.filter(m => m.structure.hasPointer); - return function visitPointers(cb, options = {}) { - const { - source, - vivificate = false, - isActive = always$8, - isMutable = always$8, - } = options; - const childOptions = { - ...options, - isActive: (object) => { - // make sure parent object is active, then check whether the child is active - return isActive(this) && isChildActive.call(this, object); - }, - isMutable: (object) => { - return isMutable(this) && isChildMutable.call(this, object); - }, - }; - for (const { slot } of pointerMembers) { - if (source) { - // when src is a the struct's template, most slots will likely be empty, - // since pointer fields aren't likely to have default values - const srcChild = source[SLOTS$8]?.[slot]; - if (!srcChild) { - continue; - } - childOptions.source = srcChild; - } - const child = this[SLOTS$8][slot] ?? (vivificate ? this[VIVIFICATOR$8](slot) : null); - if (child) { - child[POINTER_VISITOR$8](cb, childOptions); - } - } - }; -} +const methodCache$a = {}; -function defineArgStruct$8(structure, env) { - const { - byteSize, - align, - instance: { members }, - hasPointer, - } = structure; - const hasObject = !!members.find(m => m.type === MemberType$8.Object); - const constructor = structure.constructor = function(args) { - const dv = env.allocateMemory(byteSize, align); - this[MEMORY$8] = dv; - if (hasObject) { - this[SLOTS$8] = {}; +function cacheMethod$a(access, member, cb) { + const { type, bitOffset, bitSize, structure } = member; + const bitPos = bitOffset & 0x07; + const typeName = getTypeName$a(member); + const suffix = isByteAligned$a(member) ? `` : `Bit${bitPos}`; + const isInt = type === MemberType$a.Int || type === MemberType$a.Uint; + let name = `${access}${typeName}${suffix}`; + let isSize = false, originalName = name; + if (isInt && bitSize === 64) { + const zigTypeName = structure?.name; + if (zigTypeName === 'usize' || zigTypeName === 'isize') { + name += 'Size'; + isSize = true; } - initializer.call(this, args); - }; - const argNames = members.slice(0, -1).map(m => m.name); - const argCount = argNames.length; - const initializer = function(args) { - if (args.length !== argCount) { - throwArgumentCountMismatch$8(structure, args.length); + } + let fn = methodCache$a[name]; + if (!fn) { + if (isInt && access === 'set') { + // add auto-conversion between number and bigint + const Primitive = getPrimitiveClass$a(member); + const set = cb(originalName); + fn = function(offset, value, littleEndian) { + set.call(this, offset, Primitive(value), littleEndian); + }; + } else if (isSize && access === 'get') { + // use number instead of bigint where possible + const get = cb(originalName); + const min = BigInt(Number.MIN_SAFE_INTEGER); + const max = BigInt(Number.MAX_SAFE_INTEGER); + fn = function(offset, littleEndian) { + const value = get.call(this, offset, littleEndian); + if (min <= value && value <= max) { + return Number(value); + } else { + return value; + } + }; + } else { + fn = cb(name); } - for (const [ index, name ] of argNames.entries()) { - try { - this[name] = args[index]; - } catch (err) { - rethrowArgumentError$8(structure, index, err); - } + if (fn && fn.name !== name) { + Object.defineProperty(fn, 'name', { value: name, configurable: true, writable: false }); } - }; - const memberDescriptors = {}; - for (const member of members) { - memberDescriptors[member.name] = getDescriptor$8(member, env); + methodCache$a[name] = fn; } - const isChildMutable = function(object) { - return (object === this.retval); - }; - defineProperties$8(constructor.prototype, { - ...memberDescriptors, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, - [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, { isChildMutable }) }, - }); - defineProperties$8(constructor, { - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, - }); - return constructor; + return fn; } -function defineArray$8(structure, env) { - const { - length, - byteSize, - align, - instance: { members: [ member ] }, - hasPointer, - } = structure; - const { get, set } = getDescriptor$8(member, env); - const hasStringProp = canBeString$8(member); - const propApplier = createPropertyApplier$8(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$8](arg); - if (hasPointer) { - this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); - } - } else { - if (typeof(arg) === 'string' && hasStringProp) { - arg = { string: arg }; - } - if (arg?.[Symbol.iterator]) { - arg = transformIterable$8(arg); - if (arg.length !== length) { - throwArrayLengthMismatch$8(structure, this, arg); - } - let i = 0; - for (const value of arg) { - set.call(this, i++, value); - } - } else if (arg && typeof(arg) === 'object') { - if (propApplier.call(this, arg) === 0) { - throwInvalidArrayInitializer$8(structure, arg); - } - } else if (arg !== undefined) { - throwInvalidArrayInitializer$8(structure, arg); - } - } - }; - const finalizer = createArrayProxy$8; - const constructor = structure.constructor = createConstructor$8(structure, { initializer, finalizer }, env); - const typedArray = structure.typedArray = getTypedArrayClass$8(member); - const hasObject = member.type === MemberType$8.Object; - const instanceDescriptors = { - $: { get: getProxy$8, set: initializer }, - length: { value: length }, - dataView: getDataViewDescriptor$8(structure), - base64: getBase64Descriptor$8(structure), - string: hasStringProp && getStringDescriptor$8(structure), - typedArray: typedArray && getTypedArrayDescriptor$8(structure), - get: { value: get }, - set: { value: set }, - entries: { value: getArrayEntries$8 }, - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - [Symbol.iterator]: { value: getArrayIterator$8 }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$g(structure) }, - [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$g() }, - [NORMALIZER$8]: { value: normalizeArray$8 }, - }; - const staticDescriptors = { - child: { get: () => member.structure.constructor }, - [COMPAT$8]: { value: getCompatibleTags$8(structure) }, - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, - }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +const MemberType$a = { + Void: 0, + Bool: 1, + Int: 2, + Uint: 3, + Float: 4, + Object: 5, + Type: 6, + Comptime: 7, + Static: 8, + Literal: 9, + Null: 10, + Undefined: 11, +}; + +function isReadOnly$a(type) { + switch (type) { + case MemberType$a.Type: + case MemberType$a.Comptime: + case MemberType$a.Literal: + return true; + default: + return false; + } } -function createArrayProxy$8() { - const proxy = new Proxy(this, proxyHandlers$g); - // hide the proxy so console wouldn't display a recursive structure - Object.defineProperty(this, PROXY$8, { value: proxy }); - return proxy; +const factories$u = {}; + +function useBool$a() { + factories$u[MemberType$a.Bool] = getBoolDescriptor$a; } -function canBeString$8(member) { - return member.type === MemberType$8.Uint && [ 8, 16 ].includes(member.bitSize); +function useObject$a() { + factories$u[MemberType$a.Object] = getObjectDescriptor$a; } -function normalizeArray$8(cb, options) { - const array = []; - for (const [ index, value ] of getArrayEntries$8.call(this, options)) { - array.push(cb(value)); - } - return array; +function isByteAligned$a({ bitOffset, bitSize, byteSize }) { + return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; } -function getArrayIterator$8() { - const self = this[ARRAY$8] ?? this; - const length = this.length; - let index = 0; - return { - next() { - let value, done; - if (index < length) { - const current = index++; - value = self.get(current); - done = false; - } else { - done = true; - } - return { value, done }; - }, - }; +function hasStandardIntSize({ bitSize }) { + return bitSize === 8 || bitSize === 16 || bitSize === 32 || bitSize === 64; } -function getArrayEntriesIterator$8(options) { - const self = this[ARRAY$8] ?? this; - const length = this.length; - let index = 0; - return { - next() { - let value, done; - if (index < length) { - const current = index++; - value = [ current, handleError$8(() => self.get(current), options) ]; - done = false; - } else { - done = true; - } - return { value, done }; - }, - }; +function hasStandardFloatSize({ bitSize }) { + return bitSize === 32 || bitSize === 64; } -function getArrayEntries$8(options) { - return { - [Symbol.iterator]: getArrayEntriesIterator$8.bind(this, options), - length: this.length, - }; +function getDescriptor$a(member, env) { + const f = factories$u[member.type]; + return f(member, env); } -function getChildVivificator$g(structure) { - const { instance: { members: [ member ]} } = structure; - const { byteSize, structure: elementStructure } = member; - return function getChild(index, writable = true) { - const { constructor } = elementStructure; - const dv = this[MEMORY$8]; - const parentOffset = dv.byteOffset; - const offset = parentOffset + byteSize * index; - const childDV = new DataView(dv.buffer, offset, byteSize); - const object = this[SLOTS$8][index] = constructor.call(PARENT$8, childDV, { writable }); - return object; - }; +function getBoolDescriptor$a(member, env) { + return getDescriptorUsing$a(member, env, getBoolAccessor$a) } -function getPointerVisitor$g(structure) { - return function visitPointers(cb, options = {}) { - const { - source, - vivificate = false, - isActive = always$8, - isMutable = always$8, - } = options; - const childOptions = { - ...options, - isActive: () => isActive(this), - isMutable: () => isMutable(this), - }; - for (let i = 0, len = this.length; i < len; i++) { - // no need to check for empty slots, since that isn't possible - if (source) { - childOptions.source = source?.[SLOTS$8][i]; - } - const child = this[SLOTS$8][i] ?? (vivificate ? this[VIVIFICATOR$8](i) : null); - if (child) { - child[POINTER_VISITOR$8](cb, childOptions); - } - } - }; +function isValueExpected$a(structure) { + switch (structure.type) { + case StructureType$a.Primitive: + case StructureType$a.ErrorUnion: + case StructureType$a.Optional: + case StructureType$a.Enumeration: + case StructureType$a.ErrorSet: + return true; + default: + return false; + } } -function transformIterable$8(arg) { - if (typeof(arg.length) === 'number') { - // it's an array of sort - return arg; - } - const iterator = arg[Symbol.iterator](); - const first = iterator.next(); - const length = first.value?.length; - if (typeof(length) === 'number' && Object.keys(first.value).join() === 'length') { - // return generator with length attached - return Object.assign((function*() { - let result; - while (!(result = iterator.next()).done) { - yield result.value; - } - })(), { length }); +function getValue$a(slot) { + const object = this[SLOTS$a][slot] ?? this[VIVIFICATOR$a](slot); + return object[GETTER$a](); +} + +function getObject$a(slot) { + const object = this[SLOTS$a][slot] ?? this[VIVIFICATOR$a](slot); + return object; +} + +function setValue$a(slot, value) { + const object = this[SLOTS$a][slot] ?? this[VIVIFICATOR$a](slot); + object[SETTER$a](value); +} + +function bindSlot$a(slot, { get, set }) { + if (slot !== undefined) { + return { + get: function() { + return get.call(this, slot); + }, + set: (set) + ? function(arg) { + return set.call(this, slot, arg); + } + : undefined, + }; } else { - const array = []; - let result = first; - while (!result.done) { - array.push(result.value); - result = iterator.next(); - } - return array; + // array accessors + return { get, set }; } } -const proxyHandlers$g = { - get(array, name) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - return array.get(index); - } else { - switch (name) { - case 'get': - if (!array[ELEMENT_GETTER$8]) { - array[ELEMENT_GETTER$8] = array.get.bind(array); +function getObjectDescriptor$a(member, env) { + const { structure, slot } = member; + return bindSlot$a(slot, { + get: isValueExpected$a(structure) ? getValue$a : getObject$a, + set: setValue$a, + }); +} + +function getDescriptorUsing$a(member, env, getDataViewAccessor) { + const { + littleEndian = true, + } = env; + const { bitOffset, byteSize } = member; + const getter = getDataViewAccessor('get', member); + const setter = getDataViewAccessor('set', member); + if (bitOffset !== undefined) { + const offset = bitOffset >> 3; + return { + get: function getValue() { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return getter.call(this[MEMORY$a], offset, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$a.call(this)) { + return getter.call(this[MEMORY$a], offset, littleEndian); + } else { + throw err; } - return array[ELEMENT_GETTER$8]; - case 'set': - if (!array[ELEMENT_SETTER$8]) { - array[ELEMENT_SETTER$8] = array.set.bind(array); + } + /* WASM-ONLY-END*/ + }, + set: function setValue(value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return setter.call(this[MEMORY$a], offset, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$a.call(this)) { + return setter.call(this[MEMORY$a], offset, value, littleEndian); + } else { + throw err; } - return array[ELEMENT_SETTER$8]; - case ARRAY$8: - return array; - default: - return array[name]; - } - } - }, - set(array, name, value) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - array.set(index, value); - } else { - switch (name) { - case 'get': - array[ELEMENT_GETTER$8] = value; - break; - case 'set': - array[ELEMENT_SETTER$8] = value; - break; - default: - array[name] = value; - } - } - return true; - }, - deleteProperty(array, name) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - return false; - } else { - switch (name) { - case 'get': - delete array[ELEMENT_GETTER$8]; - break; - case 'set': - delete array[ELEMENT_SETTER$8]; - break; - default: - delete array[name]; + } + /* WASM-ONLY-END*/ } - return true; - } - }, - has(array, name) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - return (index >= 0 && index < array.length); - } else { - return array[name]; - } - }, - ownKeys(array) { - const keys = []; - for (let i = 0, len = array.length; i < len; i++) { - keys.push(`${i}`); } - keys.push('length', PROXY$8); - return keys; - }, - getOwnPropertyDescriptor(array, name) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - if (index >= 0 && index < array.length) { - return { value: array.get(index), enumerable: true, writable: true, configurable: true }; - } - } else { - return Object.getOwnPropertyDescriptor(array, name); + } else { + return { + get: function getElement(index) { + try { + return getter.call(this[MEMORY$a], index * byteSize, littleEndian); + } catch (err) { + /* WASM-ONLY */ + if (err instanceof TypeError && restoreMemory$a.call(this)) { + return getter.call(this[MEMORY$a], index * byteSize, littleEndian); + } else { + /* WASM-ONLY-END */ + rethrowRangeError$a(member, index, err); + /* WASM-ONLY */ + } + /* WASM-ONLY-END */ + } + }, + set: function setElement(index, value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END */ + return setter.call(this[MEMORY$a], index * byteSize, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$a.call(this)) { + return setter.call(this[MEMORY$a], index * byteSize, value, littleEndian); + } else { + rethrowRangeError$a(member, index, err); + } + } + /* WASM-ONLY-END */ + }, } - }, -}; + } +} -function defineEnumerationShape$8(structure, env) { +function generateCode(definition, params) { + const { structures } = definition; const { - byteSize, - align, - instance: { - members: [ member ], - }, - } = structure; - const { get: getIndex, set: setIndex } = getDescriptor$8(member, env); - // get the enum descriptor instead of the int/uint descriptor - const { get, set } = getDescriptor$8({ ...member, type: MemberType$8.EnumerationItem, structure }, env); - const expected = [ 'string', 'number', 'tagged union' ]; - const propApplier = createPropertyApplier$8(structure); - const initializer = function(arg) { - if (arg && typeof(arg) === 'object') { - if (propApplier.call(this, arg) === 0) { - throwInvalidInitializer$8(structure, expected, arg); - } - } else if (arg !== undefined) { - set.call(this, arg); - } - }; - const alternateCaster = function(arg) { - if (typeof(arg) === 'string' || typeof(arg) === 'number' || typeof(arg) === 'bigint') { - const items = constructor[ITEMS$8]; - let item = items[arg]; - if (!item) { - if (constructor[MORE$8] && typeof(arg) !== 'string') { - // create the item on-the-fly when enum is non-exhaustive - item = items[arg] = new constructor(undefined); - setIndex.call(item, arg); - defineProperties$8(item, { [NAME$8]: { value: `${arg}` } }); - } - } - return item; - } else if (arg?.[TAG$8] instanceof constructor) { - // a tagged union, return the active tag - return arg[TAG$8]; - } else if (!getDataView$8(structure, arg, env)) { - throwInvalidInitializer$8(structure, expected, arg); + runtimeURL, + binarySource = null, + topLevelAwait = true, + omitExports = false, + declareFeatures = false, + addonDir = null, + } = params; + const features = (declareFeatures) ? getFeaturesUsed(structures) : []; + const exports = getExports(structures); + const lines = []; + const add = manageIndentation(lines); + add(`import {`); + for (const name of [ 'createEnvironment', ...features ]) { + add(`${name},`); + } + add(`} from ${JSON.stringify(runtimeURL)};`); + // reduce file size by only including code of features actually used + // dead-code remover will take out code not referenced here + add(`\n// activate features`); + for (const feature of features) { + add(`${feature}();`); + } + // write out the structures as object literals + addStructureDefinitions(lines, definition); + add(`\n// create runtime environment`); + add(`const env = createEnvironment(${addonDir ? JSON.stringify({ addonDir }, undefined, 2) : null});`); + add(`const __zigar = env.getControlObject();`); + add(`\n// recreate structures`); + add(`env.recreateStructures(structures, options);`); + if (binarySource) { + add(`\n// initiate loading and compilation of WASM bytecodes`); + add(`const source = ${binarySource};`); + add(`env.loadModule(source)`); + // if top level await is used, we don't need to write changes into fixed memory buffers + add(`env.linkVariables(${!topLevelAwait});`); + } + add(`\n// export root namespace and its methods and constants`); + add(`const { constructor } = root;`); + if (!omitExports) { + add(`export { constructor as default, __zigar }`); + // the first two exports are default and __zigar + const exportables = exports.slice(2); + if (exportables.length > 0) { + add(`export const {`); + for (const name of exportables) { + add(`${name},`); + } + add(`} = constructor;`); + } + } + if (topLevelAwait && binarySource) { + add(`await __zigar.init();`); + } + const code = lines.join('\n'); + return { code, exports, structures }; +} + +function addStructureDefinitions(lines, definition) { + const { structures, options, keys } = definition; + const { MEMORY, SLOTS, CONST } = keys; + const add = manageIndentation(lines); + const defaultStructure = { + constructor: null, + typedArray: null, + type: StructureType$a.Primitive, + name: undefined, + byteSize: 0, + align: 0, + isConst: false, + hasPointer: false, + instance: { + members: [], + methods: [], + template: null, + }, + static: { + members: [], + methods: [], + template: null, + }, + }; + add(`\n// structure defaults`); + add(`const s = {`); + for (const [ name, value ] of Object.entries(defaultStructure)) { + switch (name) { + case 'instance': + case 'static': + add(`${name}: {`); + for (const [ name2, value2 ] of Object.entries(value)) { + add(`${name2}: ${JSON.stringify(value2)},`); + } + add(`},`); + break; + default: + add(`${name}: ${JSON.stringify(value)},`); + } + } + add(`};`); + const defaultMember = { + type: MemberType$a.Void, + isRequired: false, + }; + add(`\n// member defaults`); + add(`const m = {`); + for (const [ name, value ] of Object.entries(defaultMember)) { + add(`${name}: ${JSON.stringify(value)},`); + } + add(`};`); + // create empty objects first, to allow objects to reference each other + add(``); + const structureNames = new Map(); + const structureMap = new Map(); + for (const [ index, structure ] of structures.entries()) { + const varname = `s${index}`; + structureNames.set(structure, varname); + structureMap.set(structure.constructor, structure); + } + for (const slice of chunk(structureNames.values(), 10)) { + add(`const ${slice.map(n => `${n} = {}`).join(', ')};`); + } + const objects = findAllObjects(structures, SLOTS); + const objectNames = new Map(); + const views = []; + for (const [ index, object ] of objects.entries()) { + const varname = `o${index}`; + objectNames.set(object, varname); + if (object[MEMORY]) { + views.push(object[MEMORY]); + } + } + for (const slice of chunk(objectNames.values(), 10)) { + add(`const ${slice.map(n => `${n} = {}`).join(', ')};`); + } + // define buffers + const arrayBufferNames = new Map(); + for (const [ index, dv ] of views.entries()) { + if (!arrayBufferNames.get(dv.buffer)) { + const varname = `a${index}`; + arrayBufferNames.set(dv.buffer, varname); + if (dv.buffer.byteLength > 0) { + const ta = new Uint8Array(dv.buffer); + add(`const ${varname} = new Uint8Array([ ${ta.join(', ')} ]);`); + } else { + add(`const ${varname} = new Uint8Array();`); + } + } + } + // add properties to objects + if (objects.length > 0) { + add('\n// define objects'); + for (const object of objects) { + const varname = objectNames.get(object); + const structure = structureMap.get(object.constructor); + const { [MEMORY]: dv, [SLOTS]: slots } = object; + add(`Object.assign(${varname}, {`); + if (structure) { + add(`structure: ${structureNames.get(structure)},`); + } + if (dv) { + const buffer = arrayBufferNames.get(dv.buffer); + const pairs = [ `array: ${buffer}` ]; + if (dv.byteLength < dv.buffer.byteLength) { + pairs.push(`offset: ${dv.byteOffset}`); + pairs.push(`length: ${dv.byteLength}`); + } + add(`memory: { ${pairs.join(', ')} },`); + if (dv.hasOwnProperty('reloc')) { + add(`reloc: ${dv.reloc},`); + if (object[CONST]) { + add(`const: true,`); + } + } + } + const entries = (slots) ? Object.entries(slots).filter(a => a[1]) : []; + if (entries.length > 0) { + add(`slots: {`); + const pairs = entries.map(([slot, child]) => `${slot}: ${objectNames.get(child)}`); + for (const slice of chunk(pairs, 10)) { + add(slice.join(', ') + ','); + } + add(`},`); + } + add(`});`); + } + } + const methods = []; + for (const structure of structures) { + // add static members; instance methods are also static methods, so + // we don't need to add them separately + methods.push(...structure.static.methods); + } + const methodNames = new Map(); + if (methods.length > 0) { + add(`\n// define functions`); + for (const [ index, method ] of methods.entries()) { + const varname = `f${index}`; + methodNames.set(method, varname); + add(`const ${varname} = {`); + for (const [ name, value ] of Object.entries(method)) { + switch (name) { + case 'argStruct': + add(`${name}: ${structureNames.get(value)},`); + break; + default: + add(`${name}: ${JSON.stringify(value)},`); + } + } + add(`};`); + } + } + add('\n// define structures'); + for (const structure of structures) { + const varname = structureNames.get(structure); + add(`Object.assign(${varname}, {`); + add(`...s,`); + for (const [ name, value ] of Object.entries(structure)) { + if (isDifferent(value, defaultStructure[name])) { + switch (name) { + case 'constructor': + case 'typedArray': + case 'sentinel': + break; + case 'instance': + case 'static': { + const { methods, members, template } = value; + add(`${name}: {`); + add(`members: [`); + for (const member of members) { + add(`{`); + add(`...m,`); + for (const [ name, value ] of Object.entries(member)) { + if (isDifferent(value, defaultMember[name])) { + switch (name) { + case 'structure': + add(`${name}: ${structureNames.get(value)},`); + break; + default: + add(`${name}: ${JSON.stringify(value)},`); + } + } + } + add(`},`); + } + add(`],`); + add(`methods: [`); + for (const slice of chunk(methods, 10)) { + add(slice.map(m => methodNames.get(m)).join(', ') + ','); + } + add(`],`); + if (template) { + add(`template: ${objectNames.get(template)}`); + } + add(`},`); + } break; + default: + add(`${name}: ${JSON.stringify(value)},`); + } + } + } + add(`});`); + } + add(`const structures = [`); + for (const slice of chunk([ ...structureNames.values() ], 10)) { + add(slice.join(', ') + ','); + } + add(`];`); + const root = structures[structures.length - 1]; + add(`const root = ${structureNames.get(root)};`); + add(`const options = {`); + for (const [ name, value ] of Object.entries(options)) { + add(`${name}: ${value},`); + } + add(`};`); + return lines; +} + +function getExports(structures) { + const root = structures[structures.length - 1]; + const { constructor } = root; + const exportables = []; + // export only members whose names are legal JS identifiers + const legal = /^[$\w]+$/; + for (const method of root.static.methods) { + if (legal.test(method.name)) { + exportables.push(method.name); + } + } + for (const member of root.static.members) { + // only read-only properties are exportable + if (isReadOnly$a(member.type) && legal.test(member.name)) { + try { + // make sure that getter wouldn't throw (possible with error union) + constructor[member.name]; + exportables.push(member.name); + } catch (err) { + } + } + } + return [ 'default', '__zigar', ...exportables ]; +} + +function manageIndentation(lines) { + let indent = 0; + return (s) => { + if (/^\s*[\]\}]/.test(s)) { + indent--; + } + const lastLine = lines[lines.length - 1]; + if ((lastLine?.endsWith('[') && s.startsWith(']')) + || (lastLine?.endsWith('{') && s.startsWith('}'))) { + lines[lines.length - 1] += s; + } else { + lines.push(' '.repeat(indent * 2) + s); + } + if (/[\[\{]\s*$/.test(s)) { + indent++; + } + }; +} + +function isDifferent(value, def) { + if (value === def) { + return false; + } + if (def == null) { + return value != null; + } + if (typeof(def) === 'object' && typeof(value) === 'object') { + const valueKeys = Object.keys(value); + const defKeys = Object.keys(def); + if (valueKeys.length !== defKeys.length) { + return true; + } + for (const key of defKeys) { + if (isDifferent(value[key], def[key])) { + return true; + } + } + return false; + } + return true; +} + +function* chunk(arr, n) { + if (!Array.isArray(arr)) { + arr = [ ...arr ]; + } + for (let i = 0; i < arr.length; i += n) { + yield arr.slice(i, i + n); + } +} + +async function findFile(path, follow = true) { + try { + return await (follow ? promises.stat(path) : promises.lstat(path)); + } catch (err) { + } +} + +function findFileSync(path, follow = true) { + try { + return follow ? fs.statSync(path) : fs.lstatSync(path); + } catch (err) { + } +} + +async function findMatchingFiles(dir, re) { + const map = new Map(); + const scanned = new Map(); + const scan = async (dir) => { + /* c8 ignore next 3 */ + if (scanned.get(dir)) { + return; + } + scanned.set(dir, true); + try { + const list = await promises.readdir(dir); + for (const name of list) { + if (name.startsWith('.') || name === 'node_modules' || name === 'zig-cache') { + continue; + } + const path$1 = path.join(dir, name); + const info = await findFile(path$1); + if (info?.isDirectory()) { + await scan(path$1); + } else if (info?.isFile() && re.test(name)) { + map.set(path$1, info); + } + } + /* c8 ignore next 2 */ + } catch (err) { + } + }; + await scan(dir); + return map; +} + +function findMatchingFilesSync(dir, re) { + const map = new Map(); + const scanned = new Map(); + const scan = (dir) => { + /* c8 ignore next 3 */ + if (scanned.get(dir)) { + return; + } + scanned.set(dir, true); + try { + const list = fs.readdirSync(dir); + for (const name of list) { + if (name.startsWith('.') || name === 'node_modules' || name === 'zig-cache') { + continue; + } + const path$1 = path.join(dir, name); + const info = findFileSync(path$1); + if (info?.isDirectory()) { + scan(path$1); + } else if (info?.isFile() && re.test(name)) { + map.set(path$1, info); + } + } + /* c8 ignore next 2 */ + } catch (err) { + } + }; + scan(dir); + return map; +} + +async function acquireLock(pidPath, staleTime) { + while (true) { + try { + await createDirectory(path.dirname(pidPath)); + const handle = await promises.open(pidPath, 'wx'); + handle.write(`${process.pid}`); + handle.close(); + break; + } catch (err) { + if (err.code === 'EEXIST') { + if (checkPidFile(pidPath, staleTime)) { + await delay(250); + continue; + } + } else { + throw err; + } + } + } +} + +function acquireLockSync(pidPath, staleTime) { + while (true) { + try { + createDirectorySync(path.dirname(pidPath)); + const handle = fs.openSync(pidPath, 'wx'); + fs.writeSync(handle, `${process.pid}`); + fs.closeSync(handle); + break; + } catch (err) { + if (err.code === 'EEXIST') { + if (checkPidFile(pidPath, staleTime)) { + delaySync(250); + } + } else { + throw err; + } + } + } +} + +async function releaseLock(pidPath) { + await deleteFile(pidPath); +} + +function releaseLockSync(pidPath) { + deleteFileSync(pidPath); +} + +function checkPidFile(pidPath, staleTime = 60000 * 5) { + let stale = false; + try { + const pid = loadFileSync(pidPath); + if (os.platform() === 'win32') { + child_process.execSync(`tasklist /nh /fi "pid eq ${pid}" | findstr .exe`, { stdio: 'pipe' }).toString(); + } else { + child_process.execSync(`ps -p ${pid}`).toString(); + } + const last = findFileSync(pidPath)?.mtime || 0; + const diff = new Date() - last; + if (diff > staleTime) { + stale = true; + } + } catch (err) { + stale = true; + } + if (stale) { + deleteFileSync(pidPath); + } + return !stale; +} + +async function copyFile(srcPath, dstPath) { + const info = await promises.stat(srcPath); + const data = await promises.readFile(srcPath); + await promises.writeFile(dstPath, data); + await promises.chmod(dstPath, info.mode); +} + +function copyFileSync(srcPath, dstPath) { + const info = fs.statSync(srcPath); + const data = fs.readFileSync(srcPath); + fs.writeFileSync(dstPath, data); + fs.chmodSync(dstPath, info.mode); +} + +async function loadFile(path, def) { + try { + return await promises.readFile(path, 'utf8'); + } catch (err) { + return def; + } +} + +function loadFileSync(path, def) { + try { + return fs.readFileSync(path, 'utf8'); + } catch (err) { + return def; + } +} + +async function deleteFile(path) { + try { + await promises.unlink(path); + } catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + throw err; + } + } +} + +function deleteFileSync(path) { + try { + fs.unlinkSync(path); + } catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + throw err; + } + } +} + +async function createDirectory(path$1) { + const exists = await findDirectory(path$1); + if (!exists) { + const { root, dir } = path.parse(path$1); + await createDirectory(dir); + try { + await promises.mkdir(path$1); + } catch (err) { + /* c8 ignore next 3 */ + if (err.code != 'EEXIST') { + throw err; + } + } + } +} + +function createDirectorySync(path$1) { + const exists = findDirectorySync(path$1); + if (!exists) { + const { root, dir } = path.parse(path$1); + createDirectorySync(dir); + try { + fs.mkdirSync(path$1); + } catch (err) { + /* c8 ignore next 3 */ + if (err.code != 'EEXIST') { + throw err; + } + } + } +} + +async function findDirectory(path) { + return findFile(path); +} + +function findDirectorySync(path) { + return findFileSync(path); +} + +async function deleteDirectory(dir) { + try { + const list = await promises.readdir(dir); + for (const name of list) { + const path$1 = path.join(dir, name); + const info = await findFile(path$1, false); + if (info?.isDirectory()) { + await deleteDirectory(path$1); + } else if (info) { + await deleteFile(path$1); + } + } + await promises.rmdir(dir); + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + } +} + +function deleteDirectorySync(dir) { + try { + const list = fs.readdirSync(dir); + for (const name of list) { + const path$1 = path.join(dir, name); + const info = findFileSync(path$1, false); + if (info?.isDirectory()) { + deleteDirectorySync(path$1); + } else if (info) { + deleteFileSync(path$1); + } + } + fs.rmdirSync(dir); + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + } +} + +async function delay(ms) { + await new Promise(r => setTimeout(r, ms)); +} + +function delaySync(ms) { + const buffer = new SharedArrayBuffer(8); + const ta = new BigInt64Array(buffer); + Atomics.wait(ta, 0, 0n, ms); +} + +function md5(text) { + const hash = crypto.createHash('md5'); + hash.update(text); + return hash.digest('hex'); +} + +let isGNU; + +function getPlatform() { + let platform = os.platform(); + if (platform === 'linux') { + // differentiate glibc from musl + if (isGNU === undefined) { + /* c8 ignore next 3 */ + if (process.versions?.electron || process.__nwjs) { + isGNU = true; + } else { + try { + child_process.execFileSync('getconf', [ 'GNU_LIBC_VERSION' ], { stdio: 'pipe' }); + isGNU = true; + /* c8 ignore next 3 */ + } catch (err) { + isGNU = false; + } + } + } + /* c8 ignore next 3 */ + if (!isGNU) { + platform += '-musl'; + } + } + return platform; +} + +function getArch() { + return os.arch(); +} + +function normalizePath(url$1) { + let archive; + const parts = url.fileURLToPath(url$1).split(path.sep).map((part) => { + if (part === 'app.asar') { + archive = 'asar'; + return part + '.unpacked'; + } + return part; + }); + const path$1 = parts.join(path.sep); + return { path: path$1, archive } +} + +async function compile(srcPath, modPath, options) { + const srcInfo = (srcPath) ? await findFile(srcPath) : null; + if (srcInfo === undefined) { + throw new Error(`Source file not found: ${srcPath}`); + } + if (srcInfo?.isDirectory()) { + srcPath = path.join(srcPath, '?'); + } + const config = createConfig(srcPath, modPath, options); + const { moduleDir, outputPath } = config; + let changed = false; + if (srcPath) { + const srcFileMap = await findMatchingFiles(moduleDir, /.\..*$/); + // see if the (re-)compilation is necessary + const soInfo = await findFile(outputPath); + if (soInfo) { + for (const [ name, info ] of srcFileMap) { + if (info.mtime > soInfo.mtime) { + changed = true; + break; + } + } + } else { + changed = true; + } + if (!changed) { + // rebuild when exporter or build files have changed + const zigFolder = absolute('../zig'); + const zigFileMap = await findMatchingFiles(zigFolder, /\.zig$/); + for (const [ path, info ] of zigFileMap) { + if (info.mtime > soInfo.mtime) { + changed = true; + break; + } + } + } + if (changed) { + // add custom build file + for (const [ path$1, info ] of srcFileMap) { + switch (path.basename(path$1)) { + case 'build.zig': + config.buildFilePath = path$1; + break; + case 'build.zig.zon': + config.packageConfigPath = path$1; + break; + } + } + const { zigCmd, moduleBuildDir } = config; + // only one process can compile a given file at a time + const pidPath = `${moduleBuildDir}.pid`; + await acquireLock(pidPath); + try { + // create config file + await createProject(config, moduleBuildDir); + // then run the compiler + await runCompiler(zigCmd, moduleBuildDir); + } finally { + if (config.clean) { + await deleteDirectory(moduleBuildDir); + } + await releaseLock(pidPath); + } + } + } + return { outputPath, changed } +} + +function compileSync(srcPath, modPath, options) { + const srcInfo = (srcPath) ? findFileSync(srcPath) : null; + if (srcInfo === undefined) { + throw new Error(`Source file not found: ${srcPath}`); + } + if (srcInfo?.isDirectory()) { + srcPath = path.join(srcPath, '?'); + } + const config = createConfig(srcPath, modPath, options); + const { moduleDir, outputPath } = config; + let changed = false; + if (srcPath) { + const srcFileMap = findMatchingFilesSync(moduleDir, /.\..*$/); + // see if the (re-)compilation is necessary + const soInfo = findFileSync(outputPath); + if (soInfo) { + for (const [ path, info ] of srcFileMap) { + if (info.mtime > soInfo.mtime) { + changed = true; + break; + } + } + } else { + changed = true; + } + if (!changed) { + // rebuild when exporter or build files have changed + const zigFolder = absolute('../zig'); + const zigFileMap = findMatchingFilesSync(zigFolder, /\.zig$/); + for (const [ path, info ] of zigFileMap) { + if (info.mtime > soInfo.mtime) { + changed = true; + break; + } + } + } + if (changed) { + // add custom build file + for (const [ path$1, info ] of srcFileMap) { + switch (path.basename(path$1)) { + case 'build.zig': + config.buildFilePath = path$1; + break; + case 'build.zig.zon': + config.packageConfigPath = path$1; + break; + } + } + const { zigCmd, moduleBuildDir } = config; + // only one process can compile a given file at a time + const pidPath = `${moduleBuildDir}.pid`; + acquireLockSync(pidPath); + try { + // create config file + createProjectSync(config, moduleBuildDir); + // then run the compiler + runCompilerSync(zigCmd, moduleBuildDir); + } finally { + if (config.clean) { + deleteDirectorySync(moduleBuildDir); + } + releaseLockSync(pidPath); + } + } + } + return { outputPath, changed } +} + +async function runCompiler(zigCmd, soBuildDir) { + const options = { + cwd: soBuildDir, + windowsHide: true, + }; + return new Promise((resolve, reject) => { + child_process.exec(zigCmd, options, (err, stdout, stderr) => { + if (err) { + const log = stderr; + if (log) { + const logPath = path.join(soBuildDir, 'log'); + promises.writeFile(logPath, log); + err = new Error(`Zig compilation failed\n\n${log}`); + } + reject(err); + } else { + resolve(); + } + }); + }); +} + +function runCompilerSync(zigCmd, soBuildDir) { + const options = { + cwd: soBuildDir, + windowsHide: true, + stdio: 'pipe', + }; + try { + child_process.execSync(zigCmd, options); + } catch (err) { + const log = err.stderr; + if (log) { + const logPath = path.join(soBuildDir, 'log'); + fs.writeFileSync(logPath, log); + } + throw new Error(`Zig compilation failed\n\n${log}`); + } +} + +function formatProjectConfig(config) { + const lines = []; + const fields = [ + 'moduleName', 'modulePath', 'moduleDir', 'exporterPath', 'stubPath', 'outputPath', + 'useLibc', 'isWASM', + ]; + for (const [ name, value ] of Object.entries(config)) { + if (fields.includes(name)) { + const snakeCase = name.replace(/[A-Z]+/g, m => '_' + m.toLowerCase()); + lines.push(`pub const ${snakeCase} = ${JSON.stringify(value)};`); + } + } + return lines.join('\n'); +} + +async function createProject(config, dir) { + await createDirectory(dir); + const content = formatProjectConfig(config); + const cfgFilePath = path.join(dir, 'build-cfg.zig'); + await promises.writeFile(cfgFilePath, content); + const buildFilePath = path.join(dir, 'build.zig'); + await copyFile(config.buildFilePath, buildFilePath); + if (config.packageConfigPath) { + const packageConfigPath = path.join(dir, 'build.zig.zon'); + await copyFile(config.packageConfigPath, packageConfigPath); + } +} + +function createProjectSync(config, dir) { + createDirectorySync(dir); + const content = formatProjectConfig(config); + const cfgFilePath = path.join(dir, 'build-cfg.zig'); + fs.writeFileSync(cfgFilePath, content); + const buildFilePath = path.join(dir, 'build.zig'); + copyFileSync(config.buildFilePath, buildFilePath); + if (config.packageConfigPath) { + const packageConfigPath = path.join(dir, 'build.zig.zon'); + copyFileSync(config.packageConfigPath, packageConfigPath); + } +} + +const cwd = process.cwd(); + +function getCachePath(options) { + const { + cacheDir = path.join(cwd, 'zigar-cache'), + } = options; + return cacheDir; +} + +function getModuleCachePath(srcPath, options) { + const { + optimize, + } = options; + const src = path.parse(srcPath); + const folder = path.basename(src.dir).slice(0, 16).trim() + '-' + md5(src.dir).slice(0, 8); + const cacheDir = getCachePath(options); + return path.join(cacheDir, folder, optimize, `${src.name}.zigar`); +} + +function createConfig(srcPath, modPath, options = {}) { + const { + platform = getPlatform(), + arch = getArch(), + optimize = 'Debug', + isWASM = false, + useLibc = isWASM ? false : true, + clean = false, + buildDir = path.join(os.tmpdir(), 'zigar-build'), + zigCmd = (() => { + // translate from names used by Node to those used by Zig + const cpuArchs = { + arm: 'arm', + arm64: 'aarch64', + ia32: 'x86', + loong64: 'loong64', + mips: 'mips', + mipsel: 'mipsel', + ppc: 'powerpc', + ppc64: 'powerpc64', + s390: undefined, + s390x: 's390x', + x64: 'x86_64', + }; + const osTags = { + aix: 'aix', + darwin: 'macos', + freebsd: 'freebsd', + linux: 'linux-gnu', + openbsd: 'openbsd', + sunos: 'solaris', + win32: 'windows', + }; + const cpuArch = cpuArchs[arch] ?? arch; + const osTag = osTags[platform] ?? platform; + const args = [ + `build`, + `-Doptimize=${optimize}`, + `-Dtarget=${cpuArch}-${osTag}`, + ]; + return `zig ${args.join(' ')}`; + })(), + } = options; + const suffix = isWASM ? 'wasm' : 'c'; + const src = path.parse(srcPath ?? ''); + const mod = path.parse(modPath ?? ''); + const moduleName = mod.name || src.name; + const modulePath = (src.name !== '?') ? srcPath : undefined; + const moduleDir = src.dir; + const modulePrefix = path.basename(moduleName).slice(0, 16); + const moduleHash = md5(`${moduleDir}/${moduleName}`).slice(0, 8); + const moduleBuildDir = path.join(buildDir, modulePrefix + '-' + moduleHash); + const outputPath = (() => { + if (!modPath && isWASM) { + // save output in build folder + return path.join(moduleBuildDir, optimize, `${src.name}.wasm`); + } else { + const extensions = { + darwin: 'dylib', + win32: 'dll', + }; + const ext = extensions[platform] || 'so'; + return path.join(modPath, `${platform}.${arch}.${ext}`); + } + })(); + const exporterPath = absolute(`../zig/exporter-${suffix}.zig`); + const stubPath = absolute(`../zig/stub-${suffix}.zig`); + const buildFilePath = absolute(`../zig/build.zig`); + return { + platform, + arch, + optimize, + moduleName, + modulePath, + moduleDir, + moduleBuildDir, + exporterPath, + stubPath, + buildFilePath, + packageConfigPath: undefined, + outputPath, + clean, + zigCmd, + useLibc, + isWASM, + }; +} + +function absolute(relpath) { + // import.meta.url don't always yield the right URL when transpiled to CommonJS + // just use __dirname as it's going to be there + /* c8 ignore next 2 */ + if (typeof(__dirname) === 'string') { + return path.resolve(__dirname, relpath); + } else { + return url.fileURLToPath(new URL(relpath, (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))); + } +} + +const optionsForCompile = { + optimize: { + type: 'string', + enum: [ 'Debug', 'ReleaseSmall', 'ReleaseFast', 'ReleaseSafe' ], + title: 'Zig optimization mode', + }, + omitFunctions: { + type: 'boolean', + title: 'Omit all Zig functions', + }, + omitVariables: { + type: 'boolean', + title: 'Omit all variables', + }, + omitExports: { + type: 'boolean', + title: 'Omit export statements', + }, + useLibc: { + type: 'boolean', + title: 'Link in C standard library', + }, + topLevelAwait: { + type: 'boolean', + title: 'Use top-level await to load WASM file', + }, + buildDir: { + type: 'string', + title: 'Root directory where temporary build directories are placed', + }, + cacheDir: { + type: 'string', + title: 'Directory where compiled library files are placed', + }, + zigCmd: { + type: 'string', + title: 'Zig command used to build libraries', + }, + sourceFiles: { + type: 'object', + title: 'Map of modules to source files/directories', + }, + clean: { + type: 'boolean', + title: 'Remove temporary build directory after compilation finishes', + }, + targets: { + type: 'object', + title: 'List of cross-compilation targets', + }, +}; + +const optionsForTranspile = { + useReadFile: { + type: 'boolean', + title: 'Enable the use of readFile() to Load WASM file when library is used in Node.js', + }, + embedWASM: { + type: 'boolean', + title: 'Embed WASM file in JavaScript source code', + }, + stripWASM: { + type: 'boolean', + title: 'Remove unnecessary code from WASM file', + }, + keepNames: { + type: 'boolean', + title: 'Keep names of function in WASM binary when stripping', + }, +}; + +const allOptions = { + ...optionsForCompile, + ...optionsForTranspile, +}; + +function extractOptions(searchParams, availableOptions) { + const options = {}; + const names = Object.keys(availableOptions); + for (const [ name, string ] of searchParams) { + const key = getCamelCase(name, names); + const option = availableOptions[key]; + if (!option) { + throwUnknownOption(name); + } + if (key === 'optimize') { + options[key] = getCamelCase(string, [ 'Debug', 'ReleaseSafe', 'ReleaseFast', 'ReleaseSmall' ]); + } else { + switch (option.type) { + case 'boolean': + options[key] = !!parseInt(string); + break; + case 'number': + options[key] = parseInt(string); + break; + default: + options[key] = string; + } + } + } + return options; +} + +function getCamelCase(name, names) { + for (const nameCC of names) { + const nameSC = nameCC.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase(); + const nameKC = nameSC.replace(/_/g, '-'); + if (name === nameKC || name === nameSC || name === nameCC) { + return nameCC; + } + } + return name; +} + +function throwUnknownOption(key) { + const adjective = (allOptions[key]) ? 'Unavailable' : 'Unrecognized'; + throw new Error(`${adjective} option: ${key}`); +} + +async function findConfigFile(name, dir) { + const path$1 = path.join(dir, name); + const info = await findFile(path$1); + if (info?.isFile()) { + return path$1; + } else { + const parent = path.dirname(dir); + if (parent !== dir) { + return findConfigFile(name, parent); + } + } +} + +function findConfigFileSync(name, dir) { + const path$1 = path.join(dir, name); + const info = findFileSync(path$1); + if (info?.isFile()) { + return path$1; + } else { + const parent = path.dirname(dir); + if (parent !== dir) { + return findConfigFileSync(name, parent); + } + } +} + +async function loadConfigFile(cfgPath, availableOptions) { + const text = await loadFile(cfgPath); + return processConfigFile(text, cfgPath, availableOptions); +} + +function loadConfigFileSync(cfgPath, availableOptions) { + const text = loadFileSync(cfgPath); + return processConfigFile(text, cfgPath, availableOptions); +} + +function processConfigFile(text, cfgPath, availableOptions) { + const options = JSON.parse(text); + for (const [ key, value ] of Object.entries(options)) { + const option = availableOptions[key]; + if (!option) { + throwUnknownOption(key); + } + if (typeof(value) !== option.type) { + throw new Error(`${key} is expected to be a ${option.type}, received: ${value}`); + } + } + options.sourceFiles = getAbsoluteMapping(options.sourceFiles, path.dirname(cfgPath)); + return options; +} + +function getAbsoluteMapping(sourceFiles, cfgDir) { + if (!sourceFiles) { + return; + } + const map = {}; + for (const [ module, source ] of Object.entries(sourceFiles)) { + const modulePath = path.resolve(cfgDir, module); + const sourcePath = path.resolve(cfgDir, source); + map[modulePath] = sourcePath; + } + return map; +} + +function findSourceFile(modulePath, options) { + const { sourceFiles } = options; + return sourceFiles?.[modulePath]; +} + +function addMethods(s, env) { + const add = (target, { methods }, pushThis) => { + const descriptors = {}; + const re = /^(get|set)\s+([\s\S]+)/; + for (const method of methods) { + const f = env.createCaller(method, pushThis); + const m = re.exec(f.name); + if (m) { + // getter/setter + const type = m[1], propName = m[2]; + const argRequired = (type === 'get') ? 0 : 1; + const argCount = getArgumentCount(method, pushThis); + // need to match arg count, since instance methods also show up as static methods + if (argCount === argRequired) { + let descriptor = descriptors[propName]; + if (!descriptor) { + descriptor = descriptors[propName] = { configurable: true, enumerable: true }; + } + descriptor[type] = f; + } + } else { + descriptors[f.name] = { value: f, configurable: true, writable: true }; + } + } + defineProperties$a(target, descriptors); + }; + add(s.constructor, s.static, false); + add(s.constructor.prototype, s.instance, true); +} + +function getArgumentCount(method, pushThis) { + const { argStruct: { instance: { members } } } = method; + return members.length - (pushThis ? 2 : 1); +} + +function addStaticMembers(structure, env) { + const { + type, + constructor, + static: { members, template }, + } = structure; + const descriptors = {}; + for (const member of members) { + descriptors[member.name] = getDescriptor$a(member, env); + } + defineProperties$a(constructor, { + valueOf: { value: getValueOf$a }, + toJSON: { value: convertToJSON$a }, + ...descriptors, + [Symbol.iterator]: { value: getStructIterator$a }, + // static variables are objects stored in the static template's slots + [SLOTS$a]: template ? { value: template[SLOTS$a] } : undefined, + // anyerror would have props already + [PROPS$a]: !constructor[PROPS$a] ? { value: members.map(m => m.name) } : undefined, + [NORMALIZER$a]: { value: normalizeStruct$a }, + }); + if (type === StructureType$a.Enumeration) { + for (const { name, slot } of members) { + appendEnumeration$2(constructor, name, constructor[SLOTS$a][slot]); + } + } else if (type === StructureType$a.ErrorSet) { + for (const { name, slot } of members) { + appendErrorSet(constructor, name, constructor[SLOTS$a][slot]); + } + } +} + +class Environment { + context; + contextStack = []; + consolePending = []; + consoleTimeout = 0; + viewMap = new WeakMap(); + initPromise; + abandoned = false; + released = false; + littleEndian = true; + runtimeSafety = true; + comptime = false; + /* COMPTIME-ONLY */ + slotNumbers = {}; + slots = {}; + structures = []; + /* COMPTIME-ONLY-END */ + imports; + console = globalThis.console; + + /* + Functions to be defined in subclass: + + getBufferAddress(buffer: ArrayBuffer): bigint|number { + // return a buffer's address + } + allocateHostMemory(len: number, align: number): DataView { + // allocate memory and remember its address + } + allocateShadowMemory(len: number, align: number): DataView { + // allocate memory for shadowing objects + } + freeHostMemory(address: bigint|number, len: number, align: number): void { + // free previously allocated memory + } + freeShadowMemory(address: bigint|number, len: number, align: number): void { + // free memory allocated for shadow + } + allocateFixedMemory(len: number, align: number): DataView { + // allocate fixed memory and keep a reference to it + } + freeFixedMemory(address: bigint|number, len: number, align: number): void { + // free previously allocated fixed memory return the reference + } + obtainFixedView(address: bigint|number, len: number): DataView { + // obtain a data view of memory at given address + } + releaseFixedView(dv: DataView): void { + // release allocated memory stored in data view, doing nothing if data view + // does not contain fixed memory or if memory is static + } + inFixedMemory(object: object): boolean { + // return true/false depending on whether object is in fixed memory + } + copyBytes(dst: DataView, address: bigint|number, len: number): void { + // copy memory at given address into destination view + } + findSentinel(address: bigint|number, bytes: DataView): number { + // return offset where sentinel value is found + } + getMemoryOffset(address: bigint|number) number { + // return offset of address relative to start of module memory + } + recreateAddress(reloc: number) number { + // recreate address of memory belonging to module + } + + getTargetAddress(target: object, cluster: object|undefined) { + // return the address of target's buffer if correctly aligned + } + */ + + startContext() { + if (this.context) { + this.contextStack.push(this.context); + } + this.context = new CallContext(); + } + + endContext() { + this.context = this.contextStack.pop(); + } + + allocateMemory(len, align = 0, fixed = false) { + if (fixed) { + return this.allocateFixedMemory(len, align); + } else { + return this.allocateRelocMemory(len, align); + } + } + + allocateRelocMemory(len, align) { + return this.obtainView(new ArrayBuffer(len), 0, len); + } + + registerMemory(dv, targetDV = null, targetAlign = undefined) { + const { memoryList } = this.context; + const address = this.getViewAddress(dv); + const index = findMemoryIndex(memoryList, address); + memoryList.splice(index, 0, { address, dv, len: dv.byteLength, targetDV, targetAlign }); + return address; + } + + unregisterMemory(address) { + const { memoryList } = this.context; + const index = findMemoryIndex(memoryList, address); + const prev = memoryList[index - 1]; + if (prev?.address === address) { + memoryList.splice(index - 1, 1); + } + } + + findMemory(address, len) { + // check for null address (=== can't be used since address can be both number and bigint) + if (this.context) { + const { memoryList } = this.context; + const index = findMemoryIndex(memoryList, address); + const entry = memoryList[index - 1]; + if (entry?.address === address && entry.len === len) { + return entry.targetDV ?? entry.dv; + } else if (entry?.address <= address && address < add(entry.address, entry.len)) { + const offset = Number(address - entry.address); + const targetDV = entry.targetDV ?? entry.dv; + const isOpaque = len === undefined; + if (isOpaque) { + len = targetDV.byteLength - offset; + } + const dv = this.obtainView(targetDV.buffer, targetDV.byteOffset + offset, len); + if (isOpaque) { + // opaque structure--need to save the alignment + dv[ALIGN$a] = entry.targetAlign; + } + return dv; + } + } + // not found in any of the buffers we've seen--assume it's fixed memory + return this.obtainFixedView(address, len ?? 0); + } + + getViewAddress(dv) { + const address = this.getBufferAddress(dv.buffer); + return add(address, dv.byteOffset); + } + + obtainView(buffer, offset, len) { + let entry = this.viewMap.get(buffer); + if (!entry) { + const dv = new DataView(buffer, offset, len); + this.viewMap.set(buffer, dv); + return dv; + } + if (entry instanceof DataView) { + // only one view created thus far--see if that's the matching one + if (entry.byteOffset === offset && entry.byteLength === len) { + return entry; + } else { + // no, need to replace the entry with a hash keyed by `offset:len` + const dv = entry; + const key = `${dv.byteOffset}:${dv.byteLength}`; + entry = { [key]: dv }; + this.viewMap.set(buffer, entry); + } + } + const key = `${offset}:${len}`; + let dv = entry[key]; + if (!dv) { + dv = entry[key] = new DataView(buffer, offset, len); + } + return dv; + } + + captureView(address, len, copy) { + if (copy) { + // copy content into reloctable memory + const dv = this.allocateRelocMemory(len, 0); + if (len > 0) { + this.copyBytes(dv, address, len); + } + return dv; + } else { + // link into fixed memory + return this.obtainFixedView(address, len); + } + } + + castView(structure, dv, writable) { + const { constructor, hasPointer } = structure; + const object = constructor.call(ENVIRONMENT$a, dv, { writable }); + if (hasPointer) { + // acquire targets of pointers + this.acquirePointerTargets(object); + } + return object; + } + + /* COMPTIME-ONLY */ + getSlotNumber(scope, key) { + let slotNumber = this.slotNumbers[scope]; + if (!slotNumber) { + slotNumber = this.slotNumbers[scope] = { next: 0, map: {} }; + } + let slot = slotNumber.map[key]; + if (slot === undefined) { + slot = slotNumber.map[key] = slotNumber.next++; + } + return slot; + } + + readSlot(target, slot) { + const slots = target ? target[SLOTS$a] : this.slots; + return slots?.[slot]; + } + + writeSlot(target, slot, value) { + const slots = target ? target[SLOTS$a] : this.slots; + if (slots) { + slots[slot] = value; + } + } + + createTemplate(dv) { + return { + [MEMORY$a]: dv, + [SLOTS$a]: {} + }; + } + + beginStructure(def) { + const { + type, + name, + length, + byteSize, + align, + isConst, + hasPointer, + } = def; + return { + constructor: null, + typedArray: null, + type, + name, + length, + byteSize, + align, + isConst, + hasPointer, + instance: { + members: [], + methods: [], + template: null, + }, + static: { + members: [], + methods: [], + template: null, + }, + }; + } + + attachMember(structure, member, isStatic = false) { + const target = (isStatic) ? structure.static : structure.instance; + target.members.push(member); + } + + attachMethod(structure, method, isStaticOnly = false) { + structure.static.methods.push(method); + if (!isStaticOnly) { + structure.instance.methods.push(method); + } + } + + attachTemplate(structure, template, isStatic = false) { + const target = (isStatic) ? structure.static : structure.instance; + target.template = template; + } + + endStructure(structure) { + this.structures.push(structure); + this.finalizeStructure(structure); + for (const structure of this.structures) { + this.acquireDefaultPointers(structure); + } + } + + defineFactoryArgStruct() { + useBool$a(); + useObject$a(); + useArgStruct$a(); + const options = this.beginStructure({ + type: StructureType$a.Struct, + name: 'Options', + byteSize: 2, + hasPointer: false, + }); + this.attachMember(options, { + type: MemberType$a.Bool, + name: 'omitFunctions', + bitOffset: 0, + bitSize: 1, + byteSize: 1, + }); + this.attachMember(options, { + type: MemberType$a.Bool, + name: 'omitVariables', + bitOffset: 8, + bitSize: 1, + byteSize: 1, + }); + this.finalizeShape(options); + const structure = this.beginStructure({ + type: StructureType$a.ArgStruct, + name: 'factory', + byteSize: 2, + hasPointer: false, + }); + this.attachMember(structure, { + type: MemberType$a.Object, + name: '0', + bitOffset: 0, + bitSize: 16, + byteSize: 2, + slot: 0, + structure: options, + }); + this.attachMember(structure, { + type: MemberType$a.Void, + name: 'retval', + bitOffset: 16, + bitSize: 0, + byteSize: 0 + }); + this.finalizeShape(structure); + return structure.constructor; + } + + acquireStructures(options) { + const { + omitFunctions = false, + omitVariables = isElectron(), + } = options; + resetGlobalErrorSet(); + const thunkId = this.getFactoryThunk(); + const ArgStruct = this.defineFactoryArgStruct(); + const args = new ArgStruct([ { omitFunctions, omitVariables } ]); + this.comptime = true; + this.invokeThunk(thunkId, args); + this.comptime = false; + } + + getRootModule() { + const root = this.structures[this.structures.length - 1]; + return root.constructor; + } + + hasMethods() { + // all methods are static, so there's no need to check instance methods + return !!this.structures.find(s => s.static.methods.length > 0); + } + + exportStructures() { + this.prepareObjectsForExport(); + const { structures, runtimeSafety, littleEndian } = this; + return { + structures, + options: { runtimeSafety, littleEndian }, + keys: { MEMORY: MEMORY$a, SLOTS: SLOTS$a, CONST: CONST$a } + }; + } + + prepareObjectsForExport() { + const objects = findAllObjects(this.structures, SLOTS$a); + const list = []; + for (const object of objects) { + if (object[MEMORY$a]) { + if (this.inFixedMemory(object)) { + // replace fixed memory + const dv = object[MEMORY$a]; + const address = this.getViewAddress(dv); + const offset = this.getMemoryOffset(address); + const len = dv.byteLength; + const relocDV = this.captureView(address, len, true); + relocDV.reloc = offset; + object[MEMORY$a] = relocDV; + list.push({ offset, len, owner: object, replaced: false }); + } + } + } + // larger memory blocks come first + list.sort((a, b) => b.len - a.len); + for (const a of list) { + if (!a.replaced) { + for (const b of list) { + if (a !== b && !b.replaced) { + if (a.offset <= b.offset && b.offset < a.offset + a.len) { + // B is inside A--replace it with a view of A's buffer + const dv = a.owner[MEMORY$a]; + const pos = b.offset - a.offset + dv.byteOffset; + const newDV = this.obtainView(dv.buffer, pos, b.len); + newDV.reloc = b.offset; + b.owner[MEMORY$a] = newDV; + b.replaced = true; + } + } + } + } + } + } + + useStructures() { + const module = this.getRootModule(); + // add fixed memory object to list so they can be unlinked + const objects = findAllObjects(this.structures, SLOTS$a); + for (const object of objects) { + if (object[MEMORY$a] && this.inFixedMemory(object)) { + this.variables.push({ object }); + } + } + // clear comptime-only variables + this.slots = {}; + this.structures = []; + module.__zigar = this.getControlObject(); + return module; + } + /* COMPTIME-ONLY-END */ + + finalizeShape(structure) { + const f = getStructureFactory(structure.type); + const constructor = f(structure, this); + if (typeof(constructor) === 'function') { + defineProperties$a(constructor, { + name: { value: structure.name, configurable: true }, + }); + if (!constructor.prototype.hasOwnProperty(Symbol.toStringTag)) { + defineProperties$a(constructor.prototype, { + [Symbol.toStringTag]: { value: structure.name, configurable: true }, + }); + } + } + } + + finalizeStructure(structure) { + addStaticMembers(structure, this); + addMethods(structure, this); + } + + createCaller(method, useThis) { + const { name, argStruct, thunkId } = method; + const { constructor } = argStruct; + const self = this; + let f; + if (useThis) { + f = function(...args) { + return self.invokeThunk(thunkId, new constructor([ this, ...args ])); + }; + } else { + f = function(...args) { + return self.invokeThunk(thunkId, new constructor(args)); + }; + } + Object.defineProperty(f, 'name', { value: name }); + return f; + } + + + getShadowAddress(target, cluster) { + if (cluster) { + const dv = target[MEMORY$a]; + if (cluster.address === undefined) { + const shadow = this.createClusterShadow(cluster); + cluster.address = this.getViewAddress(shadow[MEMORY$a]); + } + return add(cluster.address, dv.byteOffset); + } else { + const shadow = this.createShadow(target); + return this.getViewAddress(shadow[MEMORY$a]); + } + } + + createShadow(object) { + const dv = object[MEMORY$a]; + // use the alignment of the structure; in the case of an opaque pointer's target, + // try to the alignment specified when the memory was allocated + const align = object.constructor[ALIGN$a] ?? dv[ALIGN$a]; + const shadow = Object.create(object.constructor.prototype); + const shadowDV = shadow[MEMORY$a] = this.allocateShadowMemory(dv.byteLength, align); + shadow[ATTRIBUTES] = { + address: this.getViewAddress(shadowDV), + len: shadowDV.byteLength, + align, + }; + return this.addShadow(shadow, object, align); + } + + addShadow(shadow, object, align) { + let { shadowMap } = this.context; + if (!shadowMap) { + shadowMap = this.context.shadowMap = new Map(); + } + shadowMap.set(shadow, object); + this.registerMemory(shadow[MEMORY$a], object[MEMORY$a], align); + return shadow; + } + + removeShadow(dv) { + const { shadowMap } = this.context; + if (shadowMap) { + for (const [ shadow ] of shadowMap) { + if (shadow[MEMORY$a] === dv) { + shadowMap.delete(shadow); + break; + } + } + } + } + + updateShadows() { + const { shadowMap } = this.context; + if (!shadowMap) { + return; + } + for (const [ shadow, object ] of shadowMap) { + shadow[COPIER$a](object); + } + } + + updateShadowTargets() { + const { shadowMap } = this.context; + if (!shadowMap) { + return; + } + for (const [ shadow, object ] of shadowMap) { + object[COPIER$a](shadow); + } + } + + releaseShadows() { + const { shadowMap } = this.context; + if (!shadowMap) { + return; + } + for (const [ shadow ] of shadowMap) { + const { address, len, align } = shadow[ATTRIBUTES]; + this.freeShadowMemory(address, len, align); + } + } + + acquirePointerTargets(args) { + const env = this; + const pointerMap = new Map(); + const callback = function({ isActive, isMutable }) { + const pointer = this[POINTER$a]; + if (pointerMap.get(pointer)) { + return; + } else { + pointerMap.set(pointer, true); + } + const writable = !pointer.constructor.const; + const currentTarget = pointer[SLOTS$a][0]; + let newTarget, location; + if (isActive(this)) { + const Target = pointer.constructor.child; + if (!currentTarget || isMutable(this)) { + // obtain address and length from memory + location = pointer[LOCATION_GETTER$a](); + if (!isInvalidAddress(location.address)) { + // get view of memory that pointer points to + const len = (Target[SIZE$a] !== undefined) ? location.length * Target[SIZE$a] : undefined; + const dv = env.findMemory(location.address, len); + // create the target + newTarget = Target.call(ENVIRONMENT$a, dv, { writable }); + } else { + newTarget = null; + } + } else { + newTarget = currentTarget; + } + } + // acquire objects pointed to by pointers in target + currentTarget?.[POINTER_VISITOR$a]?.(callback, { vivificate: true, isMutable: () => writable }); + if (newTarget !== currentTarget) { + newTarget?.[POINTER_VISITOR$a]?.(callback, { vivificate: true, isMutable: () => writable }); + pointer[SLOTS$a][0] = newTarget; + if (env.inFixedMemory(pointer)) { + pointer[FIXED_LOCATION$a] = location; + } + } + }; + args[POINTER_VISITOR$a](callback, { vivificate: true }); + } + + /* COMPTIME-ONLY */ + acquireDefaultPointers(structure) { + const { constructor, hasPointer, instance: { template } } = structure; + if (hasPointer && template && template[MEMORY$a]) { + // create a placeholder for retrieving default pointers + const placeholder = Object.create(constructor.prototype); + placeholder[MEMORY$a] = template[MEMORY$a]; + placeholder[SLOTS$a] = template[SLOTS$a]; + this.acquirePointerTargets(placeholder); + } + } + /* COMPTIME-ONLY-END */ +} + +class CallContext { + pointerProcessed = new Map(); + memoryList = []; + shadowMap = null; + /* WASM-ONLY */ + call = 0; + /* WASM-ONLY-END */ +} + +function findSortedIndex(array, value, cb) { + let low = 0; + let high = array.length; + if (high === 0) { + return 0; + } + while (low < high) { + const mid = Math.floor((low + high) / 2); + const value2 = cb(array[mid]); + if (value2 <= value) { + low = mid + 1; + } else { + high = mid; + } + } + return high; +} + +function findMemoryIndex(array, address) { + return findSortedIndex(array, address, m => m.address); +} + +function add(address, len) { + return address + ((typeof(address) === 'bigint') ? BigInt(len) : len); +} + +function isInvalidAddress(address) { + if (typeof(address) === 'bigint') { + return address === 0xaaaaaaaaaaaaaaaan; + } else { + return address === 0xaaaaaaaa; + } +} + +function isElectron() { + return typeof(process) === 'object' + && typeof(process?.versions) === 'object' + && !!process.versions?.electron; +} + +class WebAssemblyEnvironment extends Environment { + imports = { + getFactoryThunk: { argType: '', returnType: 'i' }, + allocateExternMemory: { argType: 'ii', returnType: 'i' }, + freeExternMemory: { argType: 'iii' }, + allocateShadowMemory: { argType: 'cii', returnType: 'v' }, + freeShadowMemory: { argType: 'ciii' }, + runThunk: { argType: 'iv', returnType: 'v' }, + isRuntimeSafetyActive: { argType: '', returnType: 'b' }, + }; + exports = { + allocateHostMemory: { argType: 'ii', returnType: 'v' }, + freeHostMemory: { argType: 'iii' }, + captureString: { argType: 'ii', returnType: 'v' }, + captureView: { argType: 'iib', returnType: 'v' }, + castView: { argType: 'vvb', returnType: 'v' }, + getSlotNumber: { argType: 'ii', returnType: 'i' }, + readSlot: { argType: 'vi', returnType: 'v' }, + writeSlot: { argType: 'viv' }, + getViewAddress: { argType: 'v', returnType: 'i' }, + beginDefinition: { returnType: 'v' }, + insertInteger: { argType: 'vsi', alias: 'insertProperty' }, + insertBoolean: { argType: 'vsb', alias: 'insertProperty' }, + insertString: { argType: 'vss', alias: 'insertProperty' }, + insertObject: { argType: 'vsv', alias: 'insertProperty' }, + beginStructure: { argType: 'v', returnType: 'v' }, + attachMember: { argType: 'vvb' }, + attachMethod: { argType: 'vvb' }, + createTemplate: { argType: 'v', returnType: 'v' }, + attachTemplate: { argType: 'vvb' }, + finalizeShape: { argType: 'v' }, + endStructure: { argType: 'v' }, + startCall: { argType: 'iv', returnType: 'i' }, + endCall: { argType: 'iv', returnType: 'i' }, + }; + nextValueIndex = 1; + valueTable = { 0: null }; + valueIndices = new Map; + memory = null; + // WASM is always little endian + littleEndian = true; + + allocateHostMemory(len, align) { + // allocate memory in both JavaScript and WASM space + const constructor = { [ALIGN$a]: align }; + const copier = getMemoryCopier$a(len); + const dv = this.allocateRelocMemory(len, align); + const shadowDV = this.allocateShadowMemory(len, align); + // create a shadow for the relocatable memory + const object = { constructor, [MEMORY$a]: dv, [COPIER$a]: copier }; + const shadow = { constructor, [MEMORY$a]: shadowDV, [COPIER$a]: copier }; + shadow[ATTRIBUTES] = { address: this.getViewAddress(shadowDV), len, align }; + this.addShadow(shadow, object, align); + return shadowDV; + } + + freeHostMemory(address, len, align) { + const dv = this.findMemory(address, len); + this.removeShadow(dv); + this.unregisterMemory(address); + this.freeShadowMemory(address, len, align); + } + + getBufferAddress(buffer) { + return 0; + } + + allocateFixedMemory(len, align) { + if (len === 0) { + return new DataView(this.memory.buffer, 0, 0); + } + const address = this.allocateExternMemory(len, align); + const dv = this.obtainFixedView(address, len); + dv[ALIGN$a] = align; + return dv; + } + + freeFixedMemory(address, len, align) { + if (len === 0) { + return; + } + this.freeExternMemory(address, len, align); + } + + obtainFixedView(address, len) { + const { memory } = this; + if (len === 0 && address === -1431655766) { // 0xAAAAAAAA + address = 0; + } + const dv = this.obtainView(memory.buffer, address, len); + dv[MEMORY$a] = { memory, address, len }; + return dv; + } + + releaseFixedView(dv) { + dv.buffer; + const address = dv.byteOffset; + const len = dv.byteLength; + // only allocated memory would have align attached + const align = dv[ALIGN$a]; + if (align !== undefined) { + this.freeFixedMemory(address, len, align); + } + } + + inFixedMemory(object) { + // reconnect any detached buffer before checking + if (!this.memory) { + return false; + } + restoreMemory$a.call(object); + return object[MEMORY$a].buffer === this.memory.buffer; + } + + copyBytes(dst, address, len) { + const { memory } = this; + const src = new DataView(memory.buffer, address, len); + const copy = getCopyFunction$a(len); + copy(dst, src); + } + + findSentinel(address, bytes) { + const { memory } = this; + const len = bytes.byteLength; + const end = memory.buffer.byteLength - len + 1; + for (let i = address; i < end; i += len) { + const dv = new DataView(memory.buffer, i, len); + let match = true; + for (let j = 0; j < len; j++) { + const a = dv.getUint8(j); + const b = bytes.getUint8(j); + if (a !== b) { + match = false; + break; + } + } + if (match) { + return (i - address) / len; + } + } + } + + captureString(address, len) { + const { buffer } = this.memory; + const ta = new Uint8Array(buffer, address, len); + return decodeText$a(ta); + } + + getTargetAddress(target, cluster) { + if (this.inFixedMemory(target)) { + return this.getViewAddress(target[MEMORY$a]); + } + if (target[MEMORY$a].byteLength === 0) { + // it's a null pointer/empty slice + return 0; + } + // relocatable buffers always need shadowing + return false; + } + + clearExchangeTable() { + if (this.nextValueIndex !== 1) { + this.nextValueIndex = 1; + this.valueTable = { 0: null }; + this.valueIndices = new Map(); + } + } + + getObjectIndex(object) { + if (object) { + let index = this.valueIndices.get(object); + if (index === undefined) { + index = this.nextValueIndex++; + this.valueIndices.set(object, index); + this.valueTable[index] = object; + } + return index; + } else { + return 0; + } + } + + fromWebAssembly(type, arg) { + switch (type) { + case 'v': + case 's': return this.valueTable[arg]; + case 'i': return arg; + case 'b': return !!arg; + } + } + + toWebAssembly(type, arg) { + switch (type) { + case 'v': + case 's': return this.getObjectIndex(arg); + case 'i': return arg; + case 'b': return arg ? 1 : 0; + } + } + + exportFunction(fn, argType = '', returnType = '') { + if (!fn) { + return () => {}; + } + return (...args) => { + args = args.map((arg, i) => this.fromWebAssembly(argType.charAt(i), arg)); + const retval = fn.apply(this, args); + return this.toWebAssembly(returnType, retval); + }; + } + + importFunction(fn, argType = '', returnType = '') { + let needCallContext = false; + if (argType.startsWith('c')) { + needCallContext = true; + argType = argType.slice(1); + } + return (...args) => { + args = args.map((arg, i) => this.toWebAssembly(argType.charAt(i), arg)); + if (needCallContext) { + args = [ this.context.call, ...args ]; + } + const retval = fn.apply(this, args); + return this.fromWebAssembly(returnType, retval); + }; + } + + exportFunctions() { + const imports = {}; + for (const [ name, { argType, returnType, alias } ] of Object.entries(this.exports)) { + const fn = this[alias ?? name]; + imports[`_${name}`] = this.exportFunction(fn, argType, returnType); + } + return imports; + } + + importFunctions(exports) { + for (const [ name, fn ] of Object.entries(exports)) { + const info = this.imports[name]; + if (info) { + const { argType, returnType } = info; + this[name] = this.importFunction(fn, argType, returnType); + } + } + } + + async instantiateWebAssembly(source) { + const res = await source; + const env = this.exportFunctions(); + const wasi = this.getWASI(); + const imports = { env, wasi_snapshot_preview1: wasi }; + if (res[Symbol.toStringTag] === 'Response') { + return WebAssembly.instantiateStreaming(res, imports); + } else { + return WebAssembly.instantiate(res, imports); + } + } + + loadModule(source) { + return this.initPromise = (async () => { + const { instance } = await this.instantiateWebAssembly(source); + const { memory, _initialize } = instance.exports; + this.importFunctions(instance.exports); + this.trackInstance(instance); + this.runtimeSafety = this.isRuntimeSafetyActive(); + this.memory = memory; + _initialize?.(); + })(); + } + + trackInstance(instance) { + // use WeakRef to detect whether web-assembly instance has been gc'ed + const ref = new WeakRef(instance); + Object.defineProperty(this, 'released', { get: () => !ref.deref(), enumerable: true }); + } + + linkVariables(writeBack) { + // linkage occurs when WASM compilation is complete and functions have been imported + // nothing needs to happen when WASM is not used + if (this.initPromise) { + this.initPromise = this.initPromise.then(() => super.linkVariables(writeBack)); + } + } + + /* COMPTIME-ONLY */ + beginDefinition() { + return {}; + } + + insertProperty(def, name, value) { + def[name] = value; + } + /* COMPTIME-ONLY-END */ + + getMemoryOffset(address) { + // WASM address space starts at 0 + return address; + } + + recreateAddress(reloc) { + return reloc; + } + + startCall(call, args) { + this.startContext(); + // call context, used by allocateShadowMemory and freeShadowMemory + this.context.call = call; + if (args[POINTER_VISITOR$a]) { + this.updatePointerAddresses(args); + } + // return address of shadow for argumnet struct + const address = this.getShadowAddress(args); + this.updateShadows(); + return address; + } + + endCall(call, args) { + this.updateShadowTargets(); + if (args[POINTER_VISITOR$a]) { + this.acquirePointerTargets(args); + } + this.releaseShadows(); + // restore the previous context if there's one + this.endContext(); + if (!this.context && this.flushConsole) { + this.flushConsole(); + } + } + + async runThunk(thunkId, args) { + // wait for compilation + await this.initPromise; + // invoke runThunk() from WASM code + return this.runThunk(thunkId, args); + } + + invokeThunk(thunkId, args) { + // wasm-exporter.zig will invoke startCall() with the context address and the args + // we can't do pointer fix up here since we need the context in order to allocate + // memory from the WebAssembly allocator; pointer target acquisition will happen in + // endCall() + const err = this.runThunk(thunkId, args); + // errors returned by exported Zig functions are normally written into the + // argument object and get thrown when we access its retval property (a zig error union) + // error strings returned by the thunk are due to problems in the thunking process + // (i.e. bugs in export.zig) + if (err) { + if (err[Symbol.toStringTag] === 'Promise') { + // getting a promise, WASM is not yet ready + // wait for fulfillment, then either return result or throw + return err.then((err) => { + if (err) { + throwZigError(err); + } + return args.retval; + }); + } else { + throwZigError(err); + } + } + return args.retval; + } + + getWASI() { + return { + proc_exit: (rval) => { + }, + fd_write: (fd, iovs_ptr, iovs_count, written_ptr) => { + if (fd === 1 || fd === 2) { + const dv = new DataView(this.memory.buffer); + let written = 0; + for (let i = 0, p = iovs_ptr; i < iovs_count; i++, p += 8) { + const buf_ptr = dv.getUint32(p, true); + const buf_len = dv.getUint32(p + 4, true); + const buf = new DataView(this.memory.buffer, buf_ptr, buf_len); + this.writeToConsole(buf); + written += buf_len; + } + dv.setUint32(written_ptr, written, true); + return 0; + } else { + return 1; + } + }, + random_get: (buf, buf_len) => { + const dv = new DataView(this.memory.buffer); + for (let i = 0; i < buf_len; i++) { + dv.setUint8(Math.floor(256 * Math.random())); + } + return 0; + }, + }; + } +} + +/* COMPTIME-ONLY */ + +// useAllMemberTypes(); +// useAllStructureTypes(); +// useAllExtendedTypes(); +/* COMPTIME-ONLY-END */ + +function createEnvironment(source) { + return new WebAssemblyEnvironment(); +} + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +function findSourceFile$1(modulePath, options) { + const { sourceFiles } = options; + return sourceFiles?.[modulePath]; +} + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +const MEMORY$9 = Symbol('memory'); +const SLOTS$9 = Symbol('slots'); +const PARENT$9 = Symbol('parent'); +const NAME$9 = Symbol('name'); +const CLASS$1 = Symbol('class'); +const TAG$9 = Symbol('tag'); +const PROPS$9 = Symbol('props'); +const GETTER$9 = Symbol('getter'); +const SETTER$9 = Symbol('setter'); +const ELEMENT_GETTER$9 = Symbol('elementGetter'); +const ELEMENT_SETTER$9 = Symbol('elementSetter'); +const LOCATION_GETTER$9 = Symbol('addressGetter'); +const LOCATION_SETTER$9 = Symbol('addressSetter'); +const TARGET_GETTER$9 = Symbol('targetGetter'); +const TARGET_SETTER$9 = Symbol('targetSetter'); +const FIXED_LOCATION$9 = Symbol('fixedLocation'); +const PROP_GETTERS$9 = Symbol('propGetters'); +const PROP_SETTERS$9 = Symbol('propSetters'); +const ALL_KEYS$9 = Symbol('allKeys'); +const LENGTH$9 = Symbol('length'); +const PROXY$9 = Symbol('proxy'); +const COMPAT$9 = Symbol('compat'); +const SIZE$9 = Symbol('size'); +const ALIGN$9 = Symbol('align'); +const ARRAY$9 = Symbol('array'); +const POINTER$9 = Symbol('pointer'); +const CONST$9 = Symbol('const'); +const CONST_PROTOTYPE$9 = Symbol('constProto'); +const COPIER$9 = Symbol('copier'); +const RESETTER$9 = Symbol('resetter'); +const NORMALIZER$9 = Symbol('normalizer'); +const VIVIFICATOR$9 = Symbol('vivificator'); +const POINTER_VISITOR$9 = Symbol('pointerVisitor'); +const ENVIRONMENT$9 = Symbol('environment'); +const MORE$9 = Symbol('more'); + +function getDestructor$9(env) { + return function() { + const dv = this[MEMORY$9]; + this[MEMORY$9] = null; + if (this[SLOTS$9]) { + this[SLOTS$9] = {}; + } + env.releaseFixedView(dv); + }; +} + +function getBitAlignFunction$9(bitPos, bitSize, toAligned) { + if (bitPos + bitSize <= 8) { + const mask = (2 ** bitSize) - 1; + if (toAligned) { + // from single byte + return function(dest, src, offset) { + const n = src.getUint8(offset); + const b = (n >> bitPos) & mask; + dest.setUint8(0, b); + }; + } else { + // to single byte + const destMask = 0xFF ^ (mask << bitPos); + return function(dest, src, offset) { + const n = src.getUint8(0); + const d = dest.getUint8(offset); + const b = (d & destMask) | ((n & mask) << bitPos); + dest.setUint8(offset, b); + }; + } + } else { + const leadBits = 8 - bitPos; + const leadMask = (2 ** leadBits) - 1; + if (toAligned) { + const trailBits = bitSize % 8; + const trailMask = (2 ** trailBits) - 1; + return function(dest, src, offset) { + let i = offset, j = 0; + let n = src.getUint8(i++), b; + let bitBuf = (n >> bitPos) & leadMask; + let bitCount = leadBits; + let remaining = bitSize; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + //bitCount += 8; + } + b = (remaining >= 8) ? bitBuf & 0xFF : bitBuf & trailMask; + dest.setUint8(j++, b); + bitBuf >>= 8; + //bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } else { + const trailBits = (bitSize - leadBits) % 8; + const trailMask = (2 ** trailBits) - 1; + const destMask1 = 0xFF ^ (leadMask << bitPos); + const destMask2 = 0xFF ^ trailMask; + return function(dest, src, offset) { + let i = 0, j = offset; + // preserve bits ahead of bitPos + let d = dest.getUint8(j), n, b; + let bitBuf = d & destMask1; + let bitCount = bitPos; + let remaining = bitSize + bitCount; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + bitCount += 8; + } + if (remaining >= 8) { + b = bitBuf & 0xFF; + } else { + // preserve bits at the destination sitting behind the trailing bits + d = dest.getUint8(j); + b = (d & destMask2) | (bitBuf & trailMask); + } + dest.setUint8(j++, b); + bitBuf >>= 8; + bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } + } +} + +function getMemoryCopier$9(size, multiple = false) { + const copy = getCopyFunction$9(size, multiple); + return function(target) { + /* WASM-ONLY */ + restoreMemory$9.call(this); + restoreMemory$9.call(target); + /* WASM-ONLY-END */ + const src = target[MEMORY$9]; + const dest = this[MEMORY$9]; + copy(dest, src); + }; +} + +function getCopyFunction$9(size, multiple = false) { + if (!multiple) { + const copier = copiers$9[size]; + if (copier) { + return copier; + } + } + if (!(size & 0x07)) return copy8x$9; + if (!(size & 0x03)) return copy4x$9; + if (!(size & 0x01)) return copy2x$9; + return copy1x$9; +} + +const copiers$9 = { + 1: copy1$9, + 2: copy2$9, + 4: copy4$9, + 8: copy8$9, + 16: copy16$9, + 32: copy32$9, +}; + +function copy1x$9(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i++) { + dest.setInt8(i, src.getInt8(i)); + } +} + +function copy2x$9(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 2) { + dest.setInt16(i, src.getInt16(i, true), true); + } +} + +function copy4x$9(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 4) { + dest.setInt32(i, src.getInt32(i, true), true); + } +} + +function copy8x$9(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 8) { + dest.setInt32(i, src.getInt32(i, true), true); + dest.setInt32(i + 4, src.getInt32(i + 4, true), true); + } +} + +function copy1$9(dest, src) { + dest.setInt8(0, src.getInt8(0)); +} + +function copy2$9(dest, src) { + dest.setInt16(0, src.getInt16(0, true), true); +} + +function copy4$9(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); +} + +function copy8$9(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); +} + +function copy16$9(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); +} + +function copy32$9(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); + dest.setInt32(16, src.getInt32(16, true), true); + dest.setInt32(20, src.getInt32(20, true), true); + dest.setInt32(24, src.getInt32(24, true), true); + dest.setInt32(28, src.getInt32(28, true), true); +} + +function getMemoryResetter$9(offset, size) { + const reset = getResetFunction$9(size); + return function() { + /* WASM-ONLY */ + restoreMemory$9.call(this); + /* WASM-ONLY-END */ + const dest = this[MEMORY$9]; + reset(dest, offset, size); + }; +} + +function getResetFunction$9(size) { + const resetter = resetters$9[size]; + if (resetter) { + return resetter; + } + if (!(size & 0x07)) return reset8x$9; + if (!(size & 0x03)) return reset4x$9; + if (!(size & 0x01)) return reset2x$9; + return reset1x$9; +} + +const resetters$9 = { + 1: reset1$9, + 2: reset2$9, + 4: reset4$9, + 8: reset8$9, + 16: reset16$9, + 32: reset32$9, +}; + +function reset1x$9(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i++) { + dest.setInt8(i, 0); + } +} + +function reset2x$9(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 2) { + dest.setInt16(i, 0, true); + } +} + +function reset4x$9(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 4) { + dest.setInt32(i, 0, true); + } +} + +function reset8x$9(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 8) { + dest.setInt32(i, 0, true); + dest.setInt32(i + 4, 0, true); + } +} + +function reset1$9(dest, offset) { + dest.setInt8(offset, 0); +} + +function reset2$9(dest, offset) { + dest.setInt16(offset, 0, true); +} + +function reset4$9(dest, offset) { + dest.setInt32(offset, 0, true); +} + +function reset8$9(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); +} + +function reset16$9(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); +} + +function reset32$9(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); + dest.setInt32(offset + 16, 0, true); + dest.setInt32(offset + 20, 0, true); + dest.setInt32(offset + 24, 0, true); + dest.setInt32(offset + 28, 0, true); +} + +function restoreMemory$9() { + const dv = this[MEMORY$9]; + const source = dv[MEMORY$9]; + if (!source || dv.buffer.byteLength !== 0) { + return false; + } + const { memory, address, len } = source; + const newDV = new DataView(memory.buffer, address, len); + newDV[MEMORY$9] = source; + this[MEMORY$9] = newDV; + return true; +} + +const decoders$9 = {}; +const encoders$9 = {}; + +function decodeText$9(arrays, encoding = 'utf-8') { + let decoder = decoders$9[encoding]; + if (!decoder) { + decoder = decoders$9[encoding] = new TextDecoder(encoding); + } + let array; + if (Array.isArray(arrays)) { + if (arrays.length === 1) { + array = arrays[0]; + } else { + let len = 0; + for (const a of arrays) { + len += a.length; + } + const { constructor } = arrays[0]; + array = new constructor(len); + let offset = 0; + for (const a of arrays) { + array.set(a, offset); + offset += a.length; + } + } + } else { + array = arrays; + } + return decoder.decode(array); +} + +function encodeText$9(text, encoding = 'utf-8') { + switch (encoding) { + case 'utf-16': { + const { length } = text; + const ta = new Uint16Array(length); + for (let i = 0; i < length; i++) { + ta[i] = text.charCodeAt(i); + } + return ta; + } + default: { + let encoder = encoders$9[encoding]; + if (!encoder) { + encoder = encoders$9[encoding] = new TextEncoder(); + } + return encoder.encode(text); + } + } +} + +function encodeBase64$9(dv) { + const ta = new Uint8Array(dv.buffer, dv.byteOffset, dv.byteLength); + const bstr = String.fromCharCode.apply(null, ta); + return btoa(bstr); +} + +function decodeBase64$9(str) { + const bstr = atob(str); + const ta = new Uint8Array(bstr.length); + for (let i = 0; i < ta.byteLength; i++) { + ta[i] = bstr.charCodeAt(i); + } + return new DataView(ta.buffer); +} + +function getValueOf$9() { + const map = new Map(); + const options = { error: 'throw' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$9]; + if (normalizer) { + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + map.set(value, result); + } + return result; + } else { + return value; + } + }; + return process(this); +} + +const INT_MAX$9 = BigInt(Number.MAX_SAFE_INTEGER); +const INT_MIN$9 = BigInt(Number.MIN_SAFE_INTEGER); + +function convertToJSON$9() { + const map = new Map(); + const options = { error: 'return' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$9]; + if (normalizer) { + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + if (typeof(result?.toJSON) === 'function') { + result = result.toJSON(); + } + map.set(value, result); + } + return result; + } else { + if (typeof(value) === 'bigint' && INT_MIN$9 <= value && value <= INT_MAX$9) { + return Number(value); + } + return value; + } + }; + return process(this); +} + +function normalizeValue$9(cb, options) { + const value = handleError$9(() => this.$, options); + return cb(value); +} + +function handleError$9(cb, options = {}) { + const { error = 'throw' } = options; + try { + return cb(); + } catch (err) { + if (error === 'return') { + return err; + } else { + throw err; + } + } +} + +function getDataViewDescriptor$9(structure, handlers = {}) { + return markAsSpecial$9({ + get() { + /* WASM-ONLY */ + restoreMemory$9.call(this); + /* WASM-ONLY-END */ + return this[MEMORY$9]; + }, + set(dv) { + checkDataView$9(dv); + setDataView$9.call(this, dv, structure, true, handlers); + }, + }); +} + +function getBase64Descriptor$9(structure, handlers = {}) { + return markAsSpecial$9({ + get() { + return encodeBase64$9(this.dataView); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$9('string', str); + } + const dv = decodeBase64$9(str); + setDataView$9.call(this, dv, structure, false, handlers); + } + }); +} + +function getStringDescriptor$9(structure, handlers = {}) { + const { sentinel, instance: { members }} = structure; + const { byteSize: charSize } = members[0]; + return markAsSpecial$9({ + get() { + const dv = this.dataView; + const TypedArray = (charSize === 1) ? Int8Array : Int16Array; + const ta = new TypedArray(dv.buffer, dv.byteOffset, this.length); + const s = decodeText$9(ta, `utf-${charSize * 8}`); + return (sentinel?.value === undefined) ? s : s.slice(0, -1); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$9('a string', str); + } + if (sentinel?.value !== undefined) { + if (str.charCodeAt(str.length - 1) !== sentinel.value) { + str = str + String.fromCharCode(sentinel.value); + } + } + const ta = encodeText$9(str, `utf-${charSize * 8}`); + const dv = new DataView(ta.buffer); + setDataView$9.call(this, dv, structure, false, handlers); + }, + }); +} + +function getTypedArrayDescriptor$9(structure, handlers = {}) { + const { typedArray } = structure; + return markAsSpecial$9({ + get() { + const dv = this.dataView; + const length = dv.byteLength / typedArray.BYTES_PER_ELEMENT; + return new typedArray(dv.buffer, dv.byteOffset, length); + }, + set(ta) { + if (!isTypedArray$9(ta, typedArray)) { + throwTypeMismatch$9(typedArray.name, ta); + } + const dv = new DataView(ta.buffer, ta.byteOffset, ta.byteLength); + setDataView$9.call(this, dv, structure, true, handlers); + }, + }); +} + +function markAsSpecial$9({ get, set }) { + get.special = set.special = true; + return { get, set }; +} + +function definePointer$9(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + isConst, + } = structure; + const { + runtimeSafety = true, + } = env; + const { structure: targetStructure } = member; + const { sentinel } = targetStructure; + const isTargetSlice = (targetStructure.type === StructureType$9.Slice); + const isTargetPointer = (targetStructure.type === StructureType$9.Pointer); + const hasLength = isTargetSlice && !sentinel; + const addressSize = (hasLength) ? byteSize / 2 : byteSize; + const { get: getAddress, set: setAddress } = getDescriptor$9({ + type: MemberType$9.Uint, + bitOffset: 0, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { byteSize: addressSize }, + }, env); + const { get: getLength, set: setLength } = (hasLength) ? getDescriptor$9({ + type: MemberType$9.Uint, + bitOffset: addressSize * 8, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { name: 'usize', byteSize: addressSize }, + }, env) : {}; + const updateTarget = function() { + const prevLocation = this[FIXED_LOCATION$9]; + if (prevLocation) { + const location = this[LOCATION_GETTER$9](); + if (location.address !== prevLocation.address || location.length !== prevLocation.length) { + const { constructor: Target } = targetStructure; + const dv = env.findMemory(location.address, location.length * Target[SIZE$9]); + const target = Target.call(ENVIRONMENT$9, dv, { writable: !isConst }); + this[SLOTS$9][0] = target; + this[FIXED_LOCATION$9] = location; + } + } + }; + const getTargetObject = function() { + updateTarget.call(this); + return this[SLOTS$9][0] ?? throwNullPointer$9(); + }; + const setTargetObject = function(arg) { + if (env.inFixedMemory(this)) { + // the pointer sits in fixed memory--apply the change immediately + if (env.inFixedMemory(arg)) { + const loc = { + address: env.getViewAddress(arg[MEMORY$9]), + length: (hasLength) ? arg.length : 1 + }; + addressSetter.call(this, loc); + this[FIXED_LOCATION$9] = loc; + } else { + throwFixedMemoryTargetRequired$9(); + } + } + this[SLOTS$9][0] = arg; + }; + const getTarget = isValueExpected$9(targetStructure) + ? function() { + const target = getTargetObject.call(this); + return target[GETTER$9](); + } + : getTargetObject; + const setTarget = function(value) { + updateTarget.call(this); + const object = this[SLOTS$9][0] ?? throwNullPointer$9(); + return object[SETTER$9](value); + }; + const alternateCaster = function(arg, options) { + const Target = targetStructure.constructor; + if ((this === ENVIRONMENT$9 || this === PARENT$9) || arg instanceof constructor) { + // casting from buffer to pointer is allowed only if request comes from the runtime + // casting from writable to read-only is also allowed + return false; + } else if (isPointerOf$9(arg, Target)) { + // const/non-const casting + return new constructor(Target(arg['*'], { writable: !isConst }), options); + } else if (isTargetSlice) { + // allow casting to slice through constructor of its pointer + return new constructor(Target(arg), options); + } else { + throwNoCastingToPointer$9(); + } + }; + const finalizer = function() { + const handlers = (isTargetPointer) ? {} : proxyHandlers$j; + const proxy = new Proxy(this, handlers); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$9, { value: proxy }); + return proxy; + }; + const initializer = function(arg) { + const Target = targetStructure.constructor; + if (isPointerOf$9(arg, Target)) { + // initialize with the other pointer'structure target + if (!isConst && arg.constructor.const) { + throwConstantConstraint$9(structure, arg); + } + arg = arg[SLOTS$9][0]; + } + if (arg instanceof Target) { + /* wasm-only */ + restoreMemory$9.call(arg); + /* wasm-only-end */ + if (isConst && !arg[CONST$9]) { + // create read-only version + arg = Target(arg, { writable: false }); + } else if (!isConst && arg[CONST$9]) { + throwReadOnlyTarget$9(structure); + } + } else if (isCompatible$9(arg, Target)) { + // autocast to target type + const dv = getDataView$9(targetStructure, arg, env); + arg = Target(dv, { writable: !isConst }); + } else if (arg !== undefined && !arg[MEMORY$9]) { + // autovivificate target object + const fixed = env.inFixedMemory(this); + const autoObj = new Target(arg, { writable: !isConst, fixed }); + if (runtimeSafety) { + // creation of a new slice using a typed array is probably + // not what the user wants; it's more likely that the intention + // is to point to the typed array but there's a mismatch (e.g. u32 vs i32) + if (targetStructure.typedArray && isBuffer$9(arg?.buffer)) { + warnImplicitArrayCreation$9(targetStructure, arg); + } + } + arg = autoObj; + } else if (arg !== undefined) { + throwInvalidPointerTarget$9(structure, arg); + } + this[TARGET_SETTER$9](arg); + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer, alternateCaster, finalizer }, env); + const addressSetter = function({ address, length }) { + setAddress.call(this, address); + setLength?.call(this, length); + }; + const addressGetter = function() { + const address = getAddress.call(this); + const length = (getLength) + ? getLength.call(this) + : (sentinel) + ? (address) ? env.findSentinel(address, sentinel.bytes) + 1 : 0 + : 1; + return { address, length }; + }; + const instanceDescriptors = { + '*': { get: getTarget, set: setTarget }, + '$': { get: getProxy$9, set: initializer }, + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [TARGET_GETTER$9]: { value: getTargetObject }, + [TARGET_SETTER$9]: { value: setTargetObject }, + [LOCATION_GETTER$9]: { value: addressGetter }, + [LOCATION_SETTER$9]: { value: addressSetter }, + [POINTER_VISITOR$9]: { value: visitPointer$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [VIVIFICATOR$9]: { value: throwNullPointer$9 }, + [NORMALIZER$9]: { value: normalizePointer$9 }, + [FIXED_LOCATION$9]: { value: undefined, writable: true }, + }; + const staticDescriptors = { + child: { get: () => targetStructure.constructor }, + const: { value: isConst }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizePointer$9(cb) { + let target; + try { + target = this['*']; + } catch (err) { + target = Symbol.for('inaccessible'); + } + return cb(target); +} + +function getProxy$9() { + return this[PROXY$9]; +} + +function copyPointer$9({ source }) { + const target = source[SLOTS$9][0]; + if (target) { + this[TARGET_SETTER$9](target); + } +} + +function resetPointer$9({ isActive }) { + if (this[SLOTS$9][0] && !isActive(this)) { + this[SLOTS$9][0] = undefined; + } +} + +function disablePointer$9() { + const disabledProp = { get: throwInaccessiblePointer$9, set: throwInaccessiblePointer$9 }; + const disabledFunc = { value: throwInaccessiblePointer$9 }; + defineProperties$9(this[POINTER$9], { + '*': disabledProp, + '$': disabledProp, + [GETTER$9]: disabledFunc, + [SETTER$9]: disabledFunc, + [TARGET_GETTER$9]: disabledFunc, + }); +} + +function visitPointer$9(fn, options = {}) { + const { + source, + isActive = always$9, + isMutable = always$9, + } = options; + fn.call(this, { source, isActive, isMutable }); +} + +function isPointerOf$9(arg, Target) { + return (arg?.constructor?.child === Target && arg['*']); +} + +const proxyHandlers$j = { + get(pointer, name) { + if (name === POINTER$9) { + return pointer; + } else if (name in pointer) { + return pointer[name]; + } else { + const target = pointer[TARGET_GETTER$9](); + return target[name]; + } + }, + set(pointer, name, value) { + if (name in pointer) { + pointer[name] = value; + } else { + const target = pointer[TARGET_GETTER$9](); + target[name] = value; + } + return true; + }, + deleteProperty(pointer, name) { + if (name in pointer) { + delete pointer[name]; + } else { + const target = pointer[TARGET_GETTER$9](); + delete target[name]; + } + return true; + }, + has(pointer, name) { + if (name in pointer) { + return true; + } else { + const target = pointer[TARGET_GETTER$9](); + return name in target; + } + }, +}; + +function always$9() { + return true; +} + +function never$9() { + return false; +} + +function defineStructShape$9(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const memberDescriptors = {}; + for (const member of members) { + const { get, set } = getDescriptor$9(member, env); + memberDescriptors[member.name] = { get, set, configurable: true, enumerable: true }; + if (member.isRequired && set) { + set.required = true; + } + } + const hasObject = !!members.find(m => m.type === MemberType$9.Object); + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + if (hasPointer) { + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } else if (arg && typeof(arg) === 'object') { + propApplier.call(this, arg); + } else if (arg !== undefined) { + throwInvalidInitializer$9(structure, 'object', arg); + } + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); + const instanceDescriptors = { + $: { get: getSelf$9, set: initializer }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getStructIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$j(structure, always$9) }, + [NORMALIZER$9]: { value: normalizeStruct$9 }, + [PROPS$9]: { value: members.map(m => m.name) }, + }; + const staticDescriptors = { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizeStruct$9(cb, options) { + const object = {}; + for (const [ name, value ] of getStructEntries$9.call(this, options)) { + object[name] = cb(value); + } + return object; +} + +function getStructEntries$9(options) { + return { + [Symbol.iterator]: getStructEntriesIterator$9.bind(this, options), + length: this[PROPS$9].length, + }; +} + +function getStructIterator$9(options) { + const entries = getStructEntries$9.call(this, options); + return entries[Symbol.iterator](); +} + +function getStructEntriesIterator$9(options) { + const self = this; + const props = this[PROPS$9]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + value = [ current, handleError$9(() => self[current], options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getChildVivificator$j(structure) { + const { instance: { members } } = structure; + const objectMembers = {}; + for (const member of members.filter(m => m.type === MemberType$9.Object)) { + objectMembers[member.slot] = member; + } + return function vivificateChild(slot, writable = true) { + const member = objectMembers[slot]; + const { bitOffset, byteSize, structure: { constructor } } = member; + const dv = this[MEMORY$9]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + (bitOffset >> 3); + let len = byteSize; + if (len === undefined) { + if (bitOffset & 7) { + throwNotOnByteBoundary$9(member); + } + len = member.bitSize >> 3; + } + const childDV = new DataView(dv.buffer, offset, len); + const object = this[SLOTS$9][slot] = constructor.call(PARENT$9, childDV, { writable }); + return object; + } +} + +function getPointerVisitor$j(structure, visitorOptions = {}) { + const { + isChildActive = always$9, + isChildMutable = always$9, + } = visitorOptions; + const { instance: { members } } = structure; + const pointerMembers = members.filter(m => m.structure.hasPointer); + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$9, + isMutable = always$9, + } = options; + const childOptions = { + ...options, + isActive: (object) => { + // make sure parent object is active, then check whether the child is active + return isActive(this) && isChildActive.call(this, object); + }, + isMutable: (object) => { + return isMutable(this) && isChildMutable.call(this, object); + }, + }; + for (const { slot } of pointerMembers) { + if (source) { + // when src is a the struct's template, most slots will likely be empty, + // since pointer fields aren't likely to have default values + const srcChild = source[SLOTS$9]?.[slot]; + if (!srcChild) { + continue; + } + childOptions.source = srcChild; + } + const child = this[SLOTS$9][slot] ?? (vivificate ? this[VIVIFICATOR$9](slot) : null); + if (child) { + child[POINTER_VISITOR$9](cb, childOptions); + } + } + }; +} + +function defineArgStruct$9(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const hasObject = !!members.find(m => m.type === MemberType$9.Object); + const constructor = structure.constructor = function(args) { + const dv = env.allocateMemory(byteSize, align); + this[MEMORY$9] = dv; + if (hasObject) { + this[SLOTS$9] = {}; + } + initializer.call(this, args); + }; + const argNames = members.slice(0, -1).map(m => m.name); + const argCount = argNames.length; + const initializer = function(args) { + if (args.length !== argCount) { + throwArgumentCountMismatch$9(structure, args.length); + } + for (const [ index, name ] of argNames.entries()) { + try { + this[name] = args[index]; + } catch (err) { + rethrowArgumentError$9(structure, index, err); + } + } + }; + const memberDescriptors = {}; + for (const member of members) { + memberDescriptors[member.name] = getDescriptor$9(member, env); + } + const isChildMutable = function(object) { + return (object === this.retval); + }; + defineProperties$9(constructor.prototype, { + ...memberDescriptors, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$j(structure, { isChildMutable }) }, + }); + defineProperties$9(constructor, { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }); + return constructor; +} + +function defineArray$9(structure, env) { + const { + length, + byteSize, + align, + instance: { members: [ member ] }, + hasPointer, + } = structure; + const { get, set } = getDescriptor$9(member, env); + const hasStringProp = canBeString$9(member); + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + if (hasPointer) { + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } else { + if (typeof(arg) === 'string' && hasStringProp) { + arg = { string: arg }; + } + if (arg?.[Symbol.iterator]) { + arg = transformIterable$9(arg); + if (arg.length !== length) { + throwArrayLengthMismatch$9(structure, this, arg); + } + let i = 0; + for (const value of arg) { + set.call(this, i++, value); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$9(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$9(structure, arg); + } + } + }; + const finalizer = createArrayProxy$9; + const constructor = structure.constructor = createConstructor$9(structure, { initializer, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); + const hasObject = member.type === MemberType$9.Object; + const instanceDescriptors = { + $: { get: getProxy$9, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + string: hasStringProp && getStringDescriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$9 }, + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [Symbol.iterator]: { value: getArrayIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$i(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$i() }, + [NORMALIZER$9]: { value: normalizeArray$9 }, + }; + const staticDescriptors = { + child: { get: () => member.structure.constructor }, + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function createArrayProxy$9() { + const proxy = new Proxy(this, proxyHandlers$i); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$9, { value: proxy }); + return proxy; +} + +function canBeString$9(member) { + return member.type === MemberType$9.Uint && [ 8, 16 ].includes(member.bitSize); +} + +function normalizeArray$9(cb, options) { + const array = []; + for (const [ index, value ] of getArrayEntries$9.call(this, options)) { + array.push(cb(value)); + } + return array; +} + +function getArrayIterator$9() { + const self = this[ARRAY$9] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self.get(current); + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getArrayEntriesIterator$9(options) { + const self = this[ARRAY$9] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, handleError$9(() => self.get(current), options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getArrayEntries$9(options) { + return { + [Symbol.iterator]: getArrayEntriesIterator$9.bind(this, options), + length: this.length, + }; +} + +function getChildVivificator$i(structure) { + const { instance: { members: [ member ]} } = structure; + const { byteSize, structure: elementStructure } = member; + return function getChild(index, writable = true) { + const { constructor } = elementStructure; + const dv = this[MEMORY$9]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + byteSize * index; + const childDV = new DataView(dv.buffer, offset, byteSize); + const object = this[SLOTS$9][index] = constructor.call(PARENT$9, childDV, { writable }); + return object; + }; +} + +function getPointerVisitor$i(structure) { + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$9, + isMutable = always$9, + } = options; + const childOptions = { + ...options, + isActive: () => isActive(this), + isMutable: () => isMutable(this), + }; + for (let i = 0, len = this.length; i < len; i++) { + // no need to check for empty slots, since that isn't possible + if (source) { + childOptions.source = source?.[SLOTS$9][i]; + } + const child = this[SLOTS$9][i] ?? (vivificate ? this[VIVIFICATOR$9](i) : null); + if (child) { + child[POINTER_VISITOR$9](cb, childOptions); + } + } + }; +} + +function transformIterable$9(arg) { + if (typeof(arg.length) === 'number') { + // it's an array of sort + return arg; + } + const iterator = arg[Symbol.iterator](); + const first = iterator.next(); + const length = first.value?.length; + if (typeof(length) === 'number' && Object.keys(first.value).join() === 'length') { + // return generator with length attached + return Object.assign((function*() { + let result; + while (!(result = iterator.next()).done) { + yield result.value; + } + })(), { length }); + } else { + const array = []; + let result = first; + while (!result.done) { + array.push(result.value); + result = iterator.next(); + } + return array; + } +} + +const proxyHandlers$i = { + get(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return array.get(index); + } else { + switch (name) { + case 'get': + if (!array[ELEMENT_GETTER$9]) { + array[ELEMENT_GETTER$9] = array.get.bind(array); + } + return array[ELEMENT_GETTER$9]; + case 'set': + if (!array[ELEMENT_SETTER$9]) { + array[ELEMENT_SETTER$9] = array.set.bind(array); + } + return array[ELEMENT_SETTER$9]; + case ARRAY$9: + return array; + default: + return array[name]; + } + } + }, + set(array, name, value) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + array.set(index, value); } else { + switch (name) { + case 'get': + array[ELEMENT_GETTER$9] = value; + break; + case 'set': + array[ELEMENT_SETTER$9] = value; + break; + default: + array[name] = value; + } + } + return true; + }, + deleteProperty(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { return false; + } else { + switch (name) { + case 'get': + delete array[ELEMENT_GETTER$9]; + break; + case 'set': + delete array[ELEMENT_SETTER$9]; + break; + default: + delete array[name]; + } + return true; } - }; - const constructor = structure.constructor = createConstructor$8(structure, { initializer, alternateCaster }, env); - const typedArray = structure.typedArray = getTypedArrayClass$8(member); - const toPrimitive = function(hint) { - return (hint === 'string') ? this.$[NAME$8] : getIndex.call(this); - }; - const instanceDescriptors = { - $: { get, set }, - dataView: getDataViewDescriptor$8(structure), - base64: getBase64Descriptor$8(structure), - typedArray: typedArray && getTypedArrayDescriptor$8(structure), - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - [Symbol.toPrimitive]: { value: toPrimitive }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [NORMALIZER$8]: { value: normalizeEnumerationItem$8 }, - }; - const staticDescriptors = { - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, - [ITEMS$8]: { value: {} }, - }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); -} -function normalizeEnumerationItem$8(cb) { - return cb(this.$[NAME$8]); -} + }, + has(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return (index >= 0 && index < array.length); + } else { + return array[name]; + } + }, + ownKeys(array) { + const keys = []; + for (let i = 0, len = array.length; i < len; i++) { + keys.push(`${i}`); + } + keys.push('length', PROXY$9); + return keys; + }, + getOwnPropertyDescriptor(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + if (index >= 0 && index < array.length) { + return { value: array.get(index), enumerable: true, writable: true, configurable: true }; + } + } else { + return Object.getOwnPropertyDescriptor(array, name); + } + }, +}; -function defineErrorSet$8(structure, env) { +function defineEnumerationShape$9(structure, env) { const { byteSize, align, - instance: { members: [ member ] }, + instance: { + members: [ member ], + }, } = structure; - const { get: getIndex } = getDescriptor$8(member, env); - // get the error descriptor instead of the int/uint descriptor - const { get, set } = getDescriptor$8({ ...member, type: MemberType$8.Error, structure }, env); - const expected = [ 'string', 'number' ]; - const propApplier = createPropertyApplier$8(structure); + const { get, set } = getDescriptor$9(member, env); + const expected = [ 'string', 'number', 'tagged union' ]; + const propApplier = createPropertyApplier$9(structure); const initializer = function(arg) { if (arg && typeof(arg) === 'object') { - try { - if (propApplier.call(this, arg) === 0) { - throwInvalidInitializer$8(structure, expected, arg); - } - } catch (err) { - const { error } = arg; - if (typeof(error) === 'string') { - set.call(this, error); - } else { - throw err; - } + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$9(structure, expected, arg); } } else if (arg !== undefined) { set.call(this, arg); } }; const alternateCaster = function(arg) { - if (typeof(arg) === 'number' || typeof(arg) === 'string') { - return constructor[ITEMS$8][arg]; - } else if (!getDataView$8(structure, arg, env)) { - throwInvalidInitializer$8(structure, expected, arg); + if (typeof(arg) === 'string' || typeof(arg) === 'number' || typeof(arg) === 'bigint') { + let item = constructor[arg]; + if (!item) { + if (constructor[MORE$9] && typeof(arg) !== 'string') { + // create the item on-the-fly when enum is non-exhaustive + item = new constructor(undefined); + debugger; + set.call(item, arg, 'number'); + appendEnumeration$1(constructor, `${arg}`, item); + } + } + return item; + } else if (arg instanceof constructor) { + return arg; + } else if (arg?.[TAG$9] instanceof constructor) { + // a tagged union, return the active tag + return arg[TAG$9]; + } else if (!getDataView$9(structure, arg, env)) { + throwInvalidInitializer$9(structure, expected, arg); } else { return false; } }; - const constructor = structure.constructor = createConstructor$8(structure, { initializer, alternateCaster }, env); - Object.setPrototypeOf(constructor.prototype, globalErrorSet$8.prototype); - const typedArray = structure.typedArray = getTypedArrayClass$8(member); - const getMessage = function() { return this.$.message; }; - const toStringTag = function() { return 'Error' }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); const toPrimitive = function(hint) { - if (hint === 'string') { - return Error.prototype.toString.call(this, hint); - } else { - return getIndex.call(this); - } + return (hint === 'string') ? this.$[NAME$9] : get.call(this, 'number'); }; const instanceDescriptors = { $: { get, set }, - message: { get: getMessage }, - dataView: getDataViewDescriptor$8(structure), - base64: getBase64Descriptor$8(structure), - typedArray: typedArray && getTypedArrayDescriptor$8(structure), - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - // ensure that libraries that rely on the string tag for type detection will - // correctly identify the object as an error - [Symbol.toStringTag]: { get: toStringTag }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, [Symbol.toPrimitive]: { value: toPrimitive }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [NORMALIZER$8]: { value: get }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: normalizeEnumerationItem$9 }, }; const staticDescriptors = { - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, - [ITEMS$8]: { value: {} }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); } -let globalErrorSet$8; - -function createGlobalErrorSet() { - globalErrorSet$8 = function() {}; - Object.setPrototypeOf(globalErrorSet$8.prototype, Error.prototype); +function normalizeEnumerationItem$9(cb) { + return cb(this.$[NAME$9]); } -function getGlobalErrorSet$8() { - return globalErrorSet$8; +function appendEnumeration$1(enumeration, name, item) { + if (name !== undefined) { + // enum can have static variables + if (item instanceof enumeration) { + // attach name to item so tagged union code can quickly find it + defineProperties$9(item, { [NAME$9]: { value: name } }); + // call toPrimitive directly since enum can be bigint or number + const index = item[Symbol.toPrimitive](); + defineProperties$9(enumeration, { + [index]: { value: item }, + [name]: { value: item }, + }); + } + } else { + // non-exhaustive enum + defineProperties$9(enumeration, { [MORE$9]: { value: true } }); + } } -function defineErrorUnion$8(structure, env) { +function defineErrorUnion$9(structure, env) { const { byteSize, align, instance: { members }, hasPointer, } = structure; - const { get: getValue, set: setValue } = getDescriptor$8(members[0], env); - const { get: getError, set: setError } = getDescriptor$8(members[1], env); + const { get: getValue, set: setValue } = getDescriptor$9(members[0], env); + const { get: getError, set: setError } = getDescriptor$9(members[1], env); const get = function() { - const error = getError.call(this, true); - if (error) { - throw error; + const errNum = getError.call(this, 'number'); + if (errNum) { + throw getError.call(this); } else { return getValue.call(this); } }; - const isValueVoid = members[0].type === MemberType$8.Void; - const acceptAny = members[1].structure.name === 'anyerror'; - const TargetError = (acceptAny) ? getGlobalErrorSet$8() : members[1].structure.constructor; + const isValueVoid = members[0].type === MemberType$9.Void; + const TargetError = members[1].structure.constructor[CLASS$1]; const isChildActive = function() { - return !getError.call(this, true); + return !getError.call(this, 'number'); }; const clearValue = function() { - this[RESETTER$8](); - this[POINTER_VISITOR$8]?.(resetPointer$8); + this[RESETTER$9](); + this[POINTER_VISITOR$9]?.(resetPointer$9); }; - const hasObject = !!members.find(m => m.type === MemberType$8.Object); - const propApplier = createPropertyApplier$8(structure); + const hasObject = !!members.find(m => m.type === MemberType$9.Object); + const propApplier = createPropertyApplier$9(structure); const initializer = function(arg) { if (arg instanceof constructor) { - this[COPIER$8](arg); + this[COPIER$9](arg); if (hasPointer) { if (isChildActive.call(this)) { - this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); } } } else if (arg instanceof TargetError) { @@ -1521,126 +4776,119 @@ function defineErrorUnion$8(structure, env) { try { // call setValue() first, in case it throws setValue.call(this, arg); - setError.call(this, 0, true); + setError.call(this, 0, 'number'); } catch (err) { if (arg instanceof Error) { // we give setValue a chance to see if the error is actually an acceptable value // now is time to throw an error - throwNotInErrorSet$8(structure); + throwNotInErrorSet$9(structure); + } else if (isErrorJSON$1(arg)) { + setError.call(this, arg); + clearValue.call(this); } else if (arg && typeof(arg) === 'object') { - try { - if (propApplier.call(this, arg) === 0) { - throw err; - } - } catch (err) { - const { error } = arg; - if (typeof(error) === 'string') { - setError.call(this, error); - clearValue.call(this); - } else { - throw err; - } - } + if (propApplier.call(this, arg) === 0) { + throw err; + } } else { throw err; } } } }; - const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; const instanceDescriptors = { '$': { get, set: initializer }, - dataView: getDataViewDescriptor$8(structure), - base64: getBase64Descriptor$8(structure), - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [RESETTER$8]: { value: getMemoryResetter$8(valueBitOffset / 8, valueByteSize) }, - [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, - [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, { isChildActive }) }, - [NORMALIZER$8]: { value: normalizeValue$8 }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [RESETTER$9]: { value: getMemoryResetter$9(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$j(structure, { isChildActive }) }, + [NORMALIZER$9]: { value: normalizeValue$9 }, }; const staticDescriptors = { - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); } -function defineOpaque$8(structure, env) { +function defineOpaque$9(structure, env) { const { byteSize, align, } = structure; const initializer = function() { - throwCreatingOpaque$8(structure); + throwCreatingOpaque$9(structure); }; const valueAccessor = function() { - throwAccessingOpaque$8(structure); + throwAccessingOpaque$9(structure); }; const toPrimitive = function(hint) { const { name } = structure; return `[opaque ${name}]`; }; - const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); const instanceDescriptors = { $: { get: valueAccessor, set: valueAccessor }, - dataView: getDataViewDescriptor$8(structure), - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, + dataView: getDataViewDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, [Symbol.toPrimitive]: { value: toPrimitive }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [NORMALIZER$8]: { value: normalizeOpaque$8 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: normalizeOpaque$9 }, }; const staticDescriptors = { - [COMPAT$8]: { value: getCompatibleTags$8(structure) }, - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); } -function normalizeOpaque$8(cb) { +function normalizeOpaque$9(cb) { return {}; } -function defineOptional$8(structure, env) { +function defineOptional$9(structure, env) { const { byteSize, align, instance: { members }, hasPointer, } = structure; - const { get: getValue, set: setValue } = getDescriptor$8(members[0], env); - const { get: getPresent, set: setPresent } = getDescriptor$8(members[1], env); + const { get: getValue, set: setValue } = getDescriptor$9(members[0], env); + const { get: getPresent, set: setPresent } = getDescriptor$9(members[1], env); const hasPresentFlag = !(members[0].bitSize > 0 && members[0].bitOffset === members[1].bitOffset); const get = function() { const present = getPresent.call(this); if (present) { return getValue.call(this); } else { - this[POINTER_VISITOR$8]?.(resetPointer$8); + this[POINTER_VISITOR$9]?.(resetPointer$9); return null; } }; - const isValueVoid = members[0].type === MemberType$8.Void; + const isValueVoid = members[0].type === MemberType$9.Void; const isChildActive = getPresent; const initializer = function(arg) { if (arg instanceof constructor) { - this[COPIER$8](arg); + this[COPIER$9](arg); if (hasPointer) { // don't bother copying pointers when it's empty if (isChildActive.call(arg)) { - this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); } } } else if (arg === null) { setPresent.call(this, false); - this[RESETTER$8]?.(); + this[RESETTER$9]?.(); // clear references so objects can be garbage-collected - this[POINTER_VISITOR$8]?.(resetPointer$8); + this[POINTER_VISITOR$9]?.(resetPointer$9); } else if (arg !== undefined || isValueVoid) { // call setValue() first, in case it throws setValue.call(this, arg); @@ -1652,31 +4900,111 @@ function defineOptional$8(structure, env) { } } }; - const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; - const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const hasObject = !!members.find(m => m.type === MemberType$9.Object); const instanceDescriptors = { $: { get, set: initializer }, - dataView: getDataViewDescriptor$8(structure), - base64: getBase64Descriptor$8(structure), - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, // no need to reset the value when it's a pointer, since setPresent() would null out memory used by the pointer - [RESETTER$8]: !hasPointer && { value: getMemoryResetter$8(valueBitOffset / 8, valueByteSize) }, - [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, - [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, { isChildActive }) }, - [NORMALIZER$8]: { value: normalizeValue$8 }, + [RESETTER$9]: !hasPointer && { value: getMemoryResetter$9(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$j(structure, { isChildActive }) }, + [NORMALIZER$9]: { value: normalizeValue$9 }, }; const staticDescriptors = { - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function definePrimitive$9(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { get, set } = getDescriptor$9(member, env); + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + } else { + if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + const type = getPrimitiveType$9(member); + throwInvalidInitializer$9(structure, type, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + } + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [Symbol.toPrimitive]: { value: get }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: normalizeValue$9 }, + }; + const staticDescriptors = { + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} +function getIntRange$9(member) { + const { type, bitSize } = member; + const signed = (type === MemberType$9.Int); + let magBits = (signed) ? bitSize - 1 : bitSize; + if (bitSize <= 32) { + const max = 2 ** magBits - 1; + const min = (signed) ? -(2 ** magBits) : 0; + return { min, max }; + } else { + magBits = BigInt(magBits); + const max = 2n ** magBits - 1n; + const min = (signed) ? -(2n ** magBits) : 0n; + return { min, max }; + } +} + +function getPrimitiveClass$9({ type, bitSize }) { + if (type === MemberType$9.Int || type === MemberType$9.Uint) { + if (bitSize <= 32) { + return Number; + } else { + return BigInt; + } + } else if (type === MemberType$9.Float) { + return Number; + } else if (type === MemberType$9.Bool) { + return Boolean; + } } -function defineSlice$8(structure, env) { +function getPrimitiveType$9(member) { + const Primitive = getPrimitiveClass$9(member); + if (Primitive) { + return typeof(Primitive(0)); + } +} + +function defineSlice$9(structure, env) { const { align, instance: { @@ -1684,4921 +5012,6527 @@ function defineSlice$8(structure, env) { }, hasPointer, } = structure; - const { get, set } = getDescriptor$8(member, env); + const { get, set } = getDescriptor$9(member, env); const { byteSize: elementSize, structure: elementStructure } = member; - const sentinel = getSentinel$8(structure, env); + const sentinel = getSentinel$9(structure, env); if (sentinel) { // zero-terminated strings aren't expected to be commonly used // so we're not putting this prop into the standard structure structure.sentinel = sentinel; } - const hasStringProp = canBeString$8(member); + const hasStringProp = canBeString$9(member); const shapeDefiner = function(dv, length, fixed = false) { if (!dv) { dv = env.allocateMemory(length * elementSize, align, fixed); } - this[MEMORY$8] = dv; - this[LENGTH$8] = length; + this[MEMORY$9] = dv; + this[LENGTH$9] = length; }; const shapeChecker = function(arg, length) { - if (length !== this[LENGTH$8]) { - throwArrayLengthMismatch$8(structure, this, arg); + if (length !== this[LENGTH$9]) { + throwArrayLengthMismatch$9(structure, this, arg); } }; // the initializer behave differently depending on whether it's called by the // constructor or by a member setter (i.e. after object's shape has been established) - const propApplier = createPropertyApplier$8(structure); + const propApplier = createPropertyApplier$9(structure); const initializer = function(arg, fixed = false) { if (arg instanceof constructor) { - if (!this[MEMORY$8]) { + if (!this[MEMORY$9]) { shapeDefiner.call(this, null, arg.length, fixed); } else { shapeChecker.call(this, arg, arg.length); } - this[COPIER$8](arg); + this[COPIER$9](arg); if (hasPointer) { - this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); } } else if (typeof(arg) === 'string' && hasStringProp) { initializer.call(this, { string: arg }, fixed); } else if (arg?.[Symbol.iterator]) { - arg = transformIterable$8(arg); - if (!this[MEMORY$8]) { + arg = transformIterable$9(arg); + if (!this[MEMORY$9]) { shapeDefiner.call(this, null, arg.length, fixed); } else { shapeChecker.call(this, arg, arg.length); } let i = 0; for (const value of arg) { - sentinel?.validateValue(value, i, arg.length); - set.call(this, i++, value); - } - } else if (typeof(arg) === 'number') { - if (!this[MEMORY$8] && arg >= 0 && isFinite(arg)) { - shapeDefiner.call(this, null, arg); - } else { - throwInvalidArrayInitializer$8(structure, arg, !this[MEMORY$8]); + sentinel?.validateValue(value, i, arg.length); + set.call(this, i++, value); + } + } else if (typeof(arg) === 'number') { + if (!this[MEMORY$9] && arg >= 0 && isFinite(arg)) { + shapeDefiner.call(this, null, arg); + } else { + throwInvalidArrayInitializer$9(structure, arg, !this[MEMORY$9]); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$9(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$9(structure, arg); + } + }; + const finalizer = createArrayProxy$9; + const constructor = structure.constructor = createConstructor$9(structure, { initializer, shapeDefiner, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); + const hasObject = member.type === MemberType$9.Object; + const shapeHandlers = { shapeDefiner }; + const instanceDescriptors = { + $: { get: getProxy$9, set: initializer }, + length: { get: getLength$9 }, + dataView: getDataViewDescriptor$9(structure, shapeHandlers), + base64: getBase64Descriptor$9(structure, shapeHandlers), + string: hasStringProp && getStringDescriptor$9(structure, shapeHandlers), + typedArray: typedArray && getTypedArrayDescriptor$9(structure, shapeHandlers), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$9 }, + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [Symbol.iterator]: { value: getArrayIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(elementSize, true) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$i(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$i() }, + [NORMALIZER$9]: { value: normalizeArray$9 }, + }; + const staticDescriptors = { + child: { get: () => elementStructure.constructor }, + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: elementSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function getLength$9() { + return this[LENGTH$9]; +} + +function getSentinel$9(structure, env) { + const { + runtimeSafety = true, + } = env; + const { + byteSize, + instance: { members: [ member, sentinel ], template }, + } = structure; + if (!sentinel) { + return; + } + const { get: getSentinelValue } = getDescriptor$9(sentinel, env); + const value = getSentinelValue.call(template, 0); + const { get } = getDescriptor$9(member, env); + const validateValue = (runtimeSafety) ? function(v, i, l) { + if (v === value && i !== l - 1) { + throwMisplacedSentinel$9(structure, v, i, l); + } else if (v !== value && i === l - 1) { + throwMissingSentinel$9(structure, value, i); + } + } : function(v, i, l) { + if (v !== value && i === l - 1) { + throwMissingSentinel$9(structure, value, l); + } + }; + const validateData = (runtimeSafety) ? function(source, len) { + for (let i = 0; i < len; i++) { + const v = get.call(source, i); + if (v === value && i !== len - 1) { + throwMisplacedSentinel$9(structure, value, i, len); + } else if (v !== value && i === len - 1) { + throwMissingSentinel$9(structure, value, len); + } + } + } : function(source, len) { + if (len * byteSize === source[MEMORY$9].byteLength) { + const i = len - 1; + const v = get.call(source, i); + if (v !== value) { + throwMissingSentinel$9(structure, value, len); + } + } + }; + const bytes = template[MEMORY$9]; + return { value, bytes, validateValue, validateData }; +} + +function defineUnionShape$9(structure, env) { + const { + type, + byteSize, + align, + instance: { members, template }, + hasPointer, + } = structure; + const { runtimeSafety } = env; + const isTagged = (type === StructureType$9.TaggedUnion); + const exclusion = (isTagged || (type === StructureType$9.BareUnion && runtimeSafety)); + const memberDescriptors = {}; + const memberInitializers = {}; + const memberValueGetters = {}; + const valueMembers = (exclusion) ? members.slice(0, -1) : members; + const selectorMember = (exclusion) ? members[members.length - 1] : null; + const { get: getSelector, set: setSelector } = (exclusion) ? getDescriptor$9(selectorMember, env) : {}; + const getActiveField = (isTagged) + ? function() { + const item = getSelector.call(this); + return item[NAME$9]; + } + : function() { + const index = getSelector.call(this); + return valueMembers[index].name; + }; + const setActiveField = (isTagged) + ? function(name) { + const { constructor } = selectorMember.structure; + setSelector.call(this, constructor[name]); + } + : function(name) { + const index = valueMembers.findIndex(m => m.name === name); + setSelector.call(this, index); + }; + for (const member of valueMembers) { + const { name } = member; + const { get: getValue, set: setValue } = getDescriptor$9(member, env); + const get = (exclusion) + ? function() { + const currentName = getActiveField.call(this); + if (name !== currentName) { + if (isTagged) { + // tagged union allows inactive member to be queried + return null; + } else { + // whereas bare union does not, since the condition is not detectable + // when runtime safety is off + throwInactiveUnionProperty$9(structure, name, currentName); + } + } + this[POINTER_VISITOR$9]?.(resetPointer$9); + return getValue.call(this); + } + : getValue; + const set = (exclusion && setValue) + ? function(value) { + const currentName = getActiveField.call(this); + if (name !== currentName) { + throwInactiveUnionProperty$9(structure, name, currentName); + } + setValue.call(this, value); + } + : setValue; + const init = (exclusion && setValue) + ? function(value) { + setActiveField.call(this, name); + setValue.call(this, value); + this[POINTER_VISITOR$9]?.(resetPointer$9); + } + : setValue; + memberDescriptors[name] = { get, set, configurable: true, enumerable: true }; + memberInitializers[name] = init; + memberValueGetters[name] = getValue; + } + const hasDefaultMember = !!valueMembers.find(m => !m.isRequired); + const memberKeys = Object.keys(memberDescriptors); + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + /* WASM-ONLY-END */ + this[COPIER$9](arg); + if (hasPointer) { + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } else if (arg && typeof(arg) === 'object') { + let found = 0; + for (const key of memberKeys) { + if (key in arg) { + found++; + } + } + if (found > 1) { + throwMultipleUnionInitializers$9(structure); + } + if (propApplier.call(this, arg) === 0 && !hasDefaultMember) { + throwMissingUnionInitializer$9(structure, arg, exclusion); + } + } else if (arg !== undefined) { + throwInvalidInitializer$9(structure, 'object with a single property', arg); + } + }; + // non-tagged union as marked as not having pointers--if there're actually + // members with pointers, we need to disable them + const pointerMembers = members.filter(m => m.structure.hasPointer); + const hasInaccessiblePointer = !hasPointer && (pointerMembers.length > 0); + const modifier = (hasInaccessiblePointer && !env.comptime) + ? function() { + // make pointer access throw + this[POINTER_VISITOR$9](disablePointer$9, { vivificate: true }); + } + : undefined; + const constructor = structure.constructor = createConstructor$9(structure, { modifier, initializer }, env); + const fieldDescriptor = (isTagged) + ? { + // for tagged union, only the active field + get() { return [ getActiveField.call(this) ] } + } + : { + // for bare and extern union, all members are included + value: valueMembers.map(m => m.name) + }; + const isChildActive = (isTagged) + ? function(child) { + const name = getActiveField.call(this); + const active = memberValueGetters[name].call(this); + return child === active; + } + : never$9; + const hasAnyPointer = hasPointer || hasInaccessiblePointer; + const hasObject = !!members.find(m => m.type === MemberType$9.Object); + const instanceDescriptors = { + $: { get: getSelf$9, set: initializer, configurable: true }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getUnionIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [TAG$9]: isTagged && { get: getSelector, configurable: true }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasAnyPointer && { value: getPointerVisitor$j(structure, { isChildActive }) }, + [PROP_GETTERS$9]: { value: memberValueGetters }, + [NORMALIZER$9]: { value: normalizeUnion$9 }, + [PROPS$9]: fieldDescriptor, + }; + const staticDescriptors = { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); + // replace regular setters with ones that change the active field + const setters = constructor.prototype[PROP_SETTERS$9]; + for (const [ name, init ] of Object.entries(memberInitializers)) { + if (init) { + setters[name] = init; + } + } +} +function normalizeUnion$9(cb, options) { + const object = {}; + for (const [ name, value ] of getUnionEntries$9.call(this, options)) { + object[name] = cb(value); + } + return object; +} + +function getUnionEntries$9(options) { + return { + [Symbol.iterator]: getUnionEntriesIterator$9.bind(this, options), + length: this[PROPS$9].length, + }; +} + +function getUnionIterator$9(options) { + const entries = getUnionEntries$9.call(this, options); + return entries[Symbol.iterator](); +} + +function getUnionEntriesIterator$9(options) { + const self = this; + const props = this[PROPS$9]; + const getters = this[PROP_GETTERS$9]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + // get value of prop with no check + value = [ current, handleError$9(() => getters[current].call(self), options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function defineVector$9(structure, env) { + const { + length, + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { bitSize: elementBitSize, structure: elementStructure } = member; + const elementDescriptors = {}; + for (let i = 0, bitOffset = 0; i < length; i++, bitOffset += elementBitSize) { + const { get, set } = getDescriptor$9({ ...member, bitOffset }, env); + elementDescriptors[i] = { get, set, configurable: true }; + } + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + } else if (arg?.[Symbol.iterator]) { + let argLen = arg.length; + if (typeof(argLen) !== 'number') { + arg = [ ...arg ]; + argLen = arg.length; + } + if (argLen !== length) { + throwArrayLengthMismatch$9(structure, this, arg); + } + let i = 0; + for (const value of arg) { + this[PROP_SETTERS$9][i++].call(this, value); } } else if (arg && typeof(arg) === 'object') { if (propApplier.call(this, arg) === 0) { - throwInvalidArrayInitializer$8(structure, arg); + throwInvalidArrayInitializer$9(structure, arg); } } else if (arg !== undefined) { - throwInvalidArrayInitializer$8(structure, arg); + throwInvalidArrayInitializer$9(structure, arg); } }; - const finalizer = createArrayProxy$8; - const constructor = structure.constructor = createConstructor$8(structure, { initializer, shapeDefiner, finalizer }, env); - const typedArray = structure.typedArray = getTypedArrayClass$8(member); - const hasObject = member.type === MemberType$8.Object; - const shapeHandlers = { shapeDefiner }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); const instanceDescriptors = { - $: { get: getProxy$8, set: initializer }, - length: { get: getLength$8 }, - dataView: getDataViewDescriptor$8(structure, shapeHandlers), - base64: getBase64Descriptor$8(structure, shapeHandlers), - string: hasStringProp && getStringDescriptor$8(structure, shapeHandlers), - typedArray: typedArray && getTypedArrayDescriptor$8(structure, shapeHandlers), - get: { value: get }, - set: { value: set }, - entries: { value: getArrayEntries$8 }, - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - [Symbol.iterator]: { value: getArrayIterator$8 }, - [COPIER$8]: { value: getMemoryCopier$8(elementSize, true) }, - [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$g(structure) }, - [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$g() }, - [NORMALIZER$8]: { value: normalizeArray$8 }, + ...elementDescriptors, + $: { get: getSelf$9, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + entries: { value: getVectorEntries$9 }, + delete: { value: getDestructor$9(structure) }, + [Symbol.iterator]: { value: getVectorIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: normalizeVector$9 }, }; const staticDescriptors = { child: { get: () => elementStructure.constructor }, - [COMPAT$8]: { value: getCompatibleTags$8(structure) }, - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: elementSize }, + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); } -function getLength$8() { - return this[LENGTH$8]; +function normalizeVector$9(cb, options) { + const array = []; + for (const [ index, value ] of getVectorEntries$9.call(this, options)) { + array.push(cb(value)); + } + return array; } -function getSentinel$8(structure, env) { - const { - runtimeSafety = true, - } = env; +function getVectorIterator$9() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self[current]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getVectorEntriesIterator$9() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, self[current] ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getVectorEntries$9() { + return { + [Symbol.iterator]: getVectorEntriesIterator$9.bind(this), + length: this.length, + }; +} + +const StructureType$9 = { + Primitive: 0, + Array: 1, + Struct: 2, + ExternStruct: 3, + PackedStruct: 4, + ArgStruct: 5, + ExternUnion: 6, + BareUnion: 7, + TaggedUnion: 8, + ErrorUnion: 9, + ErrorSet: 10, + Enumeration: 11, + Optional: 12, + Pointer: 13, + Slice: 14, + Vector: 15, + Opaque: 16, + Function: 17, +}; + +const factories$t = Array(Object.values(StructureType$9).length); + +function usePrimitive$9() { + factories$t[StructureType$9.Primitive] = definePrimitive$9; +} + +function useArray$9() { + factories$t[StructureType$9.Array] = defineArray$9; +} + +function useStruct$9() { + factories$t[StructureType$9.Struct] = defineStructShape$9; +} + +function usePackedStruct$9() { + factories$t[StructureType$9.PackedStruct] = defineStructShape$9; +} + +function useExternStruct$9() { + factories$t[StructureType$9.ExternStruct] = defineStructShape$9; +} + +function useArgStruct$9() { + factories$t[StructureType$9.ArgStruct] = defineArgStruct$9; +} + +function useExternUnion$9() { + factories$t[StructureType$9.ExternUnion] = defineUnionShape$9; +} + +function useBareUnion$9() { + factories$t[StructureType$9.BareUnion] = defineUnionShape$9; +} + +function useTaggedUnion$9() { + factories$t[StructureType$9.TaggedUnion] = defineUnionShape$9; +} + +function useErrorUnion$9() { + factories$t[StructureType$9.ErrorUnion] = defineErrorUnion$9; +} + +function useErrorSet$9() { + factories$t[StructureType$9.ErrorSet] = defineErrorSet$9; + useErrorSetTransform$1(); +} + +function useEnumeration$9() { + factories$t[StructureType$9.Enumeration] = defineEnumerationShape$9; + useEnumerationTransform$1(); +} + +function useOptional$9() { + factories$t[StructureType$9.Optional] = defineOptional$9; +} + +function usePointer$9() { + factories$t[StructureType$9.Pointer] = definePointer$9; + useUint$9(); +} + +function useSlice$9() { + factories$t[StructureType$9.Slice] = defineSlice$9; +} + +function useVector$9() { + factories$t[StructureType$9.Vector] = defineVector$9; +} + +function useOpaque$9() { + factories$t[StructureType$9.Opaque] = defineOpaque$9; +} + +function defineProperties$9(object, descriptors) { + for (const [ name, descriptor ] of Object.entries(descriptors)) { + if (descriptor) { + const { + set, + get, + value, + enumerable, + configurable = true, + writable = true, + } = descriptor; + Object.defineProperty(object, name, (get) + ? { get, set, configurable, enumerable } + : { value, configurable, enumerable, writable } + ); + } + } + for (const symbol of Object.getOwnPropertySymbols(descriptors)) { + const descriptor = descriptors[symbol]; + if (descriptor) { + Object.defineProperty(object, symbol, descriptor); + } + } +} + +function attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors) { + // create prototype for read-only objects + const prototypeRO = {}; + Object.setPrototypeOf(prototypeRO, constructor.prototype); + const instanceDescriptorsRO = {}; + const propSetters = {}; + for (const [ name, descriptor ] of Object.entries(instanceDescriptors)) { + if (descriptor?.set) { + instanceDescriptorsRO[name] = { ...descriptor, set: throwReadOnly$9 }; + // save the setters so we can initialize read-only objects + if (name !== '$') { + propSetters[name] = descriptor.set; + } + } else if (name === 'set') { + instanceDescriptorsRO[name] = { value: throwReadOnly$9, configurable: true, writable: true }; + } + } + const vivificate = instanceDescriptors[VIVIFICATOR$9]?.value; + const vivificateDescriptor = { + // vivificate child objects as read-only too + value: function(slot) { + return vivificate.call(this, slot, false); + } + }; + const { get, set } = instanceDescriptors.$; + defineProperties$9(constructor.prototype, { + [CONST$9]: { value: false }, + [ALL_KEYS$9]: { value: Object.keys(propSetters) }, + [SETTER$9]: { value: set }, + [GETTER$9]: { value: get }, + [PROP_SETTERS$9]: { value: propSetters }, + ...instanceDescriptors, + }); + defineProperties$9(constructor, { + [CONST_PROTOTYPE$9]: { value: prototypeRO }, + ...staticDescriptors, + }); + defineProperties$9(prototypeRO, { + constructor: { value: constructor, configurable: true }, + [CONST$9]: { value: true }, + [SETTER$9]: { value: throwReadOnly$9 }, + [VIVIFICATOR$9]: vivificate && vivificateDescriptor, + ...instanceDescriptorsRO, + }); + return constructor; +} + +function createConstructor$9(structure, handlers, env) { const { byteSize, - instance: { members: [ member, sentinel ], template }, + align, + instance: { members, template }, + hasPointer, } = structure; - if (!sentinel) { - return; + const { + modifier, + initializer, + finalizer, + alternateCaster, + shapeDefiner, + } = handlers; + const hasSlots = needSlots$9(members); + // comptime fields are stored in the instance template's slots + let comptimeFieldSlots; + if (template?.[SLOTS$9]) { + const comptimeMembers = members.filter(m => isReadOnly$9(m.type)); + if (comptimeMembers.length > 0) { + comptimeFieldSlots = comptimeMembers.map(m => m.slot); + } } - const { get: getSentinelValue } = getDescriptor$8(sentinel, env); - const value = getSentinelValue.call(template, 0); - const { get } = getDescriptor$8(member, env); - const validateValue = (runtimeSafety) ? function(v, i, l) { - if (v === value && i !== l - 1) { - throwMisplacedSentinel$8(structure, v, i, l); - } else if (v !== value && i === l - 1) { - throwMissingSentinel$8(structure, value, i); - } - } : function(v, i, l) { - if (v !== value && i === l - 1) { - throwMissingSentinel$8(structure, value, l); + const cache = new ObjectCache$9(); + const constructor = function(arg, options = {}) { + const { + writable = true, + fixed = false, + } = options; + const creating = this instanceof constructor; + let self, dv; + if (creating) { + if (arguments.length === 0) { + throwNoInitializer$9(structure); + } + self = this; + if (hasSlots) { + self[SLOTS$9] = {}; + } + if (shapeDefiner) { + // provided by defineSlice(); the slice is different from other structures as it does not have + // a fixed size; memory is allocated by the slice initializer based on the argument given + initializer.call(self, arg, fixed); + dv = self[MEMORY$9]; + } else { + self[MEMORY$9] = dv = env.allocateMemory(byteSize, align, fixed); + } + } else { + if (alternateCaster) { + // casting from number, string, etc. + self = alternateCaster.call(this, arg, options); + if (self !== false) { + return self; + } + } + // look for buffer + dv = requireDataView$9(structure, arg, env); + if (self = cache.find(dv, writable)) { + return self; + } + self = Object.create(writable ? constructor.prototype : constructor[CONST_PROTOTYPE$9]); + if (shapeDefiner) { + setDataView$9.call(self, dv, structure, false, { shapeDefiner }); + } else { + self[MEMORY$9] = dv; + } + if (hasSlots) { + self[SLOTS$9] = {}; + if (hasPointer && arg instanceof constructor) { + // copy pointer from other object + self[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } } - }; - const validateData = (runtimeSafety) ? function(source, len) { - for (let i = 0; i < len; i++) { - const v = get.call(source, i); - if (v === value && i !== len - 1) { - throwMisplacedSentinel$8(structure, value, i, len); - } else if (v !== value && i === len - 1) { - throwMissingSentinel$8(structure, value, len); + if (comptimeFieldSlots) { + for (const slot of comptimeFieldSlots) { + self[SLOTS$9][slot] = template[SLOTS$9][slot]; } } - } : function(source, len) { - if (len * byteSize === source[MEMORY$8].byteLength) { - const i = len - 1; - const v = get.call(source, i); - if (v !== value) { - throwMissingSentinel$8(structure, value, len); + if (modifier) { + modifier.call(self); + } + if (creating) { + // initialize object unless it's been done already + if (!shapeDefiner) { + initializer.call(self, arg); } + if (!writable) { + // create object with read-only prototype + self = Object.assign(Object.create(constructor[CONST_PROTOTYPE$9]), self); + } + } + if (finalizer) { + self = finalizer.call(self); } + return cache.save(dv, writable, self); }; - const bytes = template[MEMORY$8]; - return { value, bytes, validateValue, validateData }; + return constructor; } -function defineUnionShape$8(structure, env) { - const { - type, - byteSize, - align, - instance: { members, template }, - hasPointer, - } = structure; - const { runtimeSafety } = env; - const isTagged = (type === StructureType$8.TaggedUnion); - const exclusion = (isTagged || (type === StructureType$8.BareUnion && runtimeSafety)); - const memberDescriptors = {}; - const memberInitializers = {}; - const memberValueGetters = {}; - const valueMembers = (exclusion) ? members.slice(0, -1) : members; - const selectorMember = (exclusion) ? members[members.length - 1] : null; - const { get: getSelector, set: setSelector } = (exclusion) ? getDescriptor$8(selectorMember, env) : {}; - const getActiveField = (isTagged) - ? function() { - const item = getSelector.call(this); - return item[NAME$8]; - } - : function() { - const index = getSelector.call(this); - return valueMembers[index].name; - }; - const setActiveField = (isTagged) - ? function(name) { - const { constructor } = selectorMember.structure; - setSelector.call(this, constructor[name]); +function createPropertyApplier$9(structure) { + const { instance: { template } } = structure; + return function(arg) { + const argKeys = Object.keys(arg); + const propSetters = this[PROP_SETTERS$9]; + const allKeys = this[ALL_KEYS$9]; + // don't accept unknown props + for (const key of argKeys) { + if (!(key in propSetters)) { + throwNoProperty$9(structure, key); + } } - : function(name) { - const index = valueMembers.findIndex(m => m.name === name); - setSelector.call(this, index); - }; - for (const member of valueMembers) { - const { name } = member; - const { get: getValue, set: setValue } = getDescriptor$8(member, env); - const get = (exclusion) - ? function() { - const currentName = getActiveField.call(this); - if (name !== currentName) { - if (isTagged) { - // tagged union allows inactive member to be queried - return null; - } else { - // whereas bare union does not, since the condition is not detectable - // when runtime safety is off - throwInactiveUnionProperty$8(structure, name, currentName); - } + // checking each name so that we would see inenumerable initializers as well + let normalCount = 0; + let normalFound = 0; + let normalMissing = 0; + let specialFound = 0; + for (const key of allKeys) { + const set = propSetters[key]; + if (set.special) { + if (key in arg) { + specialFound++; } - this[POINTER_VISITOR$8]?.(resetPointer$8); - return getValue.call(this); - } - : getValue; - const set = (exclusion && setValue) - ? function(value) { - const currentName = getActiveField.call(this); - if (name !== currentName) { - throwInactiveUnionProperty$8(structure, name, currentName); + } else { + normalCount++; + if (key in arg) { + normalFound++; + } else if (set.required) { + normalMissing++; } - setValue.call(this, value); - } - : setValue; - const init = (exclusion && setValue) - ? function(value) { - setActiveField.call(this, name); - setValue.call(this, value); - this[POINTER_VISITOR$8]?.(resetPointer$8); - } - : setValue; - memberDescriptors[name] = { get, set, configurable: true, enumerable: true }; - memberInitializers[name] = init; - memberValueGetters[name] = getValue; - } - const hasDefaultMember = !!valueMembers.find(m => !m.isRequired); - const memberKeys = Object.keys(memberDescriptors); - const propApplier = createPropertyApplier$8(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - /* WASM-ONLY-END */ - this[COPIER$8](arg); - if (hasPointer) { - this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); } - } else if (arg && typeof(arg) === 'object') { - let found = 0; - for (const key of memberKeys) { + } + if (normalMissing !== 0 && specialFound === 0) { + const missing = allKeys.filter(k => propSetters[k].required && !(k in arg)); + throwMissingInitializers$9(structure, missing); + } + if (specialFound + normalFound > argKeys.length) { + // some props aren't enumerable + for (const key of allKeys) { if (key in arg) { - found++; + if (!argKeys.includes(key)) { + argKeys.push(key); + } } } - if (found > 1) { - throwMultipleUnionInitializers$8(structure); - } - if (propApplier.call(this, arg) === 0 && !hasDefaultMember) { - throwMissingUnionInitializer$8(structure, arg, exclusion); + } + // apply default values unless all properties are initialized + if (normalFound < normalCount && specialFound === 0) { + if (template) { + if (template[MEMORY$9]) { + this[COPIER$9](template); + } + this[POINTER_VISITOR$9]?.(copyPointer$9, { vivificate: true, source: template }); } - } else if (arg !== undefined) { - throwInvalidInitializer$8(structure, 'object with a single property', arg); } + for (const key of argKeys) { + const set = propSetters[key]; + set.call(this, arg[key]); + } + return argKeys.length; }; - // non-tagged union as marked as not having pointers--if there're actually - // members with pointers, we need to disable them - const pointerMembers = members.filter(m => m.structure.hasPointer); - const hasInaccessiblePointer = !hasPointer && (pointerMembers.length > 0); - const modifier = (hasInaccessiblePointer && !env.comptime) - ? function() { - // make pointer access throw - this[POINTER_VISITOR$8](disablePointer$8, { vivificate: true }); +} + +function needSlots$9(members) { + for (const { type } of members) { + switch (type) { + case MemberType$9.Object: + case MemberType$9.Comptime: + case MemberType$9.Type: + case MemberType$9.Literal: + return true; } - : undefined; - const constructor = structure.constructor = createConstructor$8(structure, { modifier, initializer }, env); - const fieldDescriptor = (isTagged) - ? { - // for tagged union, only the active field - get() { return [ getActiveField.call(this) ] } + } + return false; +} + +function getSelf$9() { + return this; +} + +function useAllStructureTypes$9() { + usePrimitive$9(); + useArray$9(); + useStruct$9(); + useExternStruct$9(); + usePackedStruct$9(); + useArgStruct$9(); + useExternUnion$9(); + useBareUnion$9(); + useTaggedUnion$9(); + useErrorUnion$9(); + useErrorSet$9(); + useEnumeration$9(); + useOptional$9(); + usePointer$9(); + useSlice$9(); + useVector$9(); + useOpaque$9(); +} + +let ObjectCache$9 = class ObjectCache { + [0] = null; + [1] = null; + + find(dv, writable) { + const key = (writable) ? 0 : 1; + const map = this[key]; + return map?.get(dv); + } + + save(dv, writable, object) { + const key = (writable) ? 0 : 1; + let map = this[key]; + if (!map) { + map = this[key] = new WeakMap(); } - : { - // for bare and extern union, all members are included - value: valueMembers.map(m => m.name) - }; - const isChildActive = (isTagged) - ? function(child) { - const name = getActiveField.call(this); - const active = memberValueGetters[name].call(this); - return child === active; + map.set(dv, object); + return object; + } +}; + +let currentGlobalSet$1; +let currentErrorClass$1; + +function defineErrorSet$9(structure, env) { + const { + name, + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + if (!currentErrorClass$1) { + currentErrorClass$1 = class ZigError extends ZigErrorBase$1 {}; + currentGlobalSet$1 = defineErrorSet$9({ ...structure, name: 'anyerror' }, env); + } + if (currentGlobalSet$1 && name === 'anyerror') { + structure.constructor = currentGlobalSet$1; + structure.typedArray = getTypedArrayClass$9(member); + return currentGlobalSet$1; + } + const errorClass = currentErrorClass$1; + const { get, set } = getDescriptor$9(member, env); + const expected = [ 'string', 'number' ]; + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor[CLASS$1]) { + set.call(this, arg); + } else if (arg && typeof(arg) === 'object' && !isErrorJSON$1(arg)) { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$9(structure, expected, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'number' || typeof(arg) === 'string') { + return constructor[arg]; + } else if (arg instanceof constructor[CLASS$1]) { + return constructor[Number(arg)]; + } else if (isErrorJSON$1(arg)) { + return constructor[`Error: ${arg.error}`]; + } else if (!getDataView$9(structure, arg, env)) { + throwInvalidInitializer$9(structure, expected, arg); + } else { + return false; } - : never$8; - const hasAnyPointer = hasPointer || hasInaccessiblePointer; - const hasObject = !!members.find(m => m.type === MemberType$8.Object); + }; + // items are inserted when static members get attached in static.js + const constructor = structure.constructor = createConstructor$9(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); const instanceDescriptors = { - $: { get: getSelf$8, set: initializer, configurable: true }, - dataView: getDataViewDescriptor$8(structure), - base64: getBase64Descriptor$8(structure), - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - ...memberDescriptors, - [Symbol.iterator]: { value: getUnionIterator$8 }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [TAG$8]: isTagged && { get: getSelector, configurable: true }, - [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, - [POINTER_VISITOR$8]: hasAnyPointer && { value: getPointerVisitor$h(structure, { isChildActive }) }, - [PROP_GETTERS$8]: { value: memberValueGetters }, - [NORMALIZER$8]: { value: normalizeUnion$8 }, - [PROPS$8]: fieldDescriptor, - }; + $: { get, set }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: get }, + }; const staticDescriptors = { - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + [CLASS$1]: { value: errorClass }, + // the PROPS array is normally set in static.js; it needs to be set here for anyerror + // so we can add names to it as error sets are defined + [PROPS$9]: (name === 'anyerror') ? { value: [] } : undefined, }; - attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); - // replace regular setters with ones that change the active field - const setters = constructor.prototype[PROP_SETTERS$8]; - for (const [ name, init ] of Object.entries(memberInitializers)) { - if (init) { - setters[name] = init; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function isErrorJSON$1(arg) { + return typeof(arg) === 'object' && typeof(arg.error) === 'string' && Object.keys(arg).length === 1 ; +} + +let ZigErrorBase$1 = class ZigErrorBase extends Error { + constructor(name, number) { + super(deanimalizeErrorName$1(name)); + this.number = number; + } + + [Symbol.toPrimitive](hint) { + if (hint === 'string') { + return Error.prototype.toString.call(this, hint); + } else { + return this.number; } + } + + toJSON() { + return { error: this.message }; } +}; + +function throwNoInitializer$9(structure) { + const { name } = structure; + throw new TypeError(`An initializer must be provided to the constructor of ${name}, even when the intended value is undefined`); } -function normalizeUnion$8(cb, options) { - const object = {}; - for (const [ name, value ] of getUnionEntries$8.call(this, options)) { - object[name] = cb(value); + +function throwBufferSizeMismatch$9(structure, dv, target = null) { + const { name, type, byteSize } = structure; + const actual = dv.byteLength; + const s = (byteSize !== 1) ? 's' : ''; + if (type === StructureType$9.Slice && !target) { + throw new TypeError(`${name} has elements that are ${byteSize} byte${s} in length, received ${actual}`); + } else { + const total = (type === StructureType$9.Slice) ? target.length * byteSize : byteSize; + throw new TypeError(`${name} has ${total} byte${s}, received ${actual}`); } - return object; } -function getUnionEntries$8(options) { - return { - [Symbol.iterator]: getUnionEntriesIterator$8.bind(this, options), - length: this[PROPS$8].length, - }; +function throwBufferExpected$9(structure) { + const { type, byteSize, typedArray } = structure; + const s = (byteSize !== 1) ? 's' : ''; + const acceptable = [ 'ArrayBuffer', 'DataView' ].map(addArticle$9); + if (typedArray) { + acceptable.push(addArticle$9(typedArray.name)); + } + if (type === StructureType$9.Slice) { + throw new TypeError(`Expecting ${formatList$9(acceptable)} that can accommodate items ${byteSize} byte${s} in length`); + } else { + throw new TypeError(`Expecting ${formatList$9(acceptable)} that is ${byteSize} byte${s} in length`); + } } -function getUnionIterator$8(options) { - const entries = getUnionEntries$8.call(this, options); - return entries[Symbol.iterator](); +function throwEnumExpected$9(structure, arg) { + const { name } = structure; + if (typeof(arg) === 'number' || typeof(arg) === 'bigint') { + throw new TypeError(`Value given does not correspond to an item of enum ${name}: ${arg}`); + } else { + throw new TypeError(`Enum item of the type ${name} expected, received ${arg}`); + } } -function getUnionEntriesIterator$8(options) { - const self = this; - const props = this[PROPS$8]; - const getters = this[PROP_GETTERS$8]; - let index = 0; - return { - next() { - let value, done; - if (index < props.length) { - const current = props[index++]; - // get value of prop with no check - value = [ current, handleError$8(() => getters[current].call(self), options) ]; - done = false; - } else { - done = true; - } - return { value, done }; - }, - }; +function throwErrorExpected$9(structure, arg) { + const { name } = structure; + const type = typeof(arg); + if (type === 'string' || type === 'number' || isErrorJSON$1(arg)) { + if (isErrorJSON$1(arg)) { + arg = `{ error: ${JSON.stringify(arg.error)} }`; + } + throw new TypeError(`Error ${type} does not corresponds to any error in error set ${name}: ${arg}`); + } else { + throw new TypeError(`Error of the type ${name} expected, received ${arg}`); + } +} + +function throwNotInErrorSet$9(structure) { + const { name } = structure; + throw new TypeError(`Error given is not a part of error set ${name}`); +} + +function throwMultipleUnionInitializers$9(structure) { + const { name } = structure; + throw new TypeError(`Only one property of ${name} can be given a value`); +} + +function throwInactiveUnionProperty$9(structure, name, currentName) { + throw new TypeError(`Accessing property ${name} when ${currentName} is active`); +} + +function throwMissingUnionInitializer$9(structure, arg, exclusion) { + const { name, instance: { members } } = structure; + const missing = members.slice(0, exclusion ? -1 : undefined).map(m => m.name); + throw new TypeError(`${name} needs an initializer for one of its union properties: ${missing.join(', ')}`); +} + +function throwInvalidInitializer$9(structure, expected, arg) { + const { name } = structure; + const acceptable = []; + if (Array.isArray(expected)) { + for (const type of expected) { + acceptable.push(addArticle$9(type)); + } + } else { + acceptable.push(addArticle$9(expected)); + } + const received = getDescription$9(arg); + throw new TypeError(`${name} expects ${formatList$9(acceptable)} as argument, received ${received}`); +} + +function throwInvalidArrayInitializer$9(structure, arg, shapeless = false) { + const { instance: { members: [ member ] }, type, typedArray } = structure; + const acceptable = []; + const primitive = getPrimitiveType$9(member); + if (primitive) { + let object; + switch (member.structure?.type) { + case StructureType$9.Enumeration: object = 'enum item'; break; + case StructureType$9.ErrorSet: object = 'error'; break; + default: object = primitive; + } + acceptable.push(`array of ${object}s`); + } else { + acceptable.push(`array of objects`); + } + if (typedArray) { + acceptable.push(typedArray.name); + } + if (type === StructureType$9.Slice && shapeless) { + acceptable.push(`length`); + } + throwInvalidInitializer$9(structure, acceptable.join(' or '), arg); +} + +function throwArrayLengthMismatch$9(structure, target, arg) { + const { name, length, instance: { members: [ member ] } } = structure; + const { structure: { constructor: elementConstructor} } = member; + const { length: argLength, constructor: argConstructor } = arg; + // get length from object whech it's a slice + const actualLength = target?.length ?? length; + const s = (actualLength !== 1) ? 's' : ''; + let received; + if (argConstructor === elementConstructor) { + received = `only a single one`; + } else if (argConstructor.child === elementConstructor) { + received = `a slice/array that has ${argLength}`; + } else { + received = `${argLength} initializer${argLength > 1 ? 's' : ''}`; + } + throw new TypeError(`${name} has ${actualLength} element${s}, received ${received}`); +} + +function throwMissingInitializers$9(structure, missing) { + const { name } = structure; + throw new TypeError(`Missing initializers for ${name}: ${missing.join(', ')}`); +} + +function throwNoProperty$9(structure, propName) { + const { name, instance: { members } } = structure; + const member = members.find(m => m.name === propName); + if (member) { + throw new TypeError(`Comptime value cannot be changed: ${propName}`); + } else { + throw new TypeError(`${name} does not have a property with that name: ${propName}`); + } +} + +function throwArgumentCountMismatch$9(structure, actual) { + const { name, instance: { members } } = structure; + const argCount = members.length - 1; + const s = (argCount !== 1) ? 's' : ''; + throw new Error(`${name} expects ${argCount} argument${s}, received ${actual}`); +} + +function rethrowArgumentError$9(structure, index, err) { + const { name, instance: { members } } = structure; + // Zig currently does not provide the argument name + const argName = `args[${index}]`; + const argCount = members.length - 1; + const prefix = (index !== 0) ? '..., ' : ''; + const suffix = (index !== argCount - 1) ? ', ...' : ''; + const argLabel = prefix + argName + suffix; + const newError = new err.constructor(`${name}(${argLabel}): ${err.message}`); + newError.stack = err.stack; + throw newError; +} + +function throwNoCastingToPointer$9(structure) { + throw new TypeError(`Non-slice pointers can only be created with the help of the new operator`); +} + +function throwConstantConstraint$9(structure, pointer) { + const { name: target } = structure; + const { constructor: { name } } = pointer; + throw new TypeError(`Conversion of ${name} to ${target} requires an explicit cast`); +} + +function throwMisplacedSentinel$9(structure, value, index, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}, found at ${index}`); +} + +function throwMissingSentinel$9(structure, value, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}`); +} + +function throwTypeMismatch$9(expected, arg) { + const received = getDescription$9(arg); + throw new TypeError(`Expected ${addArticle$9(expected)}, received ${received}`) +} + +function throwInaccessiblePointer$9() { + throw new TypeError(`Pointers within an untagged union are not accessible`); +} + +function throwNullPointer$9() { + throw new TypeError(`Null pointer`); +} + +function throwInvalidPointerTarget$9(structure, arg) { + const { name } = structure; + let target; + if (arg != null) { + const type = typeof(arg); + const noun = (type === 'object' && arg.constructor !== Object) ? `${arg.constructor.name} object`: type; + const a = article$9(noun); + target = `${a} ${noun}`; + } else { + target = arg + ''; + } + throw new TypeError(`${name} cannot point to ${target}`) +} + +function throwFixedMemoryTargetRequired$9(structure, arg) { + throw new TypeError(`Pointers in fixed memory cannot point to garbage-collected object`); +} + + +function throwOverflow$9(member, value) { + const typeName = getTypeName$9(member); + throw new TypeError(`${typeName} cannot represent the value given: ${value}`); +} + +function throwOutOfBound$9(member, index) { + const { name } = member; + throw new RangeError(`Index exceeds the size of ${name ?? 'array'}: ${index}`); +} + +function rethrowRangeError$9(member, index, err) { + if (err instanceof RangeError) { + throwOutOfBound$9(member, index); + } else { + throw err; + } +} + +function throwNotUndefined$9(member) { + const { name } = member; + throw new RangeError(`Property ${name} can only be undefined`); +} + +function throwNotOnByteBoundary$9(member) { + const { name, structure: { name: { struct }} } = member; + throw new TypeError(`Unable to create ${struct} as it is not situated on a byte boundary: ${name}`); } -function defineVector$8(structure, env) { - const { - length, - byteSize, - align, - instance: { members: [ member ] }, - } = structure; - const { bitSize: elementBitSize, structure: elementStructure } = member; - const elementDescriptors = {}; - for (let i = 0, bitOffset = 0; i < length; i++, bitOffset += elementBitSize) { - const { get, set } = getDescriptor$8({ ...member, bitOffset }, env); - elementDescriptors[i] = { get, set, configurable: true }; - } - const propApplier = createPropertyApplier$8(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$8](arg); - } else if (arg?.[Symbol.iterator]) { - let argLen = arg.length; - if (typeof(argLen) !== 'number') { - arg = [ ...arg ]; - argLen = arg.length; - } - if (argLen !== length) { - throwArrayLengthMismatch$8(structure, this, arg); - } - let i = 0; - for (const value of arg) { - this[PROP_SETTERS$8][i++].call(this, value); - } - } else if (arg && typeof(arg) === 'object') { - if (propApplier.call(this, arg) === 0) { - throwInvalidArrayInitializer$8(structure, arg); - } - } else if (arg !== undefined) { - throwInvalidArrayInitializer$8(structure, arg); - } - }; - const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); - const typedArray = structure.typedArray = getTypedArrayClass$8(member); - const instanceDescriptors = { - ...elementDescriptors, - $: { get: getSelf$8, set: initializer }, - length: { value: length }, - dataView: getDataViewDescriptor$8(structure), - base64: getBase64Descriptor$8(structure), - typedArray: typedArray && getTypedArrayDescriptor$8(structure), - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - entries: { value: getVectorEntries$8 }, - delete: { value: getDestructor$8(structure) }, - [Symbol.iterator]: { value: getVectorIterator$8 }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [NORMALIZER$8]: { value: normalizeVector$8 }, - }; - const staticDescriptors = { - child: { get: () => elementStructure.constructor }, - [COMPAT$8]: { value: getCompatibleTags$8(structure) }, - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, - }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +function throwReadOnly$9() { + throw new TypeError(`Unable to modify read-only object`); } -function normalizeVector$8(cb, options) { - const array = []; - for (const [ index, value ] of getVectorEntries$8.call(this, options)) { - array.push(cb(value)); - } - return array; +function throwReadOnlyTarget$9(structure) { + const { name } = structure; + throw new TypeError(`${name} cannot point to a read-only object`); } -function getVectorIterator$8() { - const self = this; - const length = this.length; - let index = 0; - return { - next() { - let value, done; - if (index < length) { - const current = index++; - value = self[current]; - done = false; - } else { - done = true; - } - return { value, done }; - }, - }; +function throwAccessingOpaque$9(structure) { + const { name } = structure; + throw new TypeError(`Unable to access opaque structure ${name}`); } -function getVectorEntriesIterator$8() { - const self = this; - const length = this.length; - let index = 0; - return { - next() { - let value, done; - if (index < length) { - const current = index++; - value = [ current, self[current] ]; - done = false; +function throwCreatingOpaque$9(structure) { + const { name } = structure; + throw new TypeError(`Unable to create instance of ${name}, as it is opaque`); +} + +function warnImplicitArrayCreation$9(structure, arg) { + const created = addArticle$9(structure.typedArray.name); + const source = addArticle$9(arg.constructor.name); + console.warn(`Implicitly creating ${created} from ${source}`); +} + +function deanimalizeErrorName$1(name) { + // deal with snake_case first + let s = name.replace(/_/g, ' '); + // then camelCase, using a try block in case Unicode regex fails + try { + s = s.replace(/(\p{Uppercase}+)(\p{Lowercase}*)/gu, (m0, m1, m2) => { + if (m1.length === 1) { + return ` ${m1.toLocaleLowerCase()}${m2}`; } else { - done = true; + if (m2) { + const acronym = m1.substring(0, m1.length - 1); + const letter = m1.charAt(m1.length - 1).toLocaleLowerCase(); + return ` ${acronym} ${letter}${m2}`; + } else { + return ` ${m1}`; + } } - return { value, done }; - }, - }; + }).trimStart(); + /* c8 ignore next 2 */ + } catch (err) { + } + return s.charAt(0).toLocaleUpperCase() + s.substring(1); } -function getVectorEntries$8() { - return { - [Symbol.iterator]: getVectorEntriesIterator$8.bind(this), - length: this.length, - }; +function getDescription$9(arg) { + const type = typeof(arg); + let s; + if (type === 'object') { + s = (arg) ? Object.prototype.toString.call(arg) : 'null'; + } else { + s = type; + } + return addArticle$9(s); } -const StructureType$8 = { - Primitive: 0, - Array: 1, - Struct: 2, - ExternStruct: 3, - PackedStruct: 4, - ArgStruct: 5, - ExternUnion: 6, - BareUnion: 7, - TaggedUnion: 8, - ErrorUnion: 9, - ErrorSet: 10, - Enumeration: 11, - Optional: 12, - Pointer: 13, - Slice: 14, - Vector: 15, - Opaque: 16, - Function: 17, -}; - -const factories$q = Array(Object.values(StructureType$8).length); +function addArticle$9(noun) { + return `${article$9(noun)} ${noun}`; +} -function usePrimitive$8() { - factories$q[StructureType$8.Primitive] = definePrimitive$8; +function article$9(noun) { + return /^\W*[aeiou]/i.test(noun) ? 'an' : 'a'; } -function useArray$8() { - factories$q[StructureType$8.Array] = defineArray$8; +function formatList$9(list, conj = 'or') { + const sep = ` ${conj} `; + if (list.length > 2) { + return list.slice(0, -1).join(', ') + sep + list[list.length - 1]; + } else { + return list.join(sep); + } } -function useStruct$8() { - factories$q[StructureType$8.Struct] = defineStructShape$8; +function getBoolAccessor$9(access, member) { + return cacheMethod$9(access, member, () => { + if (isByteAligned$9(member)) { + const { byteSize } = member; + const typeName = getTypeName$9({ type: MemberType$9.Int, bitSize: byteSize * 8 }); + if (access === 'get') { + const get = DataView.prototype[`get${typeName}`]; + return function(offset, littleEndian) { + return !!get.call(this, offset, littleEndian); + }; + } else { + const set = DataView.prototype[`set${typeName}`]; + const T = (byteSize > 4) ? 1n : 1; + const F = (byteSize > 4) ? 0n : 0; + return function(offset, value, littleEndian) { + set.call(this, offset, value ? T : F, littleEndian); + }; + } + } else { + return getExtendedTypeAccessor$9(access, member); + } + }); } -function usePackedStruct$8() { - factories$q[StructureType$8.PackedStruct] = defineStructShape$8; +function getNumericAccessor$9(access, member) { + return cacheMethod$9(access, member, (name) => { + if (DataView.prototype[name]) { + return DataView.prototype[name]; + } else { + return getExtendedTypeAccessor$9(access, member); + } + }); } -function useExternStruct$8() { - factories$q[StructureType$8.ExternStruct] = defineStructShape$8; +const factories$s = {}; + +function useExtendedBool$9() { + factories$s[MemberType$9.Bool] = getExtendedBoolAccessor$9; } -function useArgStruct$8() { - factories$q[StructureType$8.ArgStruct] = defineArgStruct$8; +function useExtendedInt$9() { + factories$s[MemberType$9.Int] = getExtendedIntAccessor$9; } -function useExternUnion$8() { - factories$q[StructureType$8.ExternUnion] = defineUnionShape$8; +function useExtendedUint$9() { + factories$s[MemberType$9.Uint] = getExtendedUintAccessor$9; } -function useBareUnion$8() { - factories$q[StructureType$8.BareUnion] = defineUnionShape$8; +function useExtendedFloat$9() { + factories$s[MemberType$9.Float] = getExtendedFloatAccessor$9; } -function useTaggedUnion$8() { - factories$q[StructureType$8.TaggedUnion] = defineUnionShape$8; +function getExtendedTypeAccessor$9(access, member) { + const f = factories$s[member.type]; + return f(access, member); } -function useErrorUnion$8() { - factories$q[StructureType$8.ErrorUnion] = defineErrorUnion$8; +function getExtendedBoolAccessor$9(access, member) { + const { bitOffset } = member; + const bitPos = bitOffset & 0x07; + const mask = 1 << bitPos; + const get = DataView.prototype.getInt8; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + return !!(n & mask); + }; + } else { + const set = DataView.prototype.setInt8; + return function(offset, value) { + const n = get.call(this, offset); + const b = (value) ? n | mask : n & ~mask; + set.call(this, offset, b); + }; + } } -function useErrorSet$8() { - factories$q[StructureType$8.ErrorSet] = defineErrorSet$8; +function getExtendedIntAccessor$9(access, member) { + if (isByteAligned$9(member)) { + return getAlignedIntAccessor$9(access, member) + } else { + return getUnalignedIntAccessor$9(access, member); + } } -function useEnumeration$8() { - factories$q[StructureType$8.Enumeration] = defineEnumerationShape$8; +function getExtendedUintAccessor$9(access, member) { + if (isByteAligned$9(member)) { + return getAlignedUintAccessor$9(access, member) + } else { + return getUnalignedUintAccessor$9(access, member); + } } -function useOptional$8() { - factories$q[StructureType$8.Optional] = defineOptional$8; +function getExtendedFloatAccessor$9(access, member) { + if (isByteAligned$9(member)) { + return getAlignedFloatAccessor$9(access, member) + } else { + return getUnalignedFloatAccessor$9(access, member); + } } -function usePointer$8() { - factories$q[StructureType$8.Pointer] = definePointer$8; +function getDataView$9(structure, arg, env) { + const { type, byteSize, typedArray } = structure; + let dv; + // not using instanceof just in case we're getting objects created in other contexts + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView') { + dv = arg; + } else if (tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + dv = env.obtainView(arg, 0, arg.byteLength); + } else if (typedArray && tag === typedArray.name || (tag === 'Uint8ClampedArray' && typedArray === Uint8Array)) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else if (tag === 'Uint8Array' && typeof(Buffer) === 'function' && arg instanceof Buffer) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else { + const memory = arg?.[MEMORY$9]; + if (memory) { + const { constructor, instance: { members: [ member ] } } = structure; + if (arg instanceof constructor) { + return memory; + } else if (type === StructureType$9.Array || type === StructureType$9.Slice || type === StructureType$9.Vector) { + const { byteSize: elementSize, structure: { constructor: Child } } = member; + const number = findElements$9(arg, Child); + if (number !== undefined) { + if (type === StructureType$9.Slice || number * elementSize === byteSize) { + return memory; + } else { + throwArrayLengthMismatch$9(structure, null, arg); + } + } + } + } + } + if (dv && byteSize !== undefined) { + checkDataViewSize$9(dv, structure); + } + return dv; } -function useSlice$8() { - factories$q[StructureType$8.Slice] = defineSlice$8; +function checkDataView$9(dv) { + if (dv?.[Symbol.toStringTag] !== 'DataView') { + throwTypeMismatch$9('a DataView', dv); + } + return dv; } -function useVector$8() { - factories$q[StructureType$8.Vector] = defineVector$8; +function checkDataViewSize$9(dv, structure) { + const { byteSize, type } = structure; + const multiple = type === StructureType$9.Slice; + if (multiple ? dv.byteLength % byteSize !== 0 : dv.byteLength !== byteSize) { + throwBufferSizeMismatch$9(structure, dv); + } } -function useOpaque$8() { - factories$q[StructureType$8.Opaque] = defineOpaque$8; +function setDataView$9(dv, structure, copy, handlers) { + const { byteSize, type, sentinel } = structure; + const multiple = type === StructureType$9.Slice; + if (!this[MEMORY$9]) { + const { shapeDefiner } = handlers; + checkDataViewSize$9(dv, structure); + const len = dv.byteLength / byteSize; + const source = { [MEMORY$9]: dv }; + sentinel?.validateData(source, len); + shapeDefiner.call(this, copy ? null : dv, len); + if (copy) { + this[COPIER$9](source); + } + } else { + const byteLength = multiple ? byteSize * this.length : byteSize; + if (dv.byteLength !== byteLength) { + throwBufferSizeMismatch$9(structure, dv, this); + } + const source = { [MEMORY$9]: dv }; + sentinel?.validateData(source, this.length); + this[COPIER$9](source); + } } -function getStructureFactory(type) { - const f = factories$q[type]; - return f; +function findElements$9(arg, Child) { + // casting to a array/slice + const { constructor: Arg } = arg; + if (Arg === Child) { + // matching object + return 1; + } else if (Arg.child === Child) { + // matching slice/array + return arg.length; + } } -function flagMemberUsage(member, features) { - const { type } = member; - switch (type) { - case MemberType$8.Bool: - features.useBool = true; - if (!isByteAligned$8(member)) { - features.useExtendedBool = true; - } - break; - case MemberType$8.Int: - features.useInt = true; - if(!isByteAligned$8(member) || !hasStandardIntSize(member)) { - features.useExtendedInt = true; - } - break; - case MemberType$8.Uint: - features.useUint = true; - if(!isByteAligned$8(member) || !hasStandardIntSize(member)) { - features.useExtendedUint = true; - } - break; - case MemberType$8.Float: - features.useFloat = true; - if (!isByteAligned$8(member) || !hasStandardFloatSize(member)) { - features.useExtendedFloat = true; - } - break; - case MemberType$8.EnumerationItem: { - features.useEnumerationItem = true; - const { type, structure } = member.structure.instance.members[0]; - flagMemberUsage({ ...member, type, structure }, features); - } break; - case MemberType$8.Error: - features.useError = true; - break; - case MemberType$8.Object: - features.useObject = true; - break; - case MemberType$8.Void: - features.useVoid = true; - break; - case MemberType$8.Null: - features.useNull = true; - break; - case MemberType$8.Undefined: - features.useUndefined = true; - break; - case MemberType$8.Type: - features.useType = true; - break; - case MemberType$8.Comptime: - features.useComptime = true; - break; - case MemberType$8.Static: - features.useStatic = true; - break; - case MemberType$8.Literal: - features.useLiteral = true; - break; +function requireDataView$9(structure, arg, env) { + const dv = getDataView$9(structure, arg, env); + if (!dv) { + throwBufferExpected$9(structure); } + return dv; } -function flagStructureUsage(structure, features) { - const { type } = structure; - const [ name ] = Object.entries(StructureType$8).find(a => a[1] === type); - features[`use${name}`] = true; - for (const members of [ structure.instance.members, structure.static.members ]) { - for (const member of members) { - flagMemberUsage(member, features); +function getTypedArrayClass$9(member) { + const { type: memberType, byteSize } = member; + if (memberType === MemberType$9.Int) { + switch (byteSize) { + case 1: return Int8Array; + case 2: return Int16Array; + case 4: return Int32Array; + case 8: return BigInt64Array; + } + } else if (memberType === MemberType$9.Uint) { + switch (byteSize) { + case 1: return Uint8Array; + case 2: return Uint16Array; + case 4: return Uint32Array; + case 8: return BigUint64Array; + } + } else if (memberType === MemberType$9.Float) { + switch (byteSize) { + case 4: return Float32Array; + case 8: return Float64Array; } + } else if (memberType === MemberType$9.Object) { + return member.structure.typedArray; } - switch (type) { - case StructureType$8.Pointer: - // pointer structure has Object member, while needing support for Uint - features.useUint = true; - break; - case StructureType$8.Enumeration: - // enum structure has Int/Uint member, while needing support for EnumerationItem - features.useEnumerationItem = true; - break; - case StructureType$8.ErrorSet: - // error set structures have Uint member, while needing support for Error - features.useError = true; - break; - } + return null; } -function getFeaturesUsed(structures) { - const features = {}; - for (const structure of structures) { - flagStructureUsage(structure, features); - } - return Object.keys(features); +function isTypedArray$9(arg, TypedArray) { + const tag = arg?.[Symbol.toStringTag]; + return (!!TypedArray && tag === TypedArray.name); } -function defineProperties$8(object, descriptors) { - for (const [ name, descriptor ] of Object.entries(descriptors)) { - if (descriptor) { - const { - set, - get, - value, - enumerable, - configurable = true, - writable = true, - } = descriptor; - Object.defineProperty(object, name, (get) - ? { get, set, configurable, enumerable } - : { value, configurable, enumerable, writable } - ); +function isCompatible$9(arg, constructor) { + const tags = constructor[COMPAT$9]; + if (tags) { + const tag = arg?.[Symbol.toStringTag]; + if (tags.includes(tag)) { + return true; } } - for (const symbol of Object.getOwnPropertySymbols(descriptors)) { - const descriptor = descriptors[symbol]; - if (descriptor) { - Object.defineProperty(object, symbol, descriptor); + if (constructor.child) { + if (findElements$9(arg, constructor.child) !== undefined) { + return true; } } + return false; } -function attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors) { - // create prototype for read-only objects - const prototypeRO = {}; - Object.setPrototypeOf(prototypeRO, constructor.prototype); - const instanceDescriptorsRO = {}; - const propSetters = {}; - for (const [ name, descriptor ] of Object.entries(instanceDescriptors)) { - if (descriptor?.set) { - instanceDescriptorsRO[name] = { ...descriptor, set: throwReadOnly$8 }; - // save the setters so we can initialize read-only objects - if (name !== '$') { - propSetters[name] = descriptor.set; - } - } else if (name === 'set') { - instanceDescriptorsRO[name] = { value: throwReadOnly$8, configurable: true, writable: true }; +function getCompatibleTags$9(structure) { + const { typedArray } = structure; + const tags = []; + if (typedArray) { + tags.push(typedArray.name); + tags.push('DataView'); + if (typedArray === Uint8Array || typedArray === Int8Array) { + tags.push('Uint8ClampedArray'); + tags.push('ArrayBuffer'); + tags.push('SharedArrayBuffer'); } } - const vivificate = instanceDescriptors[VIVIFICATOR$8]?.value; - const vivificateDescriptor = { - // vivificate child objects as read-only too - value: function(slot) { - return vivificate.call(this, slot, false); - } - }; - const { get, set } = instanceDescriptors.$; - defineProperties$8(constructor.prototype, { - [CONST$8]: { value: false }, - [ALL_KEYS$8]: { value: Object.keys(propSetters) }, - [SETTER$8]: { value: set }, - [GETTER$8]: { value: get }, - [PROP_SETTERS$8]: { value: propSetters }, - ...instanceDescriptors, - }); - defineProperties$8(constructor, { - [CONST_PROTOTYPE$8]: { value: prototypeRO }, - ...staticDescriptors, - }); - defineProperties$8(prototypeRO, { - constructor: { value: constructor, configurable: true }, - [CONST$8]: { value: true }, - [SETTER$8]: { value: throwReadOnly$8 }, - [VIVIFICATOR$8]: vivificate && vivificateDescriptor, - ...instanceDescriptorsRO, - }); - return constructor; + return tags; } -function createConstructor$8(structure, handlers, env) { - const { - byteSize, - align, - instance: { members, template }, - hasPointer, - } = structure; - const { - modifier, - initializer, - finalizer, - alternateCaster, - shapeDefiner, - } = handlers; - const hasSlots = needSlots$8(members); - // comptime fields are stored in the instance template's slots - let comptimeFieldSlots; - if (template?.[SLOTS$8]) { - const comptimeMembers = members.filter(m => isReadOnly$8(m.type)); - if (comptimeMembers.length > 0) { - comptimeFieldSlots = comptimeMembers.map(m => m.slot); - } +function isBuffer$9(arg, typedArray) { + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView' || tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + return true; + } else if (typedArray && tag === typedArray.name) { + return true; + } else { + return false; + } +} + +function getTypeName$9(member) { + const { type, bitSize, byteSize } = member; + if (type === MemberType$9.Int) { + return `${bitSize <= 32 ? '' : 'Big' }Int${bitSize}`; + } else if (type === MemberType$9.Uint) { + return `${bitSize <= 32 ? '' : 'Big' }Uint${bitSize}`; + } else if (type === MemberType$9.Float) { + return `Float${bitSize}`; + } else if (type === MemberType$9.Bool) { + const boolSize = (byteSize !== undefined) ? byteSize * 8 : 1; + return `Bool${boolSize}`; + } else if (type === MemberType$9.Void) { + return `Null`; } - const cache = new ObjectCache$8(); - const constructor = function(arg, options = {}) { - const { - writable = true, - fixed = false, - } = options; - const creating = this instanceof constructor; - let self, dv; - if (creating) { - if (arguments.length === 0) { - throwNoInitializer$8(structure); - } - self = this; - if (hasSlots) { - self[SLOTS$8] = {}; - } - if (shapeDefiner) { - // provided by defineSlice(); the slice is different from other structures as it does not have - // a fixed size; memory is allocated by the slice initializer based on the argument given - initializer.call(self, arg, fixed); - dv = self[MEMORY$8]; +} + +function getBigIntDescriptor$9(bitSize) { + const getWord = DataView.prototype.getBigUint64; + const setWord = DataView.prototype.setBigUint64; + const wordCount = Math.ceil(bitSize / 64); + return { + get: function(offset, littleEndian) { + let n = 0n; + if (littleEndian) { + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; + } } else { - self[MEMORY$8] = dv = env.allocateMemory(byteSize, align, fixed); - } - } else { - if (alternateCaster) { - // casting from number, string, etc. - self = alternateCaster.call(this, arg, options); - if (self !== false) { - return self; + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; } } - // look for buffer - dv = requireDataView$8(structure, arg, env); - if (self = cache.find(dv, writable)) { - return self; - } - self = Object.create(writable ? constructor.prototype : constructor[CONST_PROTOTYPE$8]); - if (shapeDefiner) { - setDataView$8.call(self, dv, structure, false, { shapeDefiner }); + return n; + }, + set: function(offset, value, littleEndian) { + let n = value; + const mask = 0xFFFFFFFFFFFFFFFFn; + if (littleEndian) { + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } } else { - self[MEMORY$8] = dv; - } - if (hasSlots) { - self[SLOTS$8] = {}; - if (hasPointer && arg instanceof constructor) { - // copy pointer from other object - self[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); - } + n <<= BigInt(wordCount * 64 - bitSize); + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } } + return n; + }, + }; +} + +function getAlignedIntAccessor$9(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$9({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const signMask = (bitSize <= 32) ? 2 ** (bitSize - 1) : 2n ** BigInt(bitSize - 1); + const valueMask = (bitSize <= 32) ? signMask - 1 : signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; } - if (comptimeFieldSlots) { - for (const slot of comptimeFieldSlots) { - self[SLOTS$8][slot] = template[SLOTS$8][slot]; - } + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$9(bitSize); + const signMask = 2n ** BigInt(bitSize - 1); + const valueMask = signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; } - if (modifier) { - modifier.call(self); + } +} + +function getAlignedUintAccessor$9(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$9({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const valueMask = (bitSize <= 32) ? (2 ** bitSize) - 1 : (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; } - if (creating) { - // initialize object unless it's been done already - if (!shapeDefiner) { - initializer.call(self, arg); - } - if (!writable) { - // create object with read-only prototype - self = Object.assign(Object.create(constructor[CONST_PROTOTYPE$8]), self); - } + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$9(bitSize); + const valueMask = (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; } - if (finalizer) { - self = finalizer.call(self); + } +} + +function getUnalignedIntAccessor$9(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + // sub-8-bit numbers have real use cases + const signMask = 2 ** (bitSize - 1); + const valueMask = signMask - 1; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return (s & valueMask) - (s & signMask); + }; + } else { + const outsideMask = 0xFF ^ ((valueMask | signMask) << bitPos); + return function(offset, value) { + let b = get.call(this, offset); + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + b = (b & outsideMask) | (n << bitPos); + set.call(this, offset, b); + }; } - return cache.save(dv, writable, self); - }; - return constructor; + } + return getUnalignedNumericAccessor$9(access, member); } -function createPropertyApplier$8(structure) { - const { instance: { template } } = structure; - return function(arg) { - const argKeys = Object.keys(arg); - const propSetters = this[PROP_SETTERS$8]; - const allKeys = this[ALL_KEYS$8]; - // don't accept unknown props - for (const key of argKeys) { - if (!(key in propSetters)) { - throwNoProperty$8(structure, key); +function getUnalignedUintAccessor$9(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + const valueMask = (2 ** bitSize - 1); + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return s & valueMask; + }; + } else { + const outsideMask = 0xFF ^ (valueMask << bitPos); + return function(offset, value) { + const n = get.call(this, offset); + const b = (n & outsideMask) | ((value & valueMask) << bitPos); + set.call(this, offset, b); + }; + } + } + return getUnalignedNumericAccessor$9(access, member); +} + +function getAlignedFloatAccessor$9(access, member) { + const { bitSize, byteSize } = member; + if (bitSize === 16) { + const buf = new DataView(new ArrayBuffer(4)); + const set = DataView.prototype.setUint16; + const get = DataView.prototype.getUint16; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >>> 15; + const exp = (n & 0x7C00) >> 10; + const frac = n & 0x03FF; + if (exp === 0) { + return (sign) ? -0 : 0; + } else if (exp === 0x1F) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } + } + const n32 = (sign << 31) | ((exp - 15 + 127) << 23) | (frac << 13); + buf.setUint32(0, n32, littleEndian); + return buf.getFloat32(0, littleEndian); + } + } else { + return function(offset, value, littleEndian) { + buf.setFloat32(0, value, littleEndian); + const n = buf.getUint32(0, littleEndian); + const sign = n >>> 31; + const exp = (n & 0x7F800000) >> 23; + const frac = n & 0x007FFFFF; + const exp16 = (exp - 127 + 15); + let n16; + if (exp === 0) { + n16 = sign << 15; + } else if (exp === 0xFF) { + n16 = sign << 15 | 0x1F << 10 | (frac ? 1 : 0); + } else if (exp16 >= 31) { + n16 = sign << 15 | 0x1F << 10; + } else { + n16 = sign << 15 | exp16 << 10 | (frac >> 13); + } + set.call(this, offset, n16, littleEndian); } } - // checking each name so that we would see inenumerable initializers as well - let normalCount = 0; - let normalFound = 0; - let normalMissing = 0; - let specialFound = 0; - for (const key of allKeys) { - const set = propSetters[key]; - if (set.special) { - if (key in arg) { - specialFound++; + } else if (bitSize === 80) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + return w1 | w2 << 32n | w3 << 64n; + }; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 79n; + const exp = (n & 0x7FFF0000000000000000n) >> 64n; + const frac = n & 0x00007FFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } } - } else { - normalCount++; - if (key in arg) { - normalFound++; - } else if (set.required) { - normalMissing++; + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; + } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 11n) + BigInt((frac & (2n**11n - 1n)) >= 2n**10n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); + } + } else { + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n80; + if (exp === 0n) { + n80 = sign << 79n | (frac << 11n); + } else if (exp === 0x07FFn) { + n80 = sign << 79n | 0x7FFFn << 64n | (frac ? 0x00002000000000000000n : 0n) | 0x00008000000000000000n; + // ^ bit 61 ^ bit 63 + } else { + n80 = sign << 79n | (exp - 1023n + 16383n) << 64n | (frac << 11n) | 0x00008000000000000000n; } + set.call(this, offset, n80, littleEndian); } } - if (normalMissing !== 0 && specialFound === 0) { - const missing = allKeys.filter(k => propSetters[k].required && !(k in arg)); - throwMissingInitializers$8(structure, missing); - } - if (specialFound + normalFound > argKeys.length) { - // some props aren't enumerable - for (const key of allKeys) { - if (key in arg) { - if (!argKeys.includes(key)) { - argKeys.push(key); + } else if (bitSize === 128) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + const w4 = BigInt(this.getUint32(offset + (littleEndian ? 12 : byteSize - 16), littleEndian)); + return w1 | w2 << 32n | w3 << 64n | w4 << 96n; + }; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + const w4 = (value >> 96n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + this.setUint32(offset + (littleEndian ? 12 : byteSize - 16), Number(w4), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 127n; + const exp = (n & 0x7FFF0000000000000000000000000000n) >> 112n; + const frac = n & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; } } + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; + } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 60n) + BigInt((frac & (2n**60n - 1n)) >= 2n**59n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); } - } - // apply default values unless all properties are initialized - if (normalFound < normalCount && specialFound === 0) { - if (template) { - if (template[MEMORY$8]) { - this[COPIER$8](template); + } else { + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n128; + if (exp === 0n) { + n128 = sign << 127n | (frac << 60n); + } else if (exp === 0x07FFn) { + n128 = sign << 127n | 0x7FFFn << 112n | (frac ? 1n : 0n); + } else { + n128 = sign << 127n | (exp - 1023n + 16383n) << 112n | (frac << 60n); } - this[POINTER_VISITOR$8]?.(copyPointer$8, { vivificate: true, source: template }); + set.call(this, offset, n128, littleEndian); } } - for (const key of argKeys) { - const set = propSetters[key]; - set.call(this, arg[key]); - } - return argKeys.length; - }; + } } -function needSlots$8(members) { - for (const { type } of members) { - switch (type) { - case MemberType$8.Object: - case MemberType$8.Comptime: - case MemberType$8.Type: - case MemberType$8.Literal: - return true; - } - } - return false; +function getUnalignedFloatAccessor$9(access, member) { + return getUnalignedNumericAccessor$9(access, member); } -function getSelf$8() { - return this; +function getUnalignedNumericAccessor$9(access, member) { + // pathological usage scenario--handle it anyway by copying the bitSize into a + // temporary buffer, bit-aligning the data + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + const byteSize = [ 1, 2, 4, 8 ].find(b => b * 8 >= bitSize) ?? Math.ceil(bitSize / 64) * 64; + const buf = new DataView(new ArrayBuffer(byteSize)); + if (access === 'get') { + const getAligned = getNumericAccessor$9('get', { ...member, byteSize }); + const copyBits = getBitAlignFunction$9(bitPos, bitSize, true); + return function(offset, littleEndian) { + copyBits(buf, this, offset); + return getAligned.call(buf, 0, littleEndian); + }; + } else { + const setAligned = getNumericAccessor$9('set', { ...member, byteSize }); + const applyBits = getBitAlignFunction$9(bitPos, bitSize, false); + return function(offset, value, littleEndian) { + setAligned.call(buf, 0, value, littleEndian); + applyBits(this, buf, offset); + }; + } } -function findAllObjects(structures, SLOTS) { - const list = []; - const found = new Map(); - const find = (object) => { - if (!object || found.get(object)) { - return; +const methodCache$9 = {}; + +function cacheMethod$9(access, member, cb) { + const { type, bitOffset, bitSize, structure } = member; + const bitPos = bitOffset & 0x07; + const typeName = getTypeName$9(member); + const suffix = isByteAligned$9(member) ? `` : `Bit${bitPos}`; + const isInt = type === MemberType$9.Int || type === MemberType$9.Uint; + let name = `${access}${typeName}${suffix}`; + let isSize = false, originalName = name; + if (isInt && bitSize === 64) { + const zigTypeName = structure?.name; + if (zigTypeName === 'usize' || zigTypeName === 'isize') { + name += 'Size'; + isSize = true; } - found.set(object, true); - list.push(object); - if (object[SLOTS]) { - for (const child of Object.values(object[SLOTS])) { - find(child); - } + } + let fn = methodCache$9[name]; + if (!fn) { + if (isInt && access === 'set') { + // add auto-conversion between number and bigint + const Primitive = getPrimitiveClass$9(member); + const set = cb(originalName); + fn = function(offset, value, littleEndian) { + set.call(this, offset, Primitive(value), littleEndian); + }; + } else if (isSize && access === 'get') { + // use number instead of bigint where possible + const get = cb(originalName); + const min = BigInt(Number.MIN_SAFE_INTEGER); + const max = BigInt(Number.MAX_SAFE_INTEGER); + fn = function(offset, littleEndian) { + const value = get.call(this, offset, littleEndian); + if (min <= value && value <= max) { + return Number(value); + } else { + return value; + } + }; + } else { + fn = cb(name); } - }; - for (const structure of structures) { - find(structure.instance.template); - find(structure.static.template); + if (fn && fn.name !== name) { + Object.defineProperty(fn, 'name', { value: name, configurable: true, writable: false }); + } + methodCache$9[name] = fn; + } + return fn; +} + +function useAllExtendedTypes$9() { + useExtendedBool$9(); + useExtendedInt$9(); + useExtendedUint$9(); + useExtendedFloat$9(); +} + +const MemberType$9 = { + Void: 0, + Bool: 1, + Int: 2, + Uint: 3, + Float: 4, + Object: 5, + Type: 6, + Comptime: 7, + Static: 8, + Literal: 9, + Null: 10, + Undefined: 11, +}; + +function isReadOnly$9(type) { + switch (type) { + case MemberType$9.Type: + case MemberType$9.Comptime: + case MemberType$9.Literal: + return true; + default: + return false; } - return list; } -function useAllStructureTypes$8() { - usePrimitive$8(); - useArray$8(); - useStruct$8(); - useExternStruct$8(); - usePackedStruct$8(); - useArgStruct$8(); - useExternUnion$8(); - useBareUnion$8(); - useTaggedUnion$8(); - useErrorUnion$8(); - useErrorSet$8(); - useEnumeration$8(); - useOptional$8(); - usePointer$8(); - useSlice$8(); - useVector$8(); - useOpaque$8(); +const factories$r = {}; + +function useVoid$9() { + factories$r[MemberType$9.Void] = getVoidDescriptor$9; } -let ObjectCache$8 = class ObjectCache { - [0] = null; - [1] = null; +function useBool$9() { + factories$r[MemberType$9.Bool] = getBoolDescriptor$9; +} - find(dv, writable) { - const key = (writable) ? 0 : 1; - const map = this[key]; - return map?.get(dv); - } +function useInt$9() { + factories$r[MemberType$9.Int] = getIntDescriptor$9; +} - save(dv, writable, object) { - const key = (writable) ? 0 : 1; - let map = this[key]; - if (!map) { - map = this[key] = new WeakMap(); - } - map.set(dv, object); - return object; - } -}; +function useUint$9() { + factories$r[MemberType$9.Uint] = getUintDescriptor$9; +} -function definePrimitive$8(structure, env) { - const { - byteSize, - align, - instance: { members: [ member ] }, - } = structure; - const { get, set } = getDescriptor$8(member, env); - const propApplier = createPropertyApplier$8(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$8](arg); - } else { - if (arg && typeof(arg) === 'object') { - if (propApplier.call(this, arg) === 0) { - const type = getPrimitiveType$8(member); - throwInvalidInitializer$8(structure, type, arg); - } - } else if (arg !== undefined) { - set.call(this, arg); - } - } - }; - const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); - const typedArray = structure.typedArray = getTypedArrayClass$8(member); - const instanceDescriptors = { - $: { get, set }, - dataView: getDataViewDescriptor$8(structure), - base64: getBase64Descriptor$8(structure), - typedArray: typedArray && getTypedArrayDescriptor$8(structure), - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - delete: { value: getDestructor$8(env) }, - [Symbol.toPrimitive]: { value: get }, - [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, - [NORMALIZER$8]: { value: normalizeValue$8 }, - }; - const staticDescriptors = { - [COMPAT$8]: { value: getCompatibleTags$8(structure) }, - [ALIGN$8]: { value: align }, - [SIZE$8]: { value: byteSize }, - }; - return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +function useFloat$9() { + factories$r[MemberType$9.Float] = getFloatDescriptor$9; } -function getIntRange$8(member) { - const { type, bitSize } = member; - const signed = (type === MemberType$8.Int); - let magBits = (signed) ? bitSize - 1 : bitSize; - if (bitSize <= 32) { - const max = 2 ** magBits - 1; - const min = (signed) ? -(2 ** magBits) : 0; - return { min, max }; - } else { - magBits = BigInt(magBits); - const max = 2n ** magBits - 1n; - const min = (signed) ? -(2n ** magBits) : 0n; - return { min, max }; - } + +function useObject$9() { + factories$r[MemberType$9.Object] = getObjectDescriptor$9; } -function getPrimitiveClass$8({ type, bitSize }) { - if (type === MemberType$8.Int || type === MemberType$8.Uint) { - if (bitSize <= 32) { - return Number; - } else { - return BigInt; - } - } else if (type === MemberType$8.Float) { - return Number; - } else if (type === MemberType$8.Bool) { - return Boolean; - } +function useType$9() { + factories$r[MemberType$9.Type] = getTypeDescriptor$9; } -function getPrimitiveType$8(member) { - const Primitive = getPrimitiveClass$8(member); - if (Primitive) { - return typeof(Primitive(0)); - } +function useComptime$9() { + factories$r[MemberType$9.Comptime] = getComptimeDescriptor$9; } -function throwNoInitializer$8(structure) { - const { name } = structure; - throw new TypeError(`An initializer must be provided to the constructor of ${name}, even when the intended value is undefined`); +function useStatic$9() { + factories$r[MemberType$9.Static] = getStaticDescriptor$9; } -function throwBufferSizeMismatch$8(structure, dv, target = null) { - const { name, type, byteSize } = structure; - const actual = dv.byteLength; - const s = (byteSize !== 1) ? 's' : ''; - if (type === StructureType$8.Slice && !target) { - throw new TypeError(`${name} has elements that are ${byteSize} byte${s} in length, received ${actual}`); - } else { - const total = (type === StructureType$8.Slice) ? target.length * byteSize : byteSize; - throw new TypeError(`${name} has ${total} byte${s}, received ${actual}`); - } +function useLiteral$9() { + factories$r[MemberType$9.Literal] = getLiteralDescriptor$9; } -function throwBufferExpected$8(structure) { - const { type, byteSize, typedArray } = structure; - const s = (byteSize !== 1) ? 's' : ''; - const acceptable = [ 'ArrayBuffer', 'DataView' ].map(addArticle$8); - if (typedArray) { - acceptable.push(addArticle$8(typedArray.name)); - } - if (type === StructureType$8.Slice) { - throw new TypeError(`Expecting ${formatList$8(acceptable)} that can accommodate items ${byteSize} byte${s} in length`); - } else { - throw new TypeError(`Expecting ${formatList$8(acceptable)} that is ${byteSize} byte${s} in length`); - } +function useNull$9() { + factories$r[MemberType$9.Null] = getNullDescriptor$9; } -function throwEnumExpected$8(structure, arg) { - const { name } = structure; - if (typeof(arg) === 'number' || typeof(arg) === 'bigint') { - throw new TypeError(`Value given does not correspond to an item of enum ${name}: ${arg}`); - } else { - throw new TypeError(`Enum item of the type ${name} expected, received ${arg}`); - } +function useUndefined$9() { + factories$r[MemberType$9.Undefined] = getUndefinedDescriptor$9; } -function throwErrorExpected$8(structure, arg) { - const { name } = structure; - const type = typeof(arg); - if (type === 'string' || type === 'number') { - throw new TypeError(`Error ${type} does not corresponds to any error in error set ${name}: ${arg}`); - } else { - throw new TypeError(`Error of the type ${name} expected, received ${arg}`); - } +const transformers$1 = {}; + +function useEnumerationTransform$1() { + transformers$1[StructureType$9.Enumeration] = transformEnumerationDescriptor$1; } -function throwNotInErrorSet$8(structure) { - const { name } = structure; - throw new TypeError(`Error given is not a part of error set ${name}`); +function useErrorSetTransform$1() { + transformers$1[StructureType$9.ErrorSet] = transformErrorSetDescriptor$1; } -function throwMultipleUnionInitializers$8(structure) { - const { name } = structure; - throw new TypeError(`Only one property of ${name} can be given a value`); +function isByteAligned$9({ bitOffset, bitSize, byteSize }) { + return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; } -function throwInactiveUnionProperty$8(structure, name, currentName) { - throw new TypeError(`Accessing property ${name} when ${currentName} is active`); +function getDescriptor$9(member, env) { + const f = factories$r[member.type]; + return f(member, env); } -function throwMissingUnionInitializer$8(structure, arg, exclusion) { - const { name, instance: { members } } = structure; - const missing = members.slice(0, exclusion ? -1 : undefined).map(m => m.name); - throw new TypeError(`${name} needs an initializer for one of its union properties: ${missing.join(', ')}`); +function transformDescriptor$1(descriptor, member) { + const { structure } = member; + const t = transformers$1[structure?.type]; + return (t) ? t(descriptor, structure) : descriptor; } -function throwInvalidInitializer$8(structure, expected, arg) { - const { name } = structure; - const acceptable = []; - if (Array.isArray(expected)) { - for (const type of expected) { - acceptable.push(addArticle$8(type)); - } - } else { - acceptable.push(addArticle$8(expected)); +function getVoidDescriptor$9(member, env) { + const { runtimeSafety } = env; + return { + get: function() { + return undefined; + }, + set: (runtimeSafety) + ? function(value) { + if (value !== undefined) { + throwNotUndefined$9(member); + } + } + : function() {}, } - const received = getDescription$8(arg); - throw new TypeError(`${name} expects ${formatList$8(acceptable)} as argument, received ${received}`); } -function throwInvalidArrayInitializer$8(structure, arg, shapeless = false) { - const { instance: { members: [ member ] }, type, typedArray } = structure; - const acceptable = []; - const primitive = getPrimitiveType$8(member); - if (primitive) { - acceptable.push(`array of ${primitive}s`); - } else if (member.type === MemberType$8.EnumerationItem) { - acceptable.push(`array of enum items`); - } else { - acceptable.push(`array of objects`); - } - if (typedArray) { - acceptable.push(typedArray.name); - } - if (type === StructureType$8.Slice && shapeless) { - acceptable.push(`length`); +function getNullDescriptor$9(member, env) { + return { + get: function() { + return null; + }, } - throwInvalidInitializer$8(structure, acceptable.join(' or '), arg); } -function throwArrayLengthMismatch$8(structure, target, arg) { - const { name, length, instance: { members: [ member ] } } = structure; - const { structure: { constructor: elementConstructor} } = member; - const { length: argLength, constructor: argConstructor } = arg; - // get length from object whech it's a slice - const actualLength = target?.length ?? length; - const s = (actualLength !== 1) ? 's' : ''; - let received; - if (argConstructor === elementConstructor) { - received = `only a single one`; - } else if (argConstructor.child === elementConstructor) { - received = `a slice/array that has ${argLength}`; - } else { - received = `${argLength} initializer${argLength > 1 ? 's' : ''}`; +function getUndefinedDescriptor$9(member, env) { + return { + get: function() { + return undefined; + }, } - throw new TypeError(`${name} has ${actualLength} element${s}, received ${received}`); } -function throwMissingInitializers$8(structure, missing) { - const { name } = structure; - throw new TypeError(`Missing initializers for ${name}: ${missing.join(', ')}`); +function getBoolDescriptor$9(member, env) { + return getDescriptorUsing$9(member, env, getBoolAccessor$9) +} + +function getIntDescriptor$9(member, env) { + const getDataViewAccessor = addRuntimeCheck$9(env, getNumericAccessor$9); + const descriptor = getDescriptorUsing$9(member, env, getDataViewAccessor); + return transformDescriptor$1(descriptor, member); +} + +function getUintDescriptor$9(member, env) { + const getDataViewAccessor = addRuntimeCheck$9(env, getNumericAccessor$9); + const descriptor = getDescriptorUsing$9(member, env, getDataViewAccessor); + return transformDescriptor$1(descriptor, member); +} + +function addRuntimeCheck$9(env, getDataViewAccessor) { + return function (access, member) { + const { + runtimeSafety = true, + } = env; + const accessor = getDataViewAccessor(access, member); + if (runtimeSafety && access === 'set') { + const { min, max } = getIntRange$9(member); + return function(offset, value, littleEndian) { + if (value < min || value > max) { + throwOverflow$9(member, value); + } + accessor.call(this, offset, value, littleEndian); + }; + } + return accessor; + }; +} + +function getFloatDescriptor$9(member, env) { + return getDescriptorUsing$9(member, env, getNumericAccessor$9) } -function throwNoProperty$8(structure, propName) { - const { name, instance: { members } } = structure; - const member = members.find(m => m.name === propName); - if (member) { - throw new TypeError(`Comptime value cannot be changed: ${propName}`); - } else { - throw new TypeError(`${name} does not have a property with that name: ${propName}`); - } +function transformEnumerationDescriptor$1(int, structure) { + const findEnum = function(value) { + const { constructor } = structure; + // the enumeration constructor returns the object for the int value + const item = constructor(value); + if (!item) { + throwEnumExpected$9(structure, value); + } + return item + }; + return { + get: (int.get.length === 0) + ? function getEnum(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } + return findEnum(value); + } + : function getEnumElement(index) { + const value = int.get.call(this, index); + return findEnum(value); + }, + set: (int.set.length === 1) + ? function setEnum(value, hint) { + if (hint !== 'number') { + const item = findEnum(value); + // call Symbol.toPrimitive directly as enum can be bigint or number + value = item[Symbol.toPrimitive](); + } + int.set.call(this, value); + } + : function setEnumElement(index, value) { + const item = findEnum(value); + int.set.call(this, index, item[Symbol.toPrimitive]()); + }, + }; } -function throwArgumentCountMismatch$8(structure, actual) { - const { name, instance: { members } } = structure; - const argCount = members.length - 1; - const s = (argCount !== 1) ? 's' : ''; - throw new Error(`${name} expects ${argCount} argument${s}, received ${actual}`); +function transformErrorSetDescriptor$1(int, structure) { + const findError = function(value) { + const { constructor } = structure; + const item = constructor(value); + if (!item) { + if (value instanceof Error) { + throwNotInErrorSet$9(structure); + } else { + throwErrorExpected$9(structure, value); + } + } + return item + }; + return { + get: (int.get.length === 0) + ? function getError(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } + return findError(value); + } + : function getErrorElement(index) { + const value = int.get.call(this, index); + return findError(value); + }, + set: (int.set.length === 1) + ? function setError(value, hint) { + if (hint !== 'number') { + const item = findError(value); + value = Number(item); + } + int.set.call(this, value); + } + : function setError(index, value) { + const item = findError(value); + value = Number(item); + int.set.call(this, index, value); + }, + }; } -function rethrowArgumentError$8(structure, index, err) { - const { name, instance: { members } } = structure; - // Zig currently does not provide the argument name - const argName = `args[${index}]`; - const argCount = members.length - 1; - const prefix = (index !== 0) ? '..., ' : ''; - const suffix = (index !== argCount - 1) ? ', ...' : ''; - const argLabel = prefix + argName + suffix; - const newError = new err.constructor(`${name}(${argLabel}): ${err.message}`); - newError.stack = err.stack; - throw newError; +function isValueExpected$9(structure) { + switch (structure.type) { + case StructureType$9.Primitive: + case StructureType$9.ErrorUnion: + case StructureType$9.Optional: + case StructureType$9.Enumeration: + case StructureType$9.ErrorSet: + return true; + default: + return false; + } } -function throwNoCastingToPointer$8(structure) { - throw new TypeError(`Non-slice pointers can only be created with the help of the new operator`); +function getValue$9(slot) { + const object = this[SLOTS$9][slot] ?? this[VIVIFICATOR$9](slot); + return object[GETTER$9](); } -function throwConstantConstraint$8(structure, pointer) { - const { name: target } = structure; - const { constructor: { name } } = pointer; - throw new TypeError(`Conversion of ${name} to ${target} requires an explicit cast`); +function getObject$9(slot) { + const object = this[SLOTS$9][slot] ?? this[VIVIFICATOR$9](slot); + return object; } -function throwMisplacedSentinel$8(structure, value, index, length) { - const { name } = structure; - throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}, found at ${index}`); +function setValue$9(slot, value) { + const object = this[SLOTS$9][slot] ?? this[VIVIFICATOR$9](slot); + object[SETTER$9](value); } -function throwMissingSentinel$8(structure, value, length) { - const { name } = structure; - throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}`); +function bindSlot$9(slot, { get, set }) { + if (slot !== undefined) { + return { + get: function() { + return get.call(this, slot); + }, + set: (set) + ? function(arg) { + return set.call(this, slot, arg); + } + : undefined, + }; + } else { + // array accessors + return { get, set }; + } } -function throwTypeMismatch$8(expected, arg) { - const received = getDescription$8(arg); - throw new TypeError(`Expected ${addArticle$8(expected)}, received ${received}`) +function getObjectDescriptor$9(member, env) { + const { structure, slot } = member; + return bindSlot$9(slot, { + get: isValueExpected$9(structure) ? getValue$9 : getObject$9, + set: setValue$9, + }); } -function throwInaccessiblePointer$8() { - throw new TypeError(`Pointers within an untagged union are not accessible`); +function getType$9(slot) { + // unsupported types will have undefined structure + const structure = this[SLOTS$9][slot]; + return structure?.constructor; } -function throwNullPointer$8() { - throw new TypeError(`Null pointer`); +function getTypeDescriptor$9(member, env) { + const { slot } = member; + return bindSlot$9(slot, { get: getType$9 }); } -function throwInvalidPointerTarget$8(structure, arg) { - const { name } = structure; - let target; - if (arg != null) { - const type = typeof(arg); - const noun = (type === 'object' && arg.constructor !== Object) ? `${arg.constructor.name} object`: type; - const a = article$8(noun); - target = `${a} ${noun}`; - } else { - target = arg + ''; - } - throw new TypeError(`${name} cannot point to ${target}`) +function getComptimeDescriptor$9(member, env) { + const { slot, structure } = member; + return bindSlot$9(slot, { + get: isValueExpected$9(structure) ? getValue$9 : getObject$9, + }); } -function throwFixedMemoryTargetRequired$8(structure, arg) { - throw new TypeError(`Pointers in fixed memory cannot point to garbage-collected object`); +function getStaticDescriptor$9(member, env) { + const { slot, structure } = member; + return bindSlot$9(slot, { + get: isValueExpected$9(structure) ? getValue$9 : getObject$9, + set: setValue$9, + }); } - -function throwOverflow$8(member, value) { - const typeName = getTypeName$8(member); - throw new TypeError(`${typeName} cannot represent the value given: ${value}`); +function getLiteral$9(slot) { + const object = this[SLOTS$9][slot]; + return object.string; } -function throwOutOfBound$8(member, index) { - const { name } = member; - throw new RangeError(`Index exceeds the size of ${name ?? 'array'}: ${index}`); +function getLiteralDescriptor$9(member, env) { + const { slot } = member; + return bindSlot$9(slot, { get: getLiteral$9 }); } -function rethrowRangeError$8(member, index, err) { - if (err instanceof RangeError) { - throwOutOfBound$8(member, index); +function getDescriptorUsing$9(member, env, getDataViewAccessor) { + const { + littleEndian = true, + } = env; + const { bitOffset, byteSize } = member; + const getter = getDataViewAccessor('get', member); + const setter = getDataViewAccessor('set', member); + if (bitOffset !== undefined) { + const offset = bitOffset >> 3; + return { + get: function getValue() { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return getter.call(this[MEMORY$9], offset, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$9.call(this)) { + return getter.call(this[MEMORY$9], offset, littleEndian); + } else { + throw err; + } + } + /* WASM-ONLY-END*/ + }, + set: function setValue(value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return setter.call(this[MEMORY$9], offset, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$9.call(this)) { + return setter.call(this[MEMORY$9], offset, value, littleEndian); + } else { + throw err; + } + } + /* WASM-ONLY-END*/ + } + } } else { - throw err; + return { + get: function getElement(index) { + try { + return getter.call(this[MEMORY$9], index * byteSize, littleEndian); + } catch (err) { + /* WASM-ONLY */ + if (err instanceof TypeError && restoreMemory$9.call(this)) { + return getter.call(this[MEMORY$9], index * byteSize, littleEndian); + } else { + /* WASM-ONLY-END */ + rethrowRangeError$9(member, index, err); + /* WASM-ONLY */ + } + /* WASM-ONLY-END */ + } + }, + set: function setElement(index, value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END */ + return setter.call(this[MEMORY$9], index * byteSize, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$9.call(this)) { + return setter.call(this[MEMORY$9], index * byteSize, value, littleEndian); + } else { + rethrowRangeError$9(member, index, err); + } + } + /* WASM-ONLY-END */ + }, + } } } -function throwNotUndefined$8(member) { - const { name } = member; - throw new RangeError(`Property ${name} can only be undefined`); +function useAllMemberTypes$9() { + useVoid$9(); + useNull$9(); + useUndefined$9(); + useBool$9(); + useInt$9(); + useUint$9(); + useFloat$9(); + useObject$9(); + useType$9(); + useComptime$9(); + useStatic$9(); + useLiteral$9(); } -function throwNotOnByteBoundary$8(member) { - const { name, structure: { name: { struct }} } = member; - throw new TypeError(`Unable to create ${struct} as it is not situated on a byte boundary: ${name}`); -} +process.cwd(); -function throwReadOnly$8() { - throw new TypeError(`Unable to modify read-only object`); +useAllMemberTypes$9(); +useAllStructureTypes$9(); +useAllExtendedTypes$9(); + +const MEMORY$8 = Symbol('memory'); +const SLOTS$8 = Symbol('slots'); +const PARENT$8 = Symbol('parent'); +const NAME$8 = Symbol('name'); +const CLASS = Symbol('class'); +const TAG$8 = Symbol('tag'); +const PROPS$8 = Symbol('props'); +const GETTER$8 = Symbol('getter'); +const SETTER$8 = Symbol('setter'); +const ELEMENT_GETTER$8 = Symbol('elementGetter'); +const ELEMENT_SETTER$8 = Symbol('elementSetter'); +const LOCATION_GETTER$8 = Symbol('addressGetter'); +const LOCATION_SETTER$8 = Symbol('addressSetter'); +const TARGET_GETTER$8 = Symbol('targetGetter'); +const TARGET_SETTER$8 = Symbol('targetSetter'); +const FIXED_LOCATION$8 = Symbol('fixedLocation'); +const PROP_GETTERS$8 = Symbol('propGetters'); +const PROP_SETTERS$8 = Symbol('propSetters'); +const ALL_KEYS$8 = Symbol('allKeys'); +const LENGTH$8 = Symbol('length'); +const PROXY$8 = Symbol('proxy'); +const COMPAT$8 = Symbol('compat'); +const SIZE$8 = Symbol('size'); +const ALIGN$8 = Symbol('align'); +const ARRAY$8 = Symbol('array'); +const POINTER$8 = Symbol('pointer'); +const CONST$8 = Symbol('const'); +const CONST_PROTOTYPE$8 = Symbol('constProto'); +const COPIER$8 = Symbol('copier'); +const RESETTER$8 = Symbol('resetter'); +const NORMALIZER$8 = Symbol('normalizer'); +const VIVIFICATOR$8 = Symbol('vivificator'); +const POINTER_VISITOR$8 = Symbol('pointerVisitor'); +const ENVIRONMENT$8 = Symbol('environment'); +const MORE$8 = Symbol('more'); + +function getDestructor$8(env) { + return function() { + const dv = this[MEMORY$8]; + this[MEMORY$8] = null; + if (this[SLOTS$8]) { + this[SLOTS$8] = {}; + } + env.releaseFixedView(dv); + }; } -function throwReadOnlyTarget$8(structure) { - const { name } = structure; - throw new TypeError(`${name} cannot point to a read-only object`); +function getBitAlignFunction$8(bitPos, bitSize, toAligned) { + if (bitPos + bitSize <= 8) { + const mask = (2 ** bitSize) - 1; + if (toAligned) { + // from single byte + return function(dest, src, offset) { + const n = src.getUint8(offset); + const b = (n >> bitPos) & mask; + dest.setUint8(0, b); + }; + } else { + // to single byte + const destMask = 0xFF ^ (mask << bitPos); + return function(dest, src, offset) { + const n = src.getUint8(0); + const d = dest.getUint8(offset); + const b = (d & destMask) | ((n & mask) << bitPos); + dest.setUint8(offset, b); + }; + } + } else { + const leadBits = 8 - bitPos; + const leadMask = (2 ** leadBits) - 1; + if (toAligned) { + const trailBits = bitSize % 8; + const trailMask = (2 ** trailBits) - 1; + return function(dest, src, offset) { + let i = offset, j = 0; + let n = src.getUint8(i++), b; + let bitBuf = (n >> bitPos) & leadMask; + let bitCount = leadBits; + let remaining = bitSize; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + //bitCount += 8; + } + b = (remaining >= 8) ? bitBuf & 0xFF : bitBuf & trailMask; + dest.setUint8(j++, b); + bitBuf >>= 8; + //bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } else { + const trailBits = (bitSize - leadBits) % 8; + const trailMask = (2 ** trailBits) - 1; + const destMask1 = 0xFF ^ (leadMask << bitPos); + const destMask2 = 0xFF ^ trailMask; + return function(dest, src, offset) { + let i = 0, j = offset; + // preserve bits ahead of bitPos + let d = dest.getUint8(j), n, b; + let bitBuf = d & destMask1; + let bitCount = bitPos; + let remaining = bitSize + bitCount; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + bitCount += 8; + } + if (remaining >= 8) { + b = bitBuf & 0xFF; + } else { + // preserve bits at the destination sitting behind the trailing bits + d = dest.getUint8(j); + b = (d & destMask2) | (bitBuf & trailMask); + } + dest.setUint8(j++, b); + bitBuf >>= 8; + bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } + } } -function throwAccessingOpaque$8(structure) { - const { name } = structure; - throw new TypeError(`Unable to access opaque structure ${name}`); +function getMemoryCopier$8(size, multiple = false) { + const copy = getCopyFunction$8(size, multiple); + return function(target) { + /* WASM-ONLY */ + restoreMemory$8.call(this); + restoreMemory$8.call(target); + /* WASM-ONLY-END */ + const src = target[MEMORY$8]; + const dest = this[MEMORY$8]; + copy(dest, src); + }; } -function throwCreatingOpaque$8(structure) { - const { name } = structure; - throw new TypeError(`Unable to create instance of ${name}, as it is opaque`); +function getCopyFunction$8(size, multiple = false) { + if (!multiple) { + const copier = copiers$8[size]; + if (copier) { + return copier; + } + } + if (!(size & 0x07)) return copy8x$8; + if (!(size & 0x03)) return copy4x$8; + if (!(size & 0x01)) return copy2x$8; + return copy1x$8; } -function throwZigError(name) { - throw new Error(deanimalizeErrorName(name)); -} +const copiers$8 = { + 1: copy1$8, + 2: copy2$8, + 4: copy4$8, + 8: copy8$8, + 16: copy16$8, + 32: copy32$8, +}; -function warnImplicitArrayCreation$8(structure, arg) { - const created = addArticle$8(structure.typedArray.name); - const source = addArticle$8(arg.constructor.name); - console.warn(`Implicitly creating ${created} from ${source}`); +function copy1x$8(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i++) { + dest.setInt8(i, src.getInt8(i)); + } } -function deanimalizeErrorName(name) { - // deal with snake_case first - let s = name.replace(/_/g, ' '); - // then camelCase, using a try block in case Unicode regex fails - try { - s = s.replace(/(\p{Uppercase}+)(\p{Lowercase}*)/gu, (m0, m1, m2) => { - if (m1.length === 1) { - return ` ${m1.toLocaleLowerCase()}${m2}`; - } else { - if (m2) { - const acronym = m1.substring(0, m1.length - 1); - const letter = m1.charAt(m1.length - 1).toLocaleLowerCase(); - return ` ${acronym} ${letter}${m2}`; - } else { - return ` ${m1}`; - } - } - }).trimStart(); - /* c8 ignore next 2 */ - } catch (err) { +function copy2x$8(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 2) { + dest.setInt16(i, src.getInt16(i, true), true); } - return s.charAt(0).toLocaleUpperCase() + s.substring(1); } -function getDescription$8(arg) { - const type = typeof(arg); - let s; - if (type === 'object') { - s = (arg) ? Object.prototype.toString.call(arg) : 'null'; - } else { - s = type; +function copy4x$8(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 4) { + dest.setInt32(i, src.getInt32(i, true), true); } - return addArticle$8(s); } -function addArticle$8(noun) { - return `${article$8(noun)} ${noun}`; +function copy8x$8(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 8) { + dest.setInt32(i, src.getInt32(i, true), true); + dest.setInt32(i + 4, src.getInt32(i + 4, true), true); + } } -function article$8(noun) { - return /^\W*[aeiou]/i.test(noun) ? 'an' : 'a'; +function copy1$8(dest, src) { + dest.setInt8(0, src.getInt8(0)); } -function formatList$8(list, conj = 'or') { - const sep = ` ${conj} `; - if (list.length > 2) { - return list.slice(0, -1).join(', ') + sep + list[list.length - 1]; - } else { - return list.join(sep); - } +function copy2$8(dest, src) { + dest.setInt16(0, src.getInt16(0, true), true); } -function getBoolAccessor$8(access, member) { - return cacheMethod$8(access, member, () => { - if (isByteAligned$8(member)) { - const { byteSize } = member; - const typeName = getTypeName$8({ type: MemberType$8.Int, bitSize: byteSize * 8 }); - if (access === 'get') { - const get = DataView.prototype[`get${typeName}`]; - return function(offset, littleEndian) { - return !!get.call(this, offset, littleEndian); - }; - } else { - const set = DataView.prototype[`set${typeName}`]; - const T = (byteSize > 4) ? 1n : 1; - const F = (byteSize > 4) ? 0n : 0; - return function(offset, value, littleEndian) { - set.call(this, offset, value ? T : F, littleEndian); - }; - } - } else { - return getExtendedTypeAccessor$8(access, member); - } - }); +function copy4$8(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); } -function getNumericAccessor$8(access, member) { - return cacheMethod$8(access, member, (name) => { - if (DataView.prototype[name]) { - return DataView.prototype[name]; - } else { - return getExtendedTypeAccessor$8(access, member); - } - }); +function copy8$8(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); } -const factories$p = {}; - -function useExtendedBool$8() { - factories$p[MemberType$8.Bool] = getExtendedBoolAccessor$8; +function copy16$8(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); } -function useExtendedInt$8() { - factories$p[MemberType$8.Int] = getExtendedIntAccessor$8; +function copy32$8(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); + dest.setInt32(16, src.getInt32(16, true), true); + dest.setInt32(20, src.getInt32(20, true), true); + dest.setInt32(24, src.getInt32(24, true), true); + dest.setInt32(28, src.getInt32(28, true), true); } -function useExtendedUint$8() { - factories$p[MemberType$8.Uint] = getExtendedUintAccessor$8; +function getMemoryResetter$8(offset, size) { + const reset = getResetFunction$8(size); + return function() { + /* WASM-ONLY */ + restoreMemory$8.call(this); + /* WASM-ONLY-END */ + const dest = this[MEMORY$8]; + reset(dest, offset, size); + }; } -function useExtendedFloat$8() { - factories$p[MemberType$8.Float] = getExtendedFloatAccessor$8; +function getResetFunction$8(size) { + const resetter = resetters$8[size]; + if (resetter) { + return resetter; + } + if (!(size & 0x07)) return reset8x$8; + if (!(size & 0x03)) return reset4x$8; + if (!(size & 0x01)) return reset2x$8; + return reset1x$8; } -function getExtendedTypeAccessor$8(access, member) { - const f = factories$p[member.type]; - return f(access, member); -} +const resetters$8 = { + 1: reset1$8, + 2: reset2$8, + 4: reset4$8, + 8: reset8$8, + 16: reset16$8, + 32: reset32$8, +}; -function getExtendedBoolAccessor$8(access, member) { - const { bitOffset } = member; - const bitPos = bitOffset & 0x07; - const mask = 1 << bitPos; - const get = DataView.prototype.getInt8; - if (access === 'get') { - return function(offset) { - const n = get.call(this, offset); - return !!(n & mask); - }; - } else { - const set = DataView.prototype.setInt8; - return function(offset, value) { - const n = get.call(this, offset); - const b = (value) ? n | mask : n & ~mask; - set.call(this, offset, b); - }; +function reset1x$8(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i++) { + dest.setInt8(i, 0); } } -function getExtendedIntAccessor$8(access, member) { - if (isByteAligned$8(member)) { - return getAlignedIntAccessor$8(access, member) - } else { - return getUnalignedIntAccessor$8(access, member); +function reset2x$8(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 2) { + dest.setInt16(i, 0, true); } } -function getExtendedUintAccessor$8(access, member) { - if (isByteAligned$8(member)) { - return getAlignedUintAccessor$8(access, member) - } else { - return getUnalignedUintAccessor$8(access, member); +function reset4x$8(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 4) { + dest.setInt32(i, 0, true); } } -function getExtendedFloatAccessor$8(access, member) { - if (isByteAligned$8(member)) { - return getAlignedFloatAccessor$8(access, member) - } else { - return getUnalignedFloatAccessor$8(access, member); +function reset8x$8(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 8) { + dest.setInt32(i, 0, true); + dest.setInt32(i + 4, 0, true); } } -function getDataView$8(structure, arg, env) { - const { type, byteSize, typedArray } = structure; - let dv; - // not using instanceof just in case we're getting objects created in other contexts - const tag = arg?.[Symbol.toStringTag]; - if (tag === 'DataView') { - dv = arg; - } else if (tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { - dv = env.obtainView(arg, 0, arg.byteLength); - } else if (typedArray && tag === typedArray.name || (tag === 'Uint8ClampedArray' && typedArray === Uint8Array)) { - dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); - } else if (tag === 'Uint8Array' && typeof(Buffer) === 'function' && arg instanceof Buffer) { - dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); - } else { - const memory = arg?.[MEMORY$8]; - if (memory) { - const { constructor, instance: { members: [ member ] } } = structure; - if (arg instanceof constructor) { - return memory; - } else if (type === StructureType$8.Array || type === StructureType$8.Slice || type === StructureType$8.Vector) { - const { byteSize: elementSize, structure: { constructor: Child } } = member; - const number = findElements$8(arg, Child); - if (number !== undefined) { - if (type === StructureType$8.Slice || number * elementSize === byteSize) { - return memory; - } else { - throwArrayLengthMismatch$8(structure, null, arg); - } - } - } - } - } - if (dv && byteSize !== undefined) { - checkDataViewSize$8(dv, structure); - } - return dv; +function reset1$8(dest, offset) { + dest.setInt8(offset, 0); } -function checkDataView$8(dv) { - if (dv?.[Symbol.toStringTag] !== 'DataView') { - throwTypeMismatch$8('a DataView', dv); - } - return dv; +function reset2$8(dest, offset) { + dest.setInt16(offset, 0, true); } -function checkDataViewSize$8(dv, structure) { - const { byteSize, type } = structure; - const multiple = type === StructureType$8.Slice; - if (multiple ? dv.byteLength % byteSize !== 0 : dv.byteLength !== byteSize) { - throwBufferSizeMismatch$8(structure, dv); - } +function reset4$8(dest, offset) { + dest.setInt32(offset, 0, true); } -function setDataView$8(dv, structure, copy, handlers) { - const { byteSize, type, sentinel } = structure; - const multiple = type === StructureType$8.Slice; - if (!this[MEMORY$8]) { - const { shapeDefiner } = handlers; - checkDataViewSize$8(dv, structure); - const len = dv.byteLength / byteSize; - const source = { [MEMORY$8]: dv }; - sentinel?.validateData(source, len); - shapeDefiner.call(this, copy ? null : dv, len); - if (copy) { - this[COPIER$8](source); - } - } else { - const byteLength = multiple ? byteSize * this.length : byteSize; - if (dv.byteLength !== byteLength) { - throwBufferSizeMismatch$8(structure, dv, this); - } - const source = { [MEMORY$8]: dv }; - sentinel?.validateData(source, this.length); - this[COPIER$8](source); - } +function reset8$8(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); } -function findElements$8(arg, Child) { - // casting to a array/slice - const { constructor: Arg } = arg; - if (Arg === Child) { - // matching object - return 1; - } else if (Arg.child === Child) { - // matching slice/array - return arg.length; - } +function reset16$8(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); } -function requireDataView$8(structure, arg, env) { - const dv = getDataView$8(structure, arg, env); - if (!dv) { - throwBufferExpected$8(structure); - } - return dv; +function reset32$8(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); + dest.setInt32(offset + 16, 0, true); + dest.setInt32(offset + 20, 0, true); + dest.setInt32(offset + 24, 0, true); + dest.setInt32(offset + 28, 0, true); } -function getTypedArrayClass$8(member) { - const { type: memberType, byteSize } = member; - if (memberType === MemberType$8.Int) { - switch (byteSize) { - case 1: return Int8Array; - case 2: return Int16Array; - case 4: return Int32Array; - case 8: return BigInt64Array; - } - } else if (memberType === MemberType$8.Uint) { - switch (byteSize) { - case 1: return Uint8Array; - case 2: return Uint16Array; - case 4: return Uint32Array; - case 8: return BigUint64Array; - } - } else if (memberType === MemberType$8.Float) { - switch (byteSize) { - case 4: return Float32Array; - case 8: return Float64Array; - } - } else if (memberType === MemberType$8.Object) { - return member.structure.typedArray; +function restoreMemory$8() { + const dv = this[MEMORY$8]; + const source = dv[MEMORY$8]; + if (!source || dv.buffer.byteLength !== 0) { + return false; } - return null; + const { memory, address, len } = source; + const newDV = new DataView(memory.buffer, address, len); + newDV[MEMORY$8] = source; + this[MEMORY$8] = newDV; + return true; } -function isTypedArray$8(arg, TypedArray) { - const tag = arg?.[Symbol.toStringTag]; - return (!!TypedArray && tag === TypedArray.name); -} +const decoders$8 = {}; +const encoders$8 = {}; -function isCompatible$8(arg, constructor) { - const tags = constructor[COMPAT$8]; - if (tags) { - const tag = arg?.[Symbol.toStringTag]; - if (tags.includes(tag)) { - return true; - } +function decodeText$8(arrays, encoding = 'utf-8') { + let decoder = decoders$8[encoding]; + if (!decoder) { + decoder = decoders$8[encoding] = new TextDecoder(encoding); } - if (constructor.child) { - if (findElements$8(arg, constructor.child) !== undefined) { - return true; + let array; + if (Array.isArray(arrays)) { + if (arrays.length === 1) { + array = arrays[0]; + } else { + let len = 0; + for (const a of arrays) { + len += a.length; + } + const { constructor } = arrays[0]; + array = new constructor(len); + let offset = 0; + for (const a of arrays) { + array.set(a, offset); + offset += a.length; + } } + } else { + array = arrays; } - return false; + return decoder.decode(array); } -function getCompatibleTags$8(structure) { - const { typedArray } = structure; - const tags = []; - if (typedArray) { - tags.push(typedArray.name); - tags.push('DataView'); - if (typedArray === Uint8Array || typedArray === Int8Array) { - tags.push('Uint8ClampedArray'); - tags.push('ArrayBuffer'); - tags.push('SharedArrayBuffer'); +function encodeText$8(text, encoding = 'utf-8') { + switch (encoding) { + case 'utf-16': { + const { length } = text; + const ta = new Uint16Array(length); + for (let i = 0; i < length; i++) { + ta[i] = text.charCodeAt(i); + } + return ta; + } + default: { + let encoder = encoders$8[encoding]; + if (!encoder) { + encoder = encoders$8[encoding] = new TextEncoder(); + } + return encoder.encode(text); } } - return tags; } -function isBuffer$8(arg, typedArray) { - const tag = arg?.[Symbol.toStringTag]; - if (tag === 'DataView' || tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { - return true; - } else if (typedArray && tag === typedArray.name) { - return true; - } else { - return false; - } +function encodeBase64$8(dv) { + const ta = new Uint8Array(dv.buffer, dv.byteOffset, dv.byteLength); + const bstr = String.fromCharCode.apply(null, ta); + return btoa(bstr); } -function getTypeName$8(member) { - const { type, bitSize, byteSize } = member; - if (type === MemberType$8.Int) { - return `${bitSize <= 32 ? '' : 'Big' }Int${bitSize}`; - } else if (type === MemberType$8.Uint) { - return `${bitSize <= 32 ? '' : 'Big' }Uint${bitSize}`; - } else if (type === MemberType$8.Float) { - return `Float${bitSize}`; - } else if (type === MemberType$8.Bool) { - const boolSize = (byteSize !== undefined) ? byteSize * 8 : 1; - return `Bool${boolSize}`; - } else if (type === MemberType$8.Void) { - return `Null`; +function decodeBase64$8(str) { + const bstr = atob(str); + const ta = new Uint8Array(bstr.length); + for (let i = 0; i < ta.byteLength; i++) { + ta[i] = bstr.charCodeAt(i); } + return new DataView(ta.buffer); } -function getBigIntDescriptor$8(bitSize) { - const getWord = DataView.prototype.getBigUint64; - const setWord = DataView.prototype.setBigUint64; - const wordCount = Math.ceil(bitSize / 64); - return { - get: function(offset, littleEndian) { - let n = 0n; - if (littleEndian) { - for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { - const w = getWord.call(this, j, littleEndian); - n = (n << 64n) | w; - } - } else { - for (let i = 0, j = offset; i < wordCount; i++, j += 8) { - const w = getWord.call(this, j, littleEndian); - n = (n << 64n) | w; - } - } - return n; - }, - set: function(offset, value, littleEndian) { - let n = value; - const mask = 0xFFFFFFFFFFFFFFFFn; - if (littleEndian) { - for (let i = 0, j = offset; i < wordCount; i++, j += 8) { - const w = n & mask; - setWord.call(this, j, w, littleEndian); - n >>= 64n; - } - } else { - n <<= BigInt(wordCount * 64 - bitSize); - for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { - const w = n & mask; - setWord.call(this, j, w, littleEndian); - n >>= 64n; - } +function getValueOf$8() { + const map = new Map(); + const options = { error: 'throw' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$8]; + if (normalizer) { + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + map.set(value, result); } - return n; - }, + return result; + } else { + return value; + } }; + return process(this); } -function getAlignedIntAccessor$8(access, member) { - const { bitSize, byteSize } = member; - if (bitSize < 64) { - // actual number of bits needed when stored aligned - const typeName = getTypeName$8({ ...member, bitSize: byteSize * 8 }); - const get = DataView.prototype[`get${typeName}`]; - const set = DataView.prototype[`set${typeName}`]; - const signMask = (bitSize <= 32) ? 2 ** (bitSize - 1) : 2n ** BigInt(bitSize - 1); - const valueMask = (bitSize <= 32) ? signMask - 1 : signMask - 1n; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - return (n & valueMask) - (n & signMask); - }; - } else { - return function(offset, value, littleEndian) { - const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; - set.call(this, offset, n, littleEndian); - }; - } - } else { - // larger than 64 bits - const { get, set } = getBigIntDescriptor$8(bitSize); - const signMask = 2n ** BigInt(bitSize - 1); - const valueMask = signMask - 1n; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - return (n & valueMask) - (n & signMask); - }; +const INT_MAX$8 = BigInt(Number.MAX_SAFE_INTEGER); +const INT_MIN$8 = BigInt(Number.MIN_SAFE_INTEGER); + +function convertToJSON$8() { + const map = new Map(); + const options = { error: 'return' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$8]; + if (normalizer) { + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + if (typeof(result?.toJSON) === 'function') { + result = result.toJSON(); + } + map.set(value, result); + } + return result; } else { - return function(offset, value, littleEndian) { - const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; - set.call(this, offset, n, littleEndian); - }; + if (typeof(value) === 'bigint' && INT_MIN$8 <= value && value <= INT_MAX$8) { + return Number(value); + } + return value; } - } + }; + return process(this); } -function getAlignedUintAccessor$8(access, member) { - const { bitSize, byteSize } = member; - if (bitSize < 64) { - // actual number of bits needed when stored aligned - const typeName = getTypeName$8({ ...member, bitSize: byteSize * 8 }); - const get = DataView.prototype[`get${typeName}`]; - const set = DataView.prototype[`set${typeName}`]; - const valueMask = (bitSize <= 32) ? (2 ** bitSize) - 1 : (2n ** BigInt(bitSize)) - 1n; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - return n & valueMask; - }; - } else { - return function(offset, value, littleEndian) { - const n = value & valueMask; - set.call(this, offset, n, littleEndian); - }; - } - } else { - // larger than 64 bits - const { get, set } = getBigIntDescriptor$8(bitSize); - const valueMask = (2n ** BigInt(bitSize)) - 1n; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - return n & valueMask; - }; - } else { - return function(offset, value, littleEndian) { - const n = value & valueMask; - set.call(this, offset, n, littleEndian); - }; - } - } +function normalizeValue$8(cb, options) { + const value = handleError$8(() => this.$, options); + return cb(value); } -function getUnalignedIntAccessor$8(access, member) { - const { bitSize, bitOffset } = member; - const bitPos = bitOffset & 0x07; - if (bitPos + bitSize <= 8) { - const set = DataView.prototype.setUint8; - const get = DataView.prototype.getUint8; - // sub-8-bit numbers have real use cases - const signMask = 2 ** (bitSize - 1); - const valueMask = signMask - 1; - if (access === 'get') { - return function(offset) { - const n = get.call(this, offset); - const s = n >>> bitPos; - return (s & valueMask) - (s & signMask); - }; +function handleError$8(cb, options = {}) { + const { error = 'throw' } = options; + try { + return cb(); + } catch (err) { + if (error === 'return') { + return err; } else { - const outsideMask = 0xFF ^ ((valueMask | signMask) << bitPos); - return function(offset, value) { - let b = get.call(this, offset); - const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; - b = (b & outsideMask) | (n << bitPos); - set.call(this, offset, b); - }; + throw err; } } - return getUnalignedNumericAccessor$8(access, member); } -function getUnalignedUintAccessor$8(access, member) { - const { bitSize, bitOffset } = member; - const bitPos = bitOffset & 0x07; - if (bitPos + bitSize <= 8) { - const set = DataView.prototype.setUint8; - const get = DataView.prototype.getUint8; - const valueMask = (2 ** bitSize - 1); - if (access === 'get') { - return function(offset) { - const n = get.call(this, offset); - const s = n >>> bitPos; - return s & valueMask; - }; - } else { - const outsideMask = 0xFF ^ (valueMask << bitPos); - return function(offset, value) { - const n = get.call(this, offset); - const b = (n & outsideMask) | ((value & valueMask) << bitPos); - set.call(this, offset, b); - }; +function getDataViewDescriptor$8(structure, handlers = {}) { + return markAsSpecial$8({ + get() { + /* WASM-ONLY */ + restoreMemory$8.call(this); + /* WASM-ONLY-END */ + return this[MEMORY$8]; + }, + set(dv) { + checkDataView$8(dv); + setDataView$8.call(this, dv, structure, true, handlers); + }, + }); +} + +function getBase64Descriptor$8(structure, handlers = {}) { + return markAsSpecial$8({ + get() { + return encodeBase64$8(this.dataView); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$8('string', str); + } + const dv = decodeBase64$8(str); + setDataView$8.call(this, dv, structure, false, handlers); } - } - return getUnalignedNumericAccessor$8(access, member); + }); } -function getAlignedFloatAccessor$8(access, member) { - const { bitSize, byteSize } = member; - if (bitSize === 16) { - const buf = new DataView(new ArrayBuffer(4)); - const set = DataView.prototype.setUint16; - const get = DataView.prototype.getUint16; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - const sign = n >>> 15; - const exp = (n & 0x7C00) >> 10; - const frac = n & 0x03FF; - if (exp === 0) { - return (sign) ? -0 : 0; - } else if (exp === 0x1F) { - if (!frac) { - return (sign) ? -Infinity : Infinity; - } else { - return NaN; - } - } - const n32 = (sign << 31) | ((exp - 15 + 127) << 23) | (frac << 13); - buf.setUint32(0, n32, littleEndian); - return buf.getFloat32(0, littleEndian); +function getStringDescriptor$8(structure, handlers = {}) { + const { sentinel, instance: { members }} = structure; + const { byteSize: charSize } = members[0]; + return markAsSpecial$8({ + get() { + const dv = this.dataView; + const TypedArray = (charSize === 1) ? Int8Array : Int16Array; + const ta = new TypedArray(dv.buffer, dv.byteOffset, this.length); + const s = decodeText$8(ta, `utf-${charSize * 8}`); + return (sentinel?.value === undefined) ? s : s.slice(0, -1); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$8('a string', str); } - } else { - return function(offset, value, littleEndian) { - buf.setFloat32(0, value, littleEndian); - const n = buf.getUint32(0, littleEndian); - const sign = n >>> 31; - const exp = (n & 0x7F800000) >> 23; - const frac = n & 0x007FFFFF; - const exp16 = (exp - 127 + 15); - let n16; - if (exp === 0) { - n16 = sign << 15; - } else if (exp === 0xFF) { - n16 = sign << 15 | 0x1F << 10 | (frac ? 1 : 0); - } else if (exp16 >= 31) { - n16 = sign << 15 | 0x1F << 10; - } else { - n16 = sign << 15 | exp16 << 10 | (frac >> 13); + if (sentinel?.value !== undefined) { + if (str.charCodeAt(str.length - 1) !== sentinel.value) { + str = str + String.fromCharCode(sentinel.value); } - set.call(this, offset, n16, littleEndian); } - } - } else if (bitSize === 80) { - const buf = new DataView(new ArrayBuffer(8)); - const get = function(offset, littleEndian) { - const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); - const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); - const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); - return w1 | w2 << 32n | w3 << 64n; - }; - const set = function(offset, value, littleEndian) { - const w1 = value & 0xFFFFFFFFn; - const w2 = (value >> 32n) & 0xFFFFFFFFn; - const w3 = (value >> 64n) & 0xFFFFFFFFn; - this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); - this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); - this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); - }; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - const sign = n >> 79n; - const exp = (n & 0x7FFF0000000000000000n) >> 64n; - const frac = n & 0x00007FFFFFFFFFFFFFFFn; - if (exp === 0n) { - return (sign) ? -0 : 0; - } else if (exp === 0x7FFFn) { - if (!frac) { - return (sign) ? -Infinity : Infinity; - } else { - return NaN; - } - } - const exp64 = exp - 16383n + 1023n; - if (exp64 >= 2047n) { - return (sign) ? -Infinity : Infinity; - } - const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 11n) + BigInt((frac & (2n**11n - 1n)) >= 2n**10n); - buf.setBigUint64(0, n64, littleEndian); - return buf.getFloat64(0, littleEndian); + const ta = encodeText$8(str, `utf-${charSize * 8}`); + const dv = new DataView(ta.buffer); + setDataView$8.call(this, dv, structure, false, handlers); + }, + }); +} + +function getTypedArrayDescriptor$8(structure, handlers = {}) { + const { typedArray } = structure; + return markAsSpecial$8({ + get() { + const dv = this.dataView; + const length = dv.byteLength / typedArray.BYTES_PER_ELEMENT; + return new typedArray(dv.buffer, dv.byteOffset, length); + }, + set(ta) { + if (!isTypedArray$8(ta, typedArray)) { + throwTypeMismatch$8(typedArray.name, ta); + } + const dv = new DataView(ta.buffer, ta.byteOffset, ta.byteLength); + setDataView$8.call(this, dv, structure, true, handlers); + }, + }); +} + +function markAsSpecial$8({ get, set }) { + get.special = set.special = true; + return { get, set }; +} + +function definePointer$8(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + isConst, + } = structure; + const { + runtimeSafety = true, + } = env; + const { structure: targetStructure } = member; + const { sentinel } = targetStructure; + const isTargetSlice = (targetStructure.type === StructureType$8.Slice); + const isTargetPointer = (targetStructure.type === StructureType$8.Pointer); + const hasLength = isTargetSlice && !sentinel; + const addressSize = (hasLength) ? byteSize / 2 : byteSize; + const { get: getAddress, set: setAddress } = getDescriptor$8({ + type: MemberType$8.Uint, + bitOffset: 0, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { byteSize: addressSize }, + }, env); + const { get: getLength, set: setLength } = (hasLength) ? getDescriptor$8({ + type: MemberType$8.Uint, + bitOffset: addressSize * 8, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { name: 'usize', byteSize: addressSize }, + }, env) : {}; + const updateTarget = function() { + const prevLocation = this[FIXED_LOCATION$8]; + if (prevLocation) { + const location = this[LOCATION_GETTER$8](); + if (location.address !== prevLocation.address || location.length !== prevLocation.length) { + const { constructor: Target } = targetStructure; + const dv = env.findMemory(location.address, location.length * Target[SIZE$8]); + const target = Target.call(ENVIRONMENT$8, dv, { writable: !isConst }); + this[SLOTS$8][0] = target; + this[FIXED_LOCATION$8] = location; + } + } + }; + const getTargetObject = function() { + updateTarget.call(this); + return this[SLOTS$8][0] ?? throwNullPointer$8(); + }; + const setTargetObject = function(arg) { + if (env.inFixedMemory(this)) { + // the pointer sits in fixed memory--apply the change immediately + if (env.inFixedMemory(arg)) { + const loc = { + address: env.getViewAddress(arg[MEMORY$8]), + length: (hasLength) ? arg.length : 1 + }; + addressSetter.call(this, loc); + this[FIXED_LOCATION$8] = loc; + } else { + throwFixedMemoryTargetRequired$8(); } + } + this[SLOTS$8][0] = arg; + }; + const getTarget = isValueExpected$8(targetStructure) + ? function() { + const target = getTargetObject.call(this); + return target[GETTER$8](); + } + : getTargetObject; + const setTarget = function(value) { + updateTarget.call(this); + const object = this[SLOTS$8][0] ?? throwNullPointer$8(); + return object[SETTER$8](value); + }; + const alternateCaster = function(arg, options) { + const Target = targetStructure.constructor; + if ((this === ENVIRONMENT$8 || this === PARENT$8) || arg instanceof constructor) { + // casting from buffer to pointer is allowed only if request comes from the runtime + // casting from writable to read-only is also allowed + return false; + } else if (isPointerOf$8(arg, Target)) { + // const/non-const casting + return new constructor(Target(arg['*'], { writable: !isConst }), options); + } else if (isTargetSlice) { + // allow casting to slice through constructor of its pointer + return new constructor(Target(arg), options); } else { - return function(offset, value, littleEndian) { - buf.setFloat64(0, value, littleEndian); - const n = buf.getBigUint64(0, littleEndian); - const sign = n >> 63n; - const exp = (n & 0x7FF0000000000000n) >> 52n; - const frac = n & 0x000FFFFFFFFFFFFFn; - let n80; - if (exp === 0n) { - n80 = sign << 79n | (frac << 11n); - } else if (exp === 0x07FFn) { - n80 = sign << 79n | 0x7FFFn << 64n | (frac ? 0x00002000000000000000n : 0n) | 0x00008000000000000000n; - // ^ bit 61 ^ bit 63 - } else { - n80 = sign << 79n | (exp - 1023n + 16383n) << 64n | (frac << 11n) | 0x00008000000000000000n; - } - set.call(this, offset, n80, littleEndian); + throwNoCastingToPointer$8(); + } + }; + const finalizer = function() { + const handlers = (isTargetPointer) ? {} : proxyHandlers$h; + const proxy = new Proxy(this, handlers); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$8, { value: proxy }); + return proxy; + }; + const initializer = function(arg) { + const Target = targetStructure.constructor; + if (isPointerOf$8(arg, Target)) { + // initialize with the other pointer'structure target + if (!isConst && arg.constructor.const) { + throwConstantConstraint$8(structure, arg); } + arg = arg[SLOTS$8][0]; } - } else if (bitSize === 128) { - const buf = new DataView(new ArrayBuffer(8)); - const get = function(offset, littleEndian) { - const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); - const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); - const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); - const w4 = BigInt(this.getUint32(offset + (littleEndian ? 12 : byteSize - 16), littleEndian)); - return w1 | w2 << 32n | w3 << 64n | w4 << 96n; - }; - const set = function(offset, value, littleEndian) { - const w1 = value & 0xFFFFFFFFn; - const w2 = (value >> 32n) & 0xFFFFFFFFn; - const w3 = (value >> 64n) & 0xFFFFFFFFn; - const w4 = (value >> 96n) & 0xFFFFFFFFn; - this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); - this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); - this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); - this.setUint32(offset + (littleEndian ? 12 : byteSize - 16), Number(w4), littleEndian); - }; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - const sign = n >> 127n; - const exp = (n & 0x7FFF0000000000000000000000000000n) >> 112n; - const frac = n & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFn; - if (exp === 0n) { - return (sign) ? -0 : 0; - } else if (exp === 0x7FFFn) { - if (!frac) { - return (sign) ? -Infinity : Infinity; - } else { - return NaN; - } - } - const exp64 = exp - 16383n + 1023n; - if (exp64 >= 2047n) { - return (sign) ? -Infinity : Infinity; - } - const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 60n) + BigInt((frac & (2n**60n - 1n)) >= 2n**59n); - buf.setBigUint64(0, n64, littleEndian); - return buf.getFloat64(0, littleEndian); + if (arg instanceof Target) { + /* wasm-only */ + restoreMemory$8.call(arg); + /* wasm-only-end */ + if (isConst && !arg[CONST$8]) { + // create read-only version + arg = Target(arg, { writable: false }); + } else if (!isConst && arg[CONST$8]) { + throwReadOnlyTarget$8(structure); } - } else { - return function(offset, value, littleEndian) { - buf.setFloat64(0, value, littleEndian); - const n = buf.getBigUint64(0, littleEndian); - const sign = n >> 63n; - const exp = (n & 0x7FF0000000000000n) >> 52n; - const frac = n & 0x000FFFFFFFFFFFFFn; - let n128; - if (exp === 0n) { - n128 = sign << 127n | (frac << 60n); - } else if (exp === 0x07FFn) { - n128 = sign << 127n | 0x7FFFn << 112n | (frac ? 1n : 0n); - } else { - n128 = sign << 127n | (exp - 1023n + 16383n) << 112n | (frac << 60n); + } else if (isCompatible$8(arg, Target)) { + // autocast to target type + const dv = getDataView$8(targetStructure, arg, env); + arg = Target(dv, { writable: !isConst }); + } else if (arg !== undefined && !arg[MEMORY$8]) { + // autovivificate target object + const fixed = env.inFixedMemory(this); + const autoObj = new Target(arg, { writable: !isConst, fixed }); + if (runtimeSafety) { + // creation of a new slice using a typed array is probably + // not what the user wants; it's more likely that the intention + // is to point to the typed array but there's a mismatch (e.g. u32 vs i32) + if (targetStructure.typedArray && isBuffer$8(arg?.buffer)) { + warnImplicitArrayCreation$8(targetStructure, arg); } - set.call(this, offset, n128, littleEndian); } + arg = autoObj; + } else if (arg !== undefined) { + throwInvalidPointerTarget$8(structure, arg); } + this[TARGET_SETTER$8](arg); + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer, alternateCaster, finalizer }, env); + const addressSetter = function({ address, length }) { + setAddress.call(this, address); + setLength?.call(this, length); + }; + const addressGetter = function() { + const address = getAddress.call(this); + const length = (getLength) + ? getLength.call(this) + : (sentinel) + ? (address) ? env.findSentinel(address, sentinel.bytes) + 1 : 0 + : 1; + return { address, length }; + }; + const instanceDescriptors = { + '*': { get: getTarget, set: setTarget }, + '$': { get: getProxy$8, set: initializer }, + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [TARGET_GETTER$8]: { value: getTargetObject }, + [TARGET_SETTER$8]: { value: setTargetObject }, + [LOCATION_GETTER$8]: { value: addressGetter }, + [LOCATION_SETTER$8]: { value: addressSetter }, + [POINTER_VISITOR$8]: { value: visitPointer$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [VIVIFICATOR$8]: { value: throwNullPointer$8 }, + [NORMALIZER$8]: { value: normalizePointer$8 }, + [FIXED_LOCATION$8]: { value: undefined, writable: true }, + }; + const staticDescriptors = { + child: { get: () => targetStructure.constructor }, + const: { value: isConst }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizePointer$8(cb) { + let target; + try { + target = this['*']; + } catch (err) { + target = Symbol.for('inaccessible'); } + return cb(target); } -function getUnalignedFloatAccessor$8(access, member) { - return getUnalignedNumericAccessor$8(access, member); +function getProxy$8() { + return this[PROXY$8]; } -function getUnalignedNumericAccessor$8(access, member) { - // pathological usage scenario--handle it anyway by copying the bitSize into a - // temporary buffer, bit-aligning the data - const { bitSize, bitOffset } = member; - const bitPos = bitOffset & 0x07; - const byteSize = [ 1, 2, 4, 8 ].find(b => b * 8 >= bitSize) ?? Math.ceil(bitSize / 64) * 64; - const buf = new DataView(new ArrayBuffer(byteSize)); - if (access === 'get') { - const getAligned = getNumericAccessor$8('get', { ...member, byteSize }); - const copyBits = getBitAlignFunction$8(bitPos, bitSize, true); - return function(offset, littleEndian) { - copyBits(buf, this, offset); - return getAligned.call(buf, 0, littleEndian); - }; - } else { - const setAligned = getNumericAccessor$8('set', { ...member, byteSize }); - const applyBits = getBitAlignFunction$8(bitPos, bitSize, false); - return function(offset, value, littleEndian) { - setAligned.call(buf, 0, value, littleEndian); - applyBits(this, buf, offset); - }; +function copyPointer$8({ source }) { + const target = source[SLOTS$8][0]; + if (target) { + this[TARGET_SETTER$8](target); } } -const methodCache$8 = {}; +function resetPointer$8({ isActive }) { + if (this[SLOTS$8][0] && !isActive(this)) { + this[SLOTS$8][0] = undefined; + } +} -function cacheMethod$8(access, member, cb) { - const { type, bitOffset, bitSize, structure } = member; - const bitPos = bitOffset & 0x07; - const typeName = getTypeName$8(member); - const suffix = isByteAligned$8(member) ? `` : `Bit${bitPos}`; - const isInt = type === MemberType$8.Int || type === MemberType$8.Uint; - let name = `${access}${typeName}${suffix}`; - let isSize = false, originalName = name; - if (isInt && bitSize === 64) { - const zigTypeName = structure?.name; - if (zigTypeName === 'usize' || zigTypeName === 'isize') { - name += 'Size'; - isSize = true; +function disablePointer$8() { + const disabledProp = { get: throwInaccessiblePointer$8, set: throwInaccessiblePointer$8 }; + const disabledFunc = { value: throwInaccessiblePointer$8 }; + defineProperties$8(this[POINTER$8], { + '*': disabledProp, + '$': disabledProp, + [GETTER$8]: disabledFunc, + [SETTER$8]: disabledFunc, + [TARGET_GETTER$8]: disabledFunc, + }); +} + +function visitPointer$8(fn, options = {}) { + const { + source, + isActive = always$8, + isMutable = always$8, + } = options; + fn.call(this, { source, isActive, isMutable }); +} + +function isPointerOf$8(arg, Target) { + return (arg?.constructor?.child === Target && arg['*']); +} + +const proxyHandlers$h = { + get(pointer, name) { + if (name === POINTER$8) { + return pointer; + } else if (name in pointer) { + return pointer[name]; + } else { + const target = pointer[TARGET_GETTER$8](); + return target[name]; } - } - let fn = methodCache$8[name]; - if (!fn) { - if (isInt && access === 'set') { - // add auto-conversion between number and bigint - const Primitive = getPrimitiveClass$8(member); - const set = cb(originalName); - fn = function(offset, value, littleEndian) { - set.call(this, offset, Primitive(value), littleEndian); - }; - } else if (isSize && access === 'get') { - // use number instead of bigint where possible - const get = cb(originalName); - const min = BigInt(Number.MIN_SAFE_INTEGER); - const max = BigInt(Number.MAX_SAFE_INTEGER); - fn = function(offset, littleEndian) { - const value = get.call(this, offset, littleEndian); - if (min <= value && value <= max) { - return Number(value); - } else { - return value; - } - }; + }, + set(pointer, name, value) { + if (name in pointer) { + pointer[name] = value; + } else { + const target = pointer[TARGET_GETTER$8](); + target[name] = value; + } + return true; + }, + deleteProperty(pointer, name) { + if (name in pointer) { + delete pointer[name]; } else { - fn = cb(name); + const target = pointer[TARGET_GETTER$8](); + delete target[name]; } - if (fn && fn.name !== name) { - Object.defineProperty(fn, 'name', { value: name, configurable: true, writable: false }); + return true; + }, + has(pointer, name) { + if (name in pointer) { + return true; + } else { + const target = pointer[TARGET_GETTER$8](); + return name in target; } - methodCache$8[name] = fn; - } - return fn; -} + }, +}; -function useAllExtendedTypes$8() { - useExtendedBool$8(); - useExtendedInt$8(); - useExtendedUint$8(); - useExtendedFloat$8(); +function always$8() { + return true; } -const MemberType$8 = { - Void: 0, - Bool: 1, - Int: 2, - Uint: 3, - Float: 4, - EnumerationItem: 5, - Error: 6, - Object: 7, - Type: 8, - Comptime: 9, - Static: 10, - Literal: 11, - Null: 12, - Undefined: 13, -}; +function never$8() { + return false; +} -function isReadOnly$8(type) { - switch (type) { - case MemberType$8.Type: - case MemberType$8.Comptime: - case MemberType$8.Literal: - return true; - default: - return false; +function defineStructShape$8(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const memberDescriptors = {}; + for (const member of members) { + const { get, set } = getDescriptor$8(member, env); + memberDescriptors[member.name] = { get, set, configurable: true, enumerable: true }; + if (member.isRequired && set) { + set.required = true; + } } + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); + if (hasPointer) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } else if (arg && typeof(arg) === 'object') { + propApplier.call(this, arg); + } else if (arg !== undefined) { + throwInvalidInitializer$8(structure, 'object', arg); + } + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const instanceDescriptors = { + $: { get: getSelf$8, set: initializer }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getStructIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, always$8) }, + [NORMALIZER$8]: { value: normalizeStruct$8 }, + [PROPS$8]: { value: members.map(m => m.name) }, + }; + const staticDescriptors = { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } -const factories$o = {}; - -function useVoid$8() { - factories$o[MemberType$8.Void] = getVoidDescriptor$8; +function normalizeStruct$8(cb, options) { + const object = {}; + for (const [ name, value ] of getStructEntries$8.call(this, options)) { + object[name] = cb(value); + } + return object; } -function useBool$8() { - factories$o[MemberType$8.Bool] = getBoolDescriptor$8; +function getStructEntries$8(options) { + return { + [Symbol.iterator]: getStructEntriesIterator$8.bind(this, options), + length: this[PROPS$8].length, + }; } -function useInt$8() { - factories$o[MemberType$8.Int] = getIntDescriptor$8; +function getStructIterator$8(options) { + const entries = getStructEntries$8.call(this, options); + return entries[Symbol.iterator](); } -function useUint$8() { - factories$o[MemberType$8.Uint] = getUintDescriptor$8; +function getStructEntriesIterator$8(options) { + const self = this; + const props = this[PROPS$8]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + value = [ current, handleError$8(() => self[current], options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; } - -function useFloat$8() { - factories$o[MemberType$8.Float] = getFloatDescriptor$8; + +function getChildVivificator$h(structure) { + const { instance: { members } } = structure; + const objectMembers = {}; + for (const member of members.filter(m => m.type === MemberType$8.Object)) { + objectMembers[member.slot] = member; + } + return function vivificateChild(slot, writable = true) { + const member = objectMembers[slot]; + const { bitOffset, byteSize, structure: { constructor } } = member; + const dv = this[MEMORY$8]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + (bitOffset >> 3); + let len = byteSize; + if (len === undefined) { + if (bitOffset & 7) { + throwNotOnByteBoundary$8(member); + } + len = member.bitSize >> 3; + } + const childDV = new DataView(dv.buffer, offset, len); + const object = this[SLOTS$8][slot] = constructor.call(PARENT$8, childDV, { writable }); + return object; + } } -function useEnumerationItem$8() { - factories$o[MemberType$8.EnumerationItem] = getEnumerationItemDescriptor$8; +function getPointerVisitor$h(structure, visitorOptions = {}) { + const { + isChildActive = always$8, + isChildMutable = always$8, + } = visitorOptions; + const { instance: { members } } = structure; + const pointerMembers = members.filter(m => m.structure.hasPointer); + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$8, + isMutable = always$8, + } = options; + const childOptions = { + ...options, + isActive: (object) => { + // make sure parent object is active, then check whether the child is active + return isActive(this) && isChildActive.call(this, object); + }, + isMutable: (object) => { + return isMutable(this) && isChildMutable.call(this, object); + }, + }; + for (const { slot } of pointerMembers) { + if (source) { + // when src is a the struct's template, most slots will likely be empty, + // since pointer fields aren't likely to have default values + const srcChild = source[SLOTS$8]?.[slot]; + if (!srcChild) { + continue; + } + childOptions.source = srcChild; + } + const child = this[SLOTS$8][slot] ?? (vivificate ? this[VIVIFICATOR$8](slot) : null); + if (child) { + child[POINTER_VISITOR$8](cb, childOptions); + } + } + }; } -function useError$8() { - factories$o[MemberType$8.Error] = getErrorDescriptor$8; +function defineArgStruct$8(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const constructor = structure.constructor = function(args) { + const dv = env.allocateMemory(byteSize, align); + this[MEMORY$8] = dv; + if (hasObject) { + this[SLOTS$8] = {}; + } + initializer.call(this, args); + }; + const argNames = members.slice(0, -1).map(m => m.name); + const argCount = argNames.length; + const initializer = function(args) { + if (args.length !== argCount) { + throwArgumentCountMismatch$8(structure, args.length); + } + for (const [ index, name ] of argNames.entries()) { + try { + this[name] = args[index]; + } catch (err) { + rethrowArgumentError$8(structure, index, err); + } + } + }; + const memberDescriptors = {}; + for (const member of members) { + memberDescriptors[member.name] = getDescriptor$8(member, env); + } + const isChildMutable = function(object) { + return (object === this.retval); + }; + defineProperties$8(constructor.prototype, { + ...memberDescriptors, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, { isChildMutable }) }, + }); + defineProperties$8(constructor, { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }); + return constructor; } -function useObject$8() { - factories$o[MemberType$8.Object] = getObjectDescriptor$8; +function defineArray$8(structure, env) { + const { + length, + byteSize, + align, + instance: { members: [ member ] }, + hasPointer, + } = structure; + const { get, set } = getDescriptor$8(member, env); + const hasStringProp = canBeString$8(member); + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); + if (hasPointer) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } else { + if (typeof(arg) === 'string' && hasStringProp) { + arg = { string: arg }; + } + if (arg?.[Symbol.iterator]) { + arg = transformIterable$8(arg); + if (arg.length !== length) { + throwArrayLengthMismatch$8(structure, this, arg); + } + let i = 0; + for (const value of arg) { + set.call(this, i++, value); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$8(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$8(structure, arg); + } + } + }; + const finalizer = createArrayProxy$8; + const constructor = structure.constructor = createConstructor$8(structure, { initializer, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); + const hasObject = member.type === MemberType$8.Object; + const instanceDescriptors = { + $: { get: getProxy$8, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + string: hasStringProp && getStringDescriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$8 }, + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [Symbol.iterator]: { value: getArrayIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$g(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$g() }, + [NORMALIZER$8]: { value: normalizeArray$8 }, + }; + const staticDescriptors = { + child: { get: () => member.structure.constructor }, + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } -function useType$8() { - factories$o[MemberType$8.Type] = getTypeDescriptor$8; +function createArrayProxy$8() { + const proxy = new Proxy(this, proxyHandlers$g); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$8, { value: proxy }); + return proxy; } -function useComptime$8() { - factories$o[MemberType$8.Comptime] = getComptimeDescriptor$8; +function canBeString$8(member) { + return member.type === MemberType$8.Uint && [ 8, 16 ].includes(member.bitSize); } -function useStatic$8() { - factories$o[MemberType$8.Static] = getStaticDescriptor$8; +function normalizeArray$8(cb, options) { + const array = []; + for (const [ index, value ] of getArrayEntries$8.call(this, options)) { + array.push(cb(value)); + } + return array; } -function useLiteral$8() { - factories$o[MemberType$8.Literal] = getLiteralDescriptor$8; +function getArrayIterator$8() { + const self = this[ARRAY$8] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self.get(current); + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; } -function useNull$8() { - factories$o[MemberType$8.Null] = getNullDescriptor$8; +function getArrayEntriesIterator$8(options) { + const self = this[ARRAY$8] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, handleError$8(() => self.get(current), options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; } -function useUndefined$8() { - factories$o[MemberType$8.Undefined] = getUndefinedDescriptor$8; +function getArrayEntries$8(options) { + return { + [Symbol.iterator]: getArrayEntriesIterator$8.bind(this, options), + length: this.length, + }; } -function isByteAligned$8({ bitOffset, bitSize, byteSize }) { - return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; +function getChildVivificator$g(structure) { + const { instance: { members: [ member ]} } = structure; + const { byteSize, structure: elementStructure } = member; + return function getChild(index, writable = true) { + const { constructor } = elementStructure; + const dv = this[MEMORY$8]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + byteSize * index; + const childDV = new DataView(dv.buffer, offset, byteSize); + const object = this[SLOTS$8][index] = constructor.call(PARENT$8, childDV, { writable }); + return object; + }; } -function hasStandardIntSize({ bitSize }) { - return bitSize === 8 || bitSize === 16 || bitSize === 32 || bitSize === 64; +function getPointerVisitor$g(structure) { + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$8, + isMutable = always$8, + } = options; + const childOptions = { + ...options, + isActive: () => isActive(this), + isMutable: () => isMutable(this), + }; + for (let i = 0, len = this.length; i < len; i++) { + // no need to check for empty slots, since that isn't possible + if (source) { + childOptions.source = source?.[SLOTS$8][i]; + } + const child = this[SLOTS$8][i] ?? (vivificate ? this[VIVIFICATOR$8](i) : null); + if (child) { + child[POINTER_VISITOR$8](cb, childOptions); + } + } + }; } -function hasStandardFloatSize({ bitSize }) { - return bitSize === 32 || bitSize === 64; +function transformIterable$8(arg) { + if (typeof(arg.length) === 'number') { + // it's an array of sort + return arg; + } + const iterator = arg[Symbol.iterator](); + const first = iterator.next(); + const length = first.value?.length; + if (typeof(length) === 'number' && Object.keys(first.value).join() === 'length') { + // return generator with length attached + return Object.assign((function*() { + let result; + while (!(result = iterator.next()).done) { + yield result.value; + } + })(), { length }); + } else { + const array = []; + let result = first; + while (!result.done) { + array.push(result.value); + result = iterator.next(); + } + return array; + } } -function getDescriptor$8(member, env) { - const f = factories$o[member.type]; - return f(member, env); -} +const proxyHandlers$g = { + get(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return array.get(index); + } else { + switch (name) { + case 'get': + if (!array[ELEMENT_GETTER$8]) { + array[ELEMENT_GETTER$8] = array.get.bind(array); + } + return array[ELEMENT_GETTER$8]; + case 'set': + if (!array[ELEMENT_SETTER$8]) { + array[ELEMENT_SETTER$8] = array.set.bind(array); + } + return array[ELEMENT_SETTER$8]; + case ARRAY$8: + return array; + default: + return array[name]; + } + } + }, + set(array, name, value) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + array.set(index, value); + } else { + switch (name) { + case 'get': + array[ELEMENT_GETTER$8] = value; + break; + case 'set': + array[ELEMENT_SETTER$8] = value; + break; + default: + array[name] = value; + } + } + return true; + }, + deleteProperty(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return false; + } else { + switch (name) { + case 'get': + delete array[ELEMENT_GETTER$8]; + break; + case 'set': + delete array[ELEMENT_SETTER$8]; + break; + default: + delete array[name]; + } + return true; + } + }, + has(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return (index >= 0 && index < array.length); + } else { + return array[name]; + } + }, + ownKeys(array) { + const keys = []; + for (let i = 0, len = array.length; i < len; i++) { + keys.push(`${i}`); + } + keys.push('length', PROXY$8); + return keys; + }, + getOwnPropertyDescriptor(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + if (index >= 0 && index < array.length) { + return { value: array.get(index), enumerable: true, writable: true, configurable: true }; + } + } else { + return Object.getOwnPropertyDescriptor(array, name); + } + }, +}; -function getVoidDescriptor$8(member, env) { - const { runtimeSafety } = env; - return { - get: function() { - return undefined; +function defineEnumerationShape$8(structure, env) { + const { + byteSize, + align, + instance: { + members: [ member ], }, - set: (runtimeSafety) - ? function(value) { - if (value !== undefined) { - throwNotUndefined$8(member); + } = structure; + const { get, set } = getDescriptor$8(member, env); + const expected = [ 'string', 'number', 'tagged union' ]; + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$8(structure, expected, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'string' || typeof(arg) === 'number' || typeof(arg) === 'bigint') { + let item = constructor[arg]; + if (!item) { + if (constructor[MORE$8] && typeof(arg) !== 'string') { + // create the item on-the-fly when enum is non-exhaustive + item = new constructor(undefined); + debugger; + set.call(item, arg, 'number'); + appendEnumeration(constructor, `${arg}`, item); } } - : function() {}, - } + return item; + } else if (arg instanceof constructor) { + return arg; + } else if (arg?.[TAG$8] instanceof constructor) { + // a tagged union, return the active tag + return arg[TAG$8]; + } else if (!getDataView$8(structure, arg, env)) { + throwInvalidInitializer$8(structure, expected, arg); + } else { + return false; + } + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); + const toPrimitive = function(hint) { + return (hint === 'string') ? this.$[NAME$8] : get.call(this, 'number'); + }; + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [Symbol.toPrimitive]: { value: toPrimitive }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: normalizeEnumerationItem$8 }, + }; + const staticDescriptors = { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } - -function getNullDescriptor$8(member, env) { - return { - get: function() { - return null; - }, - } +function normalizeEnumerationItem$8(cb) { + return cb(this.$[NAME$8]); } -function getUndefinedDescriptor$8(member, env) { - return { - get: function() { - return undefined; - }, +function appendEnumeration(enumeration, name, item) { + if (name !== undefined) { + // enum can have static variables + if (item instanceof enumeration) { + // attach name to item so tagged union code can quickly find it + defineProperties$8(item, { [NAME$8]: { value: name } }); + // call toPrimitive directly since enum can be bigint or number + const index = item[Symbol.toPrimitive](); + defineProperties$8(enumeration, { + [index]: { value: item }, + [name]: { value: item }, + }); + } + } else { + // non-exhaustive enum + defineProperties$8(enumeration, { [MORE$8]: { value: true } }); } } -function getBoolDescriptor$8(member, env) { - return getDescriptorUsing$8(member, env, getBoolAccessor$8) -} - -function getIntDescriptor$8(member, env) { - const getDataViewAccessor = addRuntimeCheck$8(env, getNumericAccessor$8); - return getDescriptorUsing$8(member, env, getDataViewAccessor) -} - -function getUintDescriptor$8(member, env) { - const getDataViewAccessor = addRuntimeCheck$8(env, getNumericAccessor$8); - return getDescriptorUsing$8(member, env, getDataViewAccessor) -} - -function addRuntimeCheck$8(env, getDataViewAccessor) { - return function (access, member) { - const { - runtimeSafety = true, - } = env; - const accessor = getDataViewAccessor(access, member); - if (runtimeSafety && access === 'set') { - const { min, max } = getIntRange$8(member); - return function(offset, value, littleEndian) { - if (value < min || value > max) { - throwOverflow$8(member, value); +function defineErrorUnion$8(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const { get: getValue, set: setValue } = getDescriptor$8(members[0], env); + const { get: getError, set: setError } = getDescriptor$8(members[1], env); + const get = function() { + const errNum = getError.call(this, 'number'); + if (errNum) { + throw getError.call(this); + } else { + return getValue.call(this); + } + }; + const isValueVoid = members[0].type === MemberType$8.Void; + const TargetError = members[1].structure.constructor[CLASS]; + const isChildActive = function() { + return !getError.call(this, 'number'); + }; + const clearValue = function() { + this[RESETTER$8](); + this[POINTER_VISITOR$8]?.(resetPointer$8); + }; + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); + if (hasPointer) { + if (isChildActive.call(this)) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); } - accessor.call(this, offset, value, littleEndian); - }; + } + } else if (arg instanceof TargetError) { + setError.call(this, arg); + clearValue.call(this); + } else if (arg !== undefined || isValueVoid) { + try { + // call setValue() first, in case it throws + setValue.call(this, arg); + setError.call(this, 0, 'number'); + } catch (err) { + if (arg instanceof Error) { + // we give setValue a chance to see if the error is actually an acceptable value + // now is time to throw an error + throwNotInErrorSet$8(structure); + } else if (isErrorJSON(arg)) { + setError.call(this, arg); + clearValue.call(this); + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throw err; + } + } else { + throw err; + } + } } - return accessor; + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; + const instanceDescriptors = { + '$': { get, set: initializer }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [RESETTER$8]: { value: getMemoryResetter$8(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, { isChildActive }) }, + [NORMALIZER$8]: { value: normalizeValue$8 }, + }; + const staticDescriptors = { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } -function getFloatDescriptor$8(member, env) { - return getDescriptorUsing$8(member, env, getNumericAccessor$8) +function defineOpaque$8(structure, env) { + const { + byteSize, + align, + } = structure; + const initializer = function() { + throwCreatingOpaque$8(structure); + }; + const valueAccessor = function() { + throwAccessingOpaque$8(structure); + }; + const toPrimitive = function(hint) { + const { name } = structure; + return `[opaque ${name}]`; + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const instanceDescriptors = { + $: { get: valueAccessor, set: valueAccessor }, + dataView: getDataViewDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [Symbol.toPrimitive]: { value: toPrimitive }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: normalizeOpaque$8 }, + }; + const staticDescriptors = { + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } - -function getValueDescriptor$8(member, env) { - // enum can be int or uint--need the type from the structure - const { type, structure } = member.structure.instance.members[0]; - // combine that with the offset/size - const valueMember = { ...member, type, structure }; - return getDescriptor$8(valueMember, env); +function normalizeOpaque$8(cb) { + return {}; } -function getEnumerationItemDescriptor$8(member, env) { - const { structure } = member; - const { get: getValue, set: setValue } = getValueDescriptor$8(member, env); - const findEnum = function(value) { - const { constructor } = structure; - // the enumeration constructor returns the object for the int value - const item = (value instanceof constructor) ? value : constructor(value); - if (!item) { - throwEnumExpected$8(structure, value); +function defineOptional$8(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const { get: getValue, set: setValue } = getDescriptor$8(members[0], env); + const { get: getPresent, set: setPresent } = getDescriptor$8(members[1], env); + const hasPresentFlag = !(members[0].bitSize > 0 && members[0].bitOffset === members[1].bitOffset); + const get = function() { + const present = getPresent.call(this); + if (present) { + return getValue.call(this); + } else { + this[POINTER_VISITOR$8]?.(resetPointer$8); + return null; } - return item }; - return { - get: (getValue.length === 0) - ? function getEnum() { - const value = getValue.call(this); - return findEnum(value); - } - : function getEnumElement(index) { - const value = getValue.call(this, index); - return findEnum(value); - }, - set: (setValue.length === 1) - ? function setEnum(value) { - // call Symbol.toPrimitive directly as enum can be bigint or number - const item = findEnum(value); - setValue.call(this, item[Symbol.toPrimitive]()); + const isValueVoid = members[0].type === MemberType$8.Void; + const isChildActive = getPresent; + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); + if (hasPointer) { + // don't bother copying pointers when it's empty + if (isChildActive.call(arg)) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } + } else if (arg === null) { + setPresent.call(this, false); + this[RESETTER$8]?.(); + // clear references so objects can be garbage-collected + this[POINTER_VISITOR$8]?.(resetPointer$8); + } else if (arg !== undefined || isValueVoid) { + // call setValue() first, in case it throws + setValue.call(this, arg); + if (hasPresentFlag || !env.inFixedMemory(this)) { + // since setValue() wouldn't write address into memory when the pointer is in + // relocatable memory, we need to use setPresent() in order to write something + // non-zero there so that we know the field is populated + setPresent.call(this, true); } - : function setEnumElement(index, value) { - const item = findEnum(value); - setValue.call(this, index, item[Symbol.toPrimitive]()); - }, + } + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const instanceDescriptors = { + $: { get, set: initializer }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + // no need to reset the value when it's a pointer, since setPresent() would null out memory used by the pointer + [RESETTER$8]: !hasPointer && { value: getMemoryResetter$8(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, { isChildActive }) }, + [NORMALIZER$8]: { value: normalizeValue$8 }, + }; + const staticDescriptors = { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } -function getErrorDescriptor$8(member, env) { - const { structure } = member; - const { name } = structure; - const { get: getValue, set: setValue } = getValueDescriptor$8(member, env); - const acceptAny = name === 'anyerror'; - const globalErrorSet = getGlobalErrorSet$8(); - const findError = function(value, allowZero = false) { - const { constructor } = structure; - let item; - if (value === 0 && allowZero) { - return; - } else if (value instanceof Error) { - if (value instanceof (acceptAny ? globalErrorSet : constructor)) { - item = value; - } else { - throwNotInErrorSet$8(structure); - } +function definePrimitive$8(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { get, set } = getDescriptor$8(member, env); + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); } else { - item = acceptAny ? globalErrorSet[value] : constructor(value); - if (!item) { - throwErrorExpected$8(structure, value); - } + if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + const type = getPrimitiveType$8(member); + throwInvalidInitializer$8(structure, type, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } } - return item }; - return { - get: (getValue.length === 0) - ? function getError(allowZero) { - const value = getValue.call(this); - return findError(value, allowZero); - } - : function getErrorElement(index) { - const value = getValue.call(this, index); - return findError(value, false); - }, - set: (setValue.length === 1) - ? function setError(value, allowZero) { - const item = findError(value, allowZero); - setValue.call(this, Number(item ?? 0)); - } - : function setError(index, value) { - const item = findError(value, false); - setValue.call(this, index, Number(item)); - }, + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [Symbol.toPrimitive]: { value: get }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: normalizeValue$8 }, }; + const staticDescriptors = { + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } - -function isValueExpected$8(structure) { - switch (structure.type) { - case StructureType$8.Primitive: - case StructureType$8.ErrorUnion: - case StructureType$8.Optional: - case StructureType$8.Enumeration: - case StructureType$8.ErrorSet: - return true; - default: - return false; - } -} - -function getValue$8(slot) { - const object = this[SLOTS$8][slot] ?? this[VIVIFICATOR$8](slot); - return object[GETTER$8](); -} - -function getObject$8(slot) { - const object = this[SLOTS$8][slot] ?? this[VIVIFICATOR$8](slot); - return object; -} - -function setValue$8(slot, value) { - const object = this[SLOTS$8][slot] ?? this[VIVIFICATOR$8](slot); - object[SETTER$8](value); -} - -function bindSlot$8(slot, { get, set }) { - if (slot !== undefined) { - return { - get: function() { - return get.call(this, slot); - }, - set: (set) - ? function(arg) { - return set.call(this, slot, arg); - } - : undefined, - }; +function getIntRange$8(member) { + const { type, bitSize } = member; + const signed = (type === MemberType$8.Int); + let magBits = (signed) ? bitSize - 1 : bitSize; + if (bitSize <= 32) { + const max = 2 ** magBits - 1; + const min = (signed) ? -(2 ** magBits) : 0; + return { min, max }; } else { - // array accessors - return { get, set }; + magBits = BigInt(magBits); + const max = 2n ** magBits - 1n; + const min = (signed) ? -(2n ** magBits) : 0n; + return { min, max }; } } -function getObjectDescriptor$8(member, env) { - const { structure, slot } = member; - return bindSlot$8(slot, { - get: isValueExpected$8(structure) ? getValue$8 : getObject$8, - set: setValue$8, - }); -} - -function getType$8(slot) { - // unsupported types will have undefined structure - const structure = this[SLOTS$8][slot]; - return structure?.constructor; -} - -function getTypeDescriptor$8(member, env) { - const { slot } = member; - return bindSlot$8(slot, { get: getType$8 }); -} - -function getComptimeDescriptor$8(member, env) { - const { slot, structure } = member; - return bindSlot$8(slot, { - get: isValueExpected$8(structure) ? getValue$8 : getObject$8, - }); +function getPrimitiveClass$8({ type, bitSize }) { + if (type === MemberType$8.Int || type === MemberType$8.Uint) { + if (bitSize <= 32) { + return Number; + } else { + return BigInt; + } + } else if (type === MemberType$8.Float) { + return Number; + } else if (type === MemberType$8.Bool) { + return Boolean; + } } -function getStaticDescriptor$8(member, env) { - const { slot, structure } = member; - return bindSlot$8(slot, { - get: isValueExpected$8(structure) ? getValue$8 : getObject$8, - set: setValue$8, - }); +function getPrimitiveType$8(member) { + const Primitive = getPrimitiveClass$8(member); + if (Primitive) { + return typeof(Primitive(0)); + } } -function getLiteral$8(slot) { - const object = this[SLOTS$8][slot]; - return object.string; +function defineSlice$8(structure, env) { + const { + align, + instance: { + members: [ member ], + }, + hasPointer, + } = structure; + const { get, set } = getDescriptor$8(member, env); + const { byteSize: elementSize, structure: elementStructure } = member; + const sentinel = getSentinel$8(structure, env); + if (sentinel) { + // zero-terminated strings aren't expected to be commonly used + // so we're not putting this prop into the standard structure + structure.sentinel = sentinel; + } + const hasStringProp = canBeString$8(member); + const shapeDefiner = function(dv, length, fixed = false) { + if (!dv) { + dv = env.allocateMemory(length * elementSize, align, fixed); + } + this[MEMORY$8] = dv; + this[LENGTH$8] = length; + }; + const shapeChecker = function(arg, length) { + if (length !== this[LENGTH$8]) { + throwArrayLengthMismatch$8(structure, this, arg); + } + }; + // the initializer behave differently depending on whether it's called by the + // constructor or by a member setter (i.e. after object's shape has been established) + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg, fixed = false) { + if (arg instanceof constructor) { + if (!this[MEMORY$8]) { + shapeDefiner.call(this, null, arg.length, fixed); + } else { + shapeChecker.call(this, arg, arg.length); + } + this[COPIER$8](arg); + if (hasPointer) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } else if (typeof(arg) === 'string' && hasStringProp) { + initializer.call(this, { string: arg }, fixed); + } else if (arg?.[Symbol.iterator]) { + arg = transformIterable$8(arg); + if (!this[MEMORY$8]) { + shapeDefiner.call(this, null, arg.length, fixed); + } else { + shapeChecker.call(this, arg, arg.length); + } + let i = 0; + for (const value of arg) { + sentinel?.validateValue(value, i, arg.length); + set.call(this, i++, value); + } + } else if (typeof(arg) === 'number') { + if (!this[MEMORY$8] && arg >= 0 && isFinite(arg)) { + shapeDefiner.call(this, null, arg); + } else { + throwInvalidArrayInitializer$8(structure, arg, !this[MEMORY$8]); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$8(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$8(structure, arg); + } + }; + const finalizer = createArrayProxy$8; + const constructor = structure.constructor = createConstructor$8(structure, { initializer, shapeDefiner, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); + const hasObject = member.type === MemberType$8.Object; + const shapeHandlers = { shapeDefiner }; + const instanceDescriptors = { + $: { get: getProxy$8, set: initializer }, + length: { get: getLength$8 }, + dataView: getDataViewDescriptor$8(structure, shapeHandlers), + base64: getBase64Descriptor$8(structure, shapeHandlers), + string: hasStringProp && getStringDescriptor$8(structure, shapeHandlers), + typedArray: typedArray && getTypedArrayDescriptor$8(structure, shapeHandlers), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$8 }, + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [Symbol.iterator]: { value: getArrayIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(elementSize, true) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$g(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$g() }, + [NORMALIZER$8]: { value: normalizeArray$8 }, + }; + const staticDescriptors = { + child: { get: () => elementStructure.constructor }, + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: elementSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } -function getLiteralDescriptor$8(member, env) { - const { slot } = member; - return bindSlot$8(slot, { get: getLiteral$8 }); +function getLength$8() { + return this[LENGTH$8]; } -function getDescriptorUsing$8(member, env, getDataViewAccessor) { +function getSentinel$8(structure, env) { const { - littleEndian = true, + runtimeSafety = true, } = env; - const { bitOffset, byteSize } = member; - const getter = getDataViewAccessor('get', member); - const setter = getDataViewAccessor('set', member); - if (bitOffset !== undefined) { - const offset = bitOffset >> 3; - return { - get: function getValue() { - /* WASM-ONLY */ - try { - /* WASM-ONLY-END*/ - return getter.call(this[MEMORY$8], offset, littleEndian); - /* WASM-ONLY */ - } catch (err) { - if (err instanceof TypeError && restoreMemory$8.call(this)) { - return getter.call(this[MEMORY$8], offset, littleEndian); - } else { - throw err; - } - } - /* WASM-ONLY-END*/ - }, - set: function setValue(value) { - /* WASM-ONLY */ - try { - /* WASM-ONLY-END*/ - return setter.call(this[MEMORY$8], offset, value, littleEndian); - /* WASM-ONLY */ - } catch (err) { - if (err instanceof TypeError && restoreMemory$8.call(this)) { - return setter.call(this[MEMORY$8], offset, value, littleEndian); - } else { - throw err; - } - } - /* WASM-ONLY-END*/ + const { + byteSize, + instance: { members: [ member, sentinel ], template }, + } = structure; + if (!sentinel) { + return; + } + const { get: getSentinelValue } = getDescriptor$8(sentinel, env); + const value = getSentinelValue.call(template, 0); + const { get } = getDescriptor$8(member, env); + const validateValue = (runtimeSafety) ? function(v, i, l) { + if (v === value && i !== l - 1) { + throwMisplacedSentinel$8(structure, v, i, l); + } else if (v !== value && i === l - 1) { + throwMissingSentinel$8(structure, value, i); + } + } : function(v, i, l) { + if (v !== value && i === l - 1) { + throwMissingSentinel$8(structure, value, l); + } + }; + const validateData = (runtimeSafety) ? function(source, len) { + for (let i = 0; i < len; i++) { + const v = get.call(source, i); + if (v === value && i !== len - 1) { + throwMisplacedSentinel$8(structure, value, i, len); + } else if (v !== value && i === len - 1) { + throwMissingSentinel$8(structure, value, len); } } - } else { - return { - get: function getElement(index) { - try { - return getter.call(this[MEMORY$8], index * byteSize, littleEndian); - } catch (err) { - /* WASM-ONLY */ - if (err instanceof TypeError && restoreMemory$8.call(this)) { - return getter.call(this[MEMORY$8], index * byteSize, littleEndian); + } : function(source, len) { + if (len * byteSize === source[MEMORY$8].byteLength) { + const i = len - 1; + const v = get.call(source, i); + if (v !== value) { + throwMissingSentinel$8(structure, value, len); + } + } + }; + const bytes = template[MEMORY$8]; + return { value, bytes, validateValue, validateData }; +} + +function defineUnionShape$8(structure, env) { + const { + type, + byteSize, + align, + instance: { members, template }, + hasPointer, + } = structure; + const { runtimeSafety } = env; + const isTagged = (type === StructureType$8.TaggedUnion); + const exclusion = (isTagged || (type === StructureType$8.BareUnion && runtimeSafety)); + const memberDescriptors = {}; + const memberInitializers = {}; + const memberValueGetters = {}; + const valueMembers = (exclusion) ? members.slice(0, -1) : members; + const selectorMember = (exclusion) ? members[members.length - 1] : null; + const { get: getSelector, set: setSelector } = (exclusion) ? getDescriptor$8(selectorMember, env) : {}; + const getActiveField = (isTagged) + ? function() { + const item = getSelector.call(this); + return item[NAME$8]; + } + : function() { + const index = getSelector.call(this); + return valueMembers[index].name; + }; + const setActiveField = (isTagged) + ? function(name) { + const { constructor } = selectorMember.structure; + setSelector.call(this, constructor[name]); + } + : function(name) { + const index = valueMembers.findIndex(m => m.name === name); + setSelector.call(this, index); + }; + for (const member of valueMembers) { + const { name } = member; + const { get: getValue, set: setValue } = getDescriptor$8(member, env); + const get = (exclusion) + ? function() { + const currentName = getActiveField.call(this); + if (name !== currentName) { + if (isTagged) { + // tagged union allows inactive member to be queried + return null; } else { - /* WASM-ONLY-END */ - rethrowRangeError$8(member, index, err); - /* WASM-ONLY */ + // whereas bare union does not, since the condition is not detectable + // when runtime safety is off + throwInactiveUnionProperty$8(structure, name, currentName); } - /* WASM-ONLY-END */ } - }, - set: function setElement(index, value) { - /* WASM-ONLY */ - try { - /* WASM-ONLY-END */ - return setter.call(this[MEMORY$8], index * byteSize, value, littleEndian); - /* WASM-ONLY */ - } catch (err) { - if (err instanceof TypeError && restoreMemory$8.call(this)) { - return setter.call(this[MEMORY$8], index * byteSize, value, littleEndian); - } else { - rethrowRangeError$8(member, index, err); - } + this[POINTER_VISITOR$8]?.(resetPointer$8); + return getValue.call(this); + } + : getValue; + const set = (exclusion && setValue) + ? function(value) { + const currentName = getActiveField.call(this); + if (name !== currentName) { + throwInactiveUnionProperty$8(structure, name, currentName); } - /* WASM-ONLY-END */ - }, - } - } -} - -function useAllMemberTypes$8() { - useVoid$8(); - useNull$8(); - useUndefined$8(); - useBool$8(); - useInt$8(); - useUint$8(); - useFloat$8(); - useEnumerationItem$8(); - useError$8(); - useObject$8(); - useType$8(); - useComptime$8(); - useStatic$8(); - useLiteral$8(); -} - -function generateCode(definition, params) { - const { structures, options, keys } = definition; - const { - runtimeURL, - binarySource = null, - topLevelAwait = true, - omitExports = false, - declareFeatures = false, - addonDir = null, - } = params; - const features = (declareFeatures) ? getFeaturesUsed(structures) : []; - const exports = getExports(structures); - const lines = []; - const add = manageIndentation(lines); - add(`import {`); - for (const name of [ 'createEnvironment', ...features ]) { - add(`${name},`); - } - add(`} from ${JSON.stringify(runtimeURL)};`); - // reduce file size by only including code of features actually used - // dead-code remover will take out code not referenced here - add(`\n// activate features`); - for (const feature of features) { - add(`${feature}();`); - } - // write out the structures as object literals - addStructureDefinitions(lines, definition); - add(`\n// create runtime environment`); - add(`const env = createEnvironment(${addonDir ? JSON.stringify({ addonDir }, undefined, 2) : null});`); - add(`const __zigar = env.getControlObject();`); - add(`\n// recreate structures`); - add(`env.recreateStructures(structures, options);`); - if (binarySource) { - add(`\n// initiate loading and compilation of WASM bytecodes`); - add(`const source = ${binarySource};`); - add(`env.loadModule(source)`); - // if top level await is used, we don't need to write changes into fixed memory buffers - add(`env.linkVariables(${!topLevelAwait});`); - } - add(`\n// export root namespace and its methods and constants`); - add(`const { constructor } = root;`); - if (!omitExports) { - add(`export { constructor as default, __zigar }`); - // the first two exports are default and __zigar - const exportables = exports.slice(2); - if (exportables.length > 0) { - add(`export const {`); - for (const name of exportables) { - add(`${name},`); + setValue.call(this, value); } - add(`} = constructor;`); - } - } - if (topLevelAwait && binarySource) { - add(`await __zigar.init();`); + : setValue; + const init = (exclusion && setValue) + ? function(value) { + setActiveField.call(this, name); + setValue.call(this, value); + this[POINTER_VISITOR$8]?.(resetPointer$8); + } + : setValue; + memberDescriptors[name] = { get, set, configurable: true, enumerable: true }; + memberInitializers[name] = init; + memberValueGetters[name] = getValue; } - const code = lines.join('\n'); - return { code, exports, structures }; -} - -function addStructureDefinitions(lines, definition) { - const { structures, options, keys } = definition; - const { MEMORY, SLOTS, CONST } = keys; - const add = manageIndentation(lines); - const defaultStructure = { - constructor: null, - typedArray: null, - type: StructureType$8.Primitive, - name: undefined, - byteSize: 0, - align: 0, - isConst: false, - hasPointer: false, - instance: { - members: [], - methods: [], - template: null, - }, - static: { - members: [], - methods: [], - template: null, - }, - }; - add(`\n// structure defaults`); - add(`const s = {`); - for (const [ name, value ] of Object.entries(defaultStructure)) { - switch (name) { - case 'instance': - case 'static': - add(`${name}: {`); - for (const [ name2, value2 ] of Object.entries(value)) { - add(`${name2}: ${JSON.stringify(value2)},`); + const hasDefaultMember = !!valueMembers.find(m => !m.isRequired); + const memberKeys = Object.keys(memberDescriptors); + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + /* WASM-ONLY-END */ + this[COPIER$8](arg); + if (hasPointer) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } else if (arg && typeof(arg) === 'object') { + let found = 0; + for (const key of memberKeys) { + if (key in arg) { + found++; } - add(`},`); - break; - default: - add(`${name}: ${JSON.stringify(value)},`); + } + if (found > 1) { + throwMultipleUnionInitializers$8(structure); + } + if (propApplier.call(this, arg) === 0 && !hasDefaultMember) { + throwMissingUnionInitializer$8(structure, arg, exclusion); + } + } else if (arg !== undefined) { + throwInvalidInitializer$8(structure, 'object with a single property', arg); } - } - add(`};`); - const defaultMember = { - type: MemberType$8.Void, - isRequired: false, }; - add(`\n// member defaults`); - add(`const m = {`); - for (const [ name, value ] of Object.entries(defaultMember)) { - add(`${name}: ${JSON.stringify(value)},`); - } - add(`};`); - // create empty objects first, to allow objects to reference each other - add(``); - const structureNames = new Map(); - const structureMap = new Map(); - for (const [ index, structure ] of structures.entries()) { - const varname = `s${index}`; - structureNames.set(structure, varname); - structureMap.set(structure.constructor, structure); - } - for (const slice of chunk(structureNames.values(), 10)) { - add(`const ${slice.map(n => `${n} = {}`).join(', ')};`); - } - const objects = findAllObjects(structures, SLOTS); - const objectNames = new Map(); - const views = []; - for (const [ index, object ] of objects.entries()) { - const varname = `o${index}`; - objectNames.set(object, varname); - if (object[MEMORY]) { - views.push(object[MEMORY]); + // non-tagged union as marked as not having pointers--if there're actually + // members with pointers, we need to disable them + const pointerMembers = members.filter(m => m.structure.hasPointer); + const hasInaccessiblePointer = !hasPointer && (pointerMembers.length > 0); + const modifier = (hasInaccessiblePointer && !env.comptime) + ? function() { + // make pointer access throw + this[POINTER_VISITOR$8](disablePointer$8, { vivificate: true }); + } + : undefined; + const constructor = structure.constructor = createConstructor$8(structure, { modifier, initializer }, env); + const fieldDescriptor = (isTagged) + ? { + // for tagged union, only the active field + get() { return [ getActiveField.call(this) ] } + } + : { + // for bare and extern union, all members are included + value: valueMembers.map(m => m.name) + }; + const isChildActive = (isTagged) + ? function(child) { + const name = getActiveField.call(this); + const active = memberValueGetters[name].call(this); + return child === active; + } + : never$8; + const hasAnyPointer = hasPointer || hasInaccessiblePointer; + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const instanceDescriptors = { + $: { get: getSelf$8, set: initializer, configurable: true }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getUnionIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [TAG$8]: isTagged && { get: getSelector, configurable: true }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasAnyPointer && { value: getPointerVisitor$h(structure, { isChildActive }) }, + [PROP_GETTERS$8]: { value: memberValueGetters }, + [NORMALIZER$8]: { value: normalizeUnion$8 }, + [PROPS$8]: fieldDescriptor, + }; + const staticDescriptors = { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); + // replace regular setters with ones that change the active field + const setters = constructor.prototype[PROP_SETTERS$8]; + for (const [ name, init ] of Object.entries(memberInitializers)) { + if (init) { + setters[name] = init; } } - for (const slice of chunk(objectNames.values(), 10)) { - add(`const ${slice.map(n => `${n} = {}`).join(', ')};`); +} +function normalizeUnion$8(cb, options) { + const object = {}; + for (const [ name, value ] of getUnionEntries$8.call(this, options)) { + object[name] = cb(value); } - // define buffers - const arrayBufferNames = new Map(); - for (const [ index, dv ] of views.entries()) { - if (!arrayBufferNames.get(dv.buffer)) { - const varname = `a${index}`; - arrayBufferNames.set(dv.buffer, varname); - if (dv.buffer.byteLength > 0) { - const ta = new Uint8Array(dv.buffer); - add(`const ${varname} = new Uint8Array([ ${ta.join(', ')} ]);`); + return object; +} + +function getUnionEntries$8(options) { + return { + [Symbol.iterator]: getUnionEntriesIterator$8.bind(this, options), + length: this[PROPS$8].length, + }; +} + +function getUnionIterator$8(options) { + const entries = getUnionEntries$8.call(this, options); + return entries[Symbol.iterator](); +} + +function getUnionEntriesIterator$8(options) { + const self = this; + const props = this[PROPS$8]; + const getters = this[PROP_GETTERS$8]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + // get value of prop with no check + value = [ current, handleError$8(() => getters[current].call(self), options) ]; + done = false; } else { - add(`const ${varname} = new Uint8Array();`); + done = true; } - } + return { value, done }; + }, + }; +} + +function defineVector$8(structure, env) { + const { + length, + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { bitSize: elementBitSize, structure: elementStructure } = member; + const elementDescriptors = {}; + for (let i = 0, bitOffset = 0; i < length; i++, bitOffset += elementBitSize) { + const { get, set } = getDescriptor$8({ ...member, bitOffset }, env); + elementDescriptors[i] = { get, set, configurable: true }; } - // add properties to objects - if (objects.length > 0) { - add('\n// define objects'); - for (const object of objects) { - const varname = objectNames.get(object); - const structure = structureMap.get(object.constructor); - const { [MEMORY]: dv, [SLOTS]: slots } = object; - add(`Object.assign(${varname}, {`); - if (structure) { - add(`structure: ${structureNames.get(structure)},`); - } - if (dv) { - const buffer = arrayBufferNames.get(dv.buffer); - const pairs = [ `array: ${buffer}` ]; - if (dv.byteLength < dv.buffer.byteLength) { - pairs.push(`offset: ${dv.byteOffset}`); - pairs.push(`length: ${dv.byteLength}`); - } - add(`memory: { ${pairs.join(', ')} },`); - if (dv.hasOwnProperty('reloc')) { - add(`reloc: ${dv.reloc},`); - if (object[CONST]) { - add(`const: true,`); - } - } + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); + } else if (arg?.[Symbol.iterator]) { + let argLen = arg.length; + if (typeof(argLen) !== 'number') { + arg = [ ...arg ]; + argLen = arg.length; } - const entries = (slots) ? Object.entries(slots).filter(a => a[1]) : []; - if (entries.length > 0) { - add(`slots: {`); - const pairs = entries.map(([slot, child]) => `${slot}: ${objectNames.get(child)}`); - for (const slice of chunk(pairs, 10)) { - add(slice.join(', ') + ','); - } - add(`},`); + if (argLen !== length) { + throwArrayLengthMismatch$8(structure, this, arg); } - add(`});`); - } - } - const methods = []; - for (const structure of structures) { - // add static members; instance methods are also static methods, so - // we don't need to add them separately - methods.push(...structure.static.methods); - } - const methodNames = new Map(); - if (methods.length > 0) { - add(`\n// define functions`); - for (const [ index, method ] of methods.entries()) { - const varname = `f${index}`; - methodNames.set(method, varname); - add(`const ${varname} = {`); - for (const [ name, value ] of Object.entries(method)) { - switch (name) { - case 'argStruct': - add(`${name}: ${structureNames.get(value)},`); - break; - default: - add(`${name}: ${JSON.stringify(value)},`); - } + let i = 0; + for (const value of arg) { + this[PROP_SETTERS$8][i++].call(this, value); } - add(`};`); - } - } - add('\n// define structures'); - for (const structure of structures) { - const varname = structureNames.get(structure); - add(`Object.assign(${varname}, {`); - add(`...s,`); - for (const [ name, value ] of Object.entries(structure)) { - if (isDifferent(value, defaultStructure[name])) { - switch (name) { - case 'constructor': - case 'typedArray': - case 'sentinel': - break; - case 'instance': - case 'static': { - const { methods, members, template } = value; - add(`${name}: {`); - add(`members: [`); - for (const member of members) { - add(`{`); - add(`...m,`); - for (const [ name, value ] of Object.entries(member)) { - if (isDifferent(value, defaultMember[name])) { - switch (name) { - case 'structure': - add(`${name}: ${structureNames.get(value)},`); - break; - default: - add(`${name}: ${JSON.stringify(value)},`); - } - } - } - add(`},`); - } - add(`],`); - add(`methods: [`); - for (const slice of chunk(methods, 10)) { - add(slice.map(m => methodNames.get(m)).join(', ') + ','); - } - add(`],`); - if (template) { - add(`template: ${objectNames.get(template)}`); - } - add(`},`); - } break; - default: - add(`${name}: ${JSON.stringify(value)},`); - } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$8(structure, arg); } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$8(structure, arg); } - add(`});`); - } - add(`const structures = [`); - for (const slice of chunk([ ...structureNames.values() ], 10)) { - add(slice.join(', ') + ','); - } - add(`];`); - const root = structures[structures.length - 1]; - add(`const root = ${structureNames.get(root)};`); - add(`const options = {`); - for (const [ name, value ] of Object.entries(options)) { - add(`${name}: ${value},`); + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); + const instanceDescriptors = { + ...elementDescriptors, + $: { get: getSelf$8, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + entries: { value: getVectorEntries$8 }, + delete: { value: getDestructor$8(structure) }, + [Symbol.iterator]: { value: getVectorIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: normalizeVector$8 }, + }; + const staticDescriptors = { + child: { get: () => elementStructure.constructor }, + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizeVector$8(cb, options) { + const array = []; + for (const [ index, value ] of getVectorEntries$8.call(this, options)) { + array.push(cb(value)); } - add(`};`); - return lines; + return array; +} + +function getVectorIterator$8() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self[current]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; } -function getExports(structures) { - const root = structures[structures.length - 1]; - const { constructor } = root; - const exportables = []; - // export only members whose names are legal JS identifiers - const legal = /^[$\w]+$/; - for (const method of root.static.methods) { - if (legal.test(method.name)) { - exportables.push(method.name); - } - } - for (const member of root.static.members) { - // only read-only properties are exportable - if (isReadOnly$8(member.type) && legal.test(member.name)) { - try { - // make sure that getter wouldn't throw (possible with error union) - constructor[member.name]; - exportables.push(member.name); - } catch (err) { +function getVectorEntriesIterator$8() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, self[current] ]; + done = false; + } else { + done = true; } - } - } - return [ 'default', '__zigar', ...exportables ]; + return { value, done }; + }, + }; } -function manageIndentation(lines) { - let indent = 0; - return (s) => { - if (/^\s*[\]\}]/.test(s)) { - indent--; - } - const lastLine = lines[lines.length - 1]; - if ((lastLine?.endsWith('[') && s.startsWith(']')) - || (lastLine?.endsWith('{') && s.startsWith('}'))) { - lines[lines.length - 1] += s; - } else { - lines.push(' '.repeat(indent * 2) + s); - } - if (/[\[\{]\s*$/.test(s)) { - indent++; - } +function getVectorEntries$8() { + return { + [Symbol.iterator]: getVectorEntriesIterator$8.bind(this), + length: this.length, }; } -function isDifferent(value, def) { - if (value === def) { - return false; - } - if (def == null) { - return value != null; - } - if (typeof(def) === 'object' && typeof(value) === 'object') { - const valueKeys = Object.keys(value); - const defKeys = Object.keys(def); - if (valueKeys.length !== defKeys.length) { - return true; - } - for (const key of defKeys) { - if (isDifferent(value[key], def[key])) { - return true; - } - } - return false; - } - return true; +const StructureType$8 = { + Primitive: 0, + Array: 1, + Struct: 2, + ExternStruct: 3, + PackedStruct: 4, + ArgStruct: 5, + ExternUnion: 6, + BareUnion: 7, + TaggedUnion: 8, + ErrorUnion: 9, + ErrorSet: 10, + Enumeration: 11, + Optional: 12, + Pointer: 13, + Slice: 14, + Vector: 15, + Opaque: 16, + Function: 17, +}; + +const factories$q = Array(Object.values(StructureType$8).length); + +function usePrimitive$8() { + factories$q[StructureType$8.Primitive] = definePrimitive$8; } -function* chunk(arr, n) { - if (!Array.isArray(arr)) { - arr = [ ...arr ]; - } - for (let i = 0; i < arr.length; i += n) { - yield arr.slice(i, i + n); - } +function useArray$8() { + factories$q[StructureType$8.Array] = defineArray$8; } -async function findFile(path, follow = true) { - try { - return await (follow ? promises.stat(path) : promises.lstat(path)); - } catch (err) { - } +function useStruct$8() { + factories$q[StructureType$8.Struct] = defineStructShape$8; } -function findFileSync(path, follow = true) { - try { - return follow ? fs.statSync(path) : fs.lstatSync(path); - } catch (err) { - } +function usePackedStruct$8() { + factories$q[StructureType$8.PackedStruct] = defineStructShape$8; } -async function findMatchingFiles(dir, re) { - const map = new Map(); - const scanned = new Map(); - const scan = async (dir) => { - /* c8 ignore next 3 */ - if (scanned.get(dir)) { - return; - } - scanned.set(dir, true); - try { - const list = await promises.readdir(dir); - for (const name of list) { - if (name.startsWith('.') || name === 'node_modules' || name === 'zig-cache') { - continue; - } - const path$1 = path.join(dir, name); - const info = await findFile(path$1); - if (info?.isDirectory()) { - await scan(path$1); - } else if (info?.isFile() && re.test(name)) { - map.set(path$1, info); - } - } - /* c8 ignore next 2 */ - } catch (err) { - } - }; - await scan(dir); - return map; +function useExternStruct$8() { + factories$q[StructureType$8.ExternStruct] = defineStructShape$8; } -function findMatchingFilesSync(dir, re) { - const map = new Map(); - const scanned = new Map(); - const scan = (dir) => { - /* c8 ignore next 3 */ - if (scanned.get(dir)) { - return; - } - scanned.set(dir, true); - try { - const list = fs.readdirSync(dir); - for (const name of list) { - if (name.startsWith('.') || name === 'node_modules' || name === 'zig-cache') { - continue; - } - const path$1 = path.join(dir, name); - const info = findFileSync(path$1); - if (info?.isDirectory()) { - scan(path$1); - } else if (info?.isFile() && re.test(name)) { - map.set(path$1, info); - } - } - /* c8 ignore next 2 */ - } catch (err) { - } - }; - scan(dir); - return map; +function useArgStruct$8() { + factories$q[StructureType$8.ArgStruct] = defineArgStruct$8; } -async function acquireLock(pidPath, staleTime) { - while (true) { - try { - await createDirectory(path.dirname(pidPath)); - const handle = await promises.open(pidPath, 'wx'); - handle.write(`${process.pid}`); - handle.close(); - break; - } catch (err) { - if (err.code === 'EEXIST') { - if (checkPidFile(pidPath, staleTime)) { - await delay(250); - continue; - } - } else { - throw err; - } - } - } +function useExternUnion$8() { + factories$q[StructureType$8.ExternUnion] = defineUnionShape$8; } -function acquireLockSync(pidPath, staleTime) { - while (true) { - try { - createDirectorySync(path.dirname(pidPath)); - const handle = fs.openSync(pidPath, 'wx'); - fs.writeSync(handle, `${process.pid}`); - fs.closeSync(handle); - break; - } catch (err) { - if (err.code === 'EEXIST') { - if (checkPidFile(pidPath, staleTime)) { - delaySync(250); - } - } else { - throw err; - } - } - } +function useBareUnion$8() { + factories$q[StructureType$8.BareUnion] = defineUnionShape$8; } -async function releaseLock(pidPath) { - await deleteFile(pidPath); +function useTaggedUnion$8() { + factories$q[StructureType$8.TaggedUnion] = defineUnionShape$8; +} + +function useErrorUnion$8() { + factories$q[StructureType$8.ErrorUnion] = defineErrorUnion$8; +} + +function useErrorSet$8() { + factories$q[StructureType$8.ErrorSet] = defineErrorSet$8; + useErrorSetTransform(); +} + +function useEnumeration$8() { + factories$q[StructureType$8.Enumeration] = defineEnumerationShape$8; + useEnumerationTransform(); } -function releaseLockSync(pidPath) { - deleteFileSync(pidPath); +function useOptional$8() { + factories$q[StructureType$8.Optional] = defineOptional$8; } -function checkPidFile(pidPath, staleTime = 60000 * 5) { - let stale = false; - try { - const pid = loadFileSync(pidPath); - if (os.platform() === 'win32') { - child_process.execSync(`tasklist /nh /fi "pid eq ${pid}" | findstr .exe`, { stdio: 'pipe' }).toString(); - } else { - child_process.execSync(`ps -p ${pid}`).toString(); - } - const last = findFileSync(pidPath)?.mtime || 0; - const diff = new Date() - last; - if (diff > staleTime) { - stale = true; - } - } catch (err) { - stale = true; - } - if (stale) { - deleteFileSync(pidPath); - } - return !stale; +function usePointer$8() { + factories$q[StructureType$8.Pointer] = definePointer$8; + useUint$8(); } -async function copyFile(srcPath, dstPath) { - const info = await promises.stat(srcPath); - const data = await promises.readFile(srcPath); - await promises.writeFile(dstPath, data); - await promises.chmod(dstPath, info.mode); +function useSlice$8() { + factories$q[StructureType$8.Slice] = defineSlice$8; } -function copyFileSync(srcPath, dstPath) { - const info = fs.statSync(srcPath); - const data = fs.readFileSync(srcPath); - fs.writeFileSync(dstPath, data); - fs.chmodSync(dstPath, info.mode); +function useVector$8() { + factories$q[StructureType$8.Vector] = defineVector$8; } -async function loadFile(path, def) { - try { - return await promises.readFile(path, 'utf8'); - } catch (err) { - return def; - } +function useOpaque$8() { + factories$q[StructureType$8.Opaque] = defineOpaque$8; } -function loadFileSync(path, def) { - try { - return fs.readFileSync(path, 'utf8'); - } catch (err) { - return def; +function defineProperties$8(object, descriptors) { + for (const [ name, descriptor ] of Object.entries(descriptors)) { + if (descriptor) { + const { + set, + get, + value, + enumerable, + configurable = true, + writable = true, + } = descriptor; + Object.defineProperty(object, name, (get) + ? { get, set, configurable, enumerable } + : { value, configurable, enumerable, writable } + ); + } + } + for (const symbol of Object.getOwnPropertySymbols(descriptors)) { + const descriptor = descriptors[symbol]; + if (descriptor) { + Object.defineProperty(object, symbol, descriptor); + } } } -async function deleteFile(path) { - try { - await promises.unlink(path); - } catch (err) { - if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { - throw err; +function attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors) { + // create prototype for read-only objects + const prototypeRO = {}; + Object.setPrototypeOf(prototypeRO, constructor.prototype); + const instanceDescriptorsRO = {}; + const propSetters = {}; + for (const [ name, descriptor ] of Object.entries(instanceDescriptors)) { + if (descriptor?.set) { + instanceDescriptorsRO[name] = { ...descriptor, set: throwReadOnly$8 }; + // save the setters so we can initialize read-only objects + if (name !== '$') { + propSetters[name] = descriptor.set; + } + } else if (name === 'set') { + instanceDescriptorsRO[name] = { value: throwReadOnly$8, configurable: true, writable: true }; } } + const vivificate = instanceDescriptors[VIVIFICATOR$8]?.value; + const vivificateDescriptor = { + // vivificate child objects as read-only too + value: function(slot) { + return vivificate.call(this, slot, false); + } + }; + const { get, set } = instanceDescriptors.$; + defineProperties$8(constructor.prototype, { + [CONST$8]: { value: false }, + [ALL_KEYS$8]: { value: Object.keys(propSetters) }, + [SETTER$8]: { value: set }, + [GETTER$8]: { value: get }, + [PROP_SETTERS$8]: { value: propSetters }, + ...instanceDescriptors, + }); + defineProperties$8(constructor, { + [CONST_PROTOTYPE$8]: { value: prototypeRO }, + ...staticDescriptors, + }); + defineProperties$8(prototypeRO, { + constructor: { value: constructor, configurable: true }, + [CONST$8]: { value: true }, + [SETTER$8]: { value: throwReadOnly$8 }, + [VIVIFICATOR$8]: vivificate && vivificateDescriptor, + ...instanceDescriptorsRO, + }); + return constructor; } -function deleteFileSync(path) { - try { - fs.unlinkSync(path); - } catch (err) { - if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { - throw err; - } +function createConstructor$8(structure, handlers, env) { + const { + byteSize, + align, + instance: { members, template }, + hasPointer, + } = structure; + const { + modifier, + initializer, + finalizer, + alternateCaster, + shapeDefiner, + } = handlers; + const hasSlots = needSlots$8(members); + // comptime fields are stored in the instance template's slots + let comptimeFieldSlots; + if (template?.[SLOTS$8]) { + const comptimeMembers = members.filter(m => isReadOnly$8(m.type)); + if (comptimeMembers.length > 0) { + comptimeFieldSlots = comptimeMembers.map(m => m.slot); + } } + const cache = new ObjectCache$8(); + const constructor = function(arg, options = {}) { + const { + writable = true, + fixed = false, + } = options; + const creating = this instanceof constructor; + let self, dv; + if (creating) { + if (arguments.length === 0) { + throwNoInitializer$8(structure); + } + self = this; + if (hasSlots) { + self[SLOTS$8] = {}; + } + if (shapeDefiner) { + // provided by defineSlice(); the slice is different from other structures as it does not have + // a fixed size; memory is allocated by the slice initializer based on the argument given + initializer.call(self, arg, fixed); + dv = self[MEMORY$8]; + } else { + self[MEMORY$8] = dv = env.allocateMemory(byteSize, align, fixed); + } + } else { + if (alternateCaster) { + // casting from number, string, etc. + self = alternateCaster.call(this, arg, options); + if (self !== false) { + return self; + } + } + // look for buffer + dv = requireDataView$8(structure, arg, env); + if (self = cache.find(dv, writable)) { + return self; + } + self = Object.create(writable ? constructor.prototype : constructor[CONST_PROTOTYPE$8]); + if (shapeDefiner) { + setDataView$8.call(self, dv, structure, false, { shapeDefiner }); + } else { + self[MEMORY$8] = dv; + } + if (hasSlots) { + self[SLOTS$8] = {}; + if (hasPointer && arg instanceof constructor) { + // copy pointer from other object + self[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } + } + if (comptimeFieldSlots) { + for (const slot of comptimeFieldSlots) { + self[SLOTS$8][slot] = template[SLOTS$8][slot]; + } + } + if (modifier) { + modifier.call(self); + } + if (creating) { + // initialize object unless it's been done already + if (!shapeDefiner) { + initializer.call(self, arg); + } + if (!writable) { + // create object with read-only prototype + self = Object.assign(Object.create(constructor[CONST_PROTOTYPE$8]), self); + } + } + if (finalizer) { + self = finalizer.call(self); + } + return cache.save(dv, writable, self); + }; + return constructor; } -async function createDirectory(path$1) { - const exists = await findDirectory(path$1); - if (!exists) { - const { root, dir } = path.parse(path$1); - await createDirectory(dir); - try { - await promises.mkdir(path$1); - } catch (err) { - /* c8 ignore next 3 */ - if (err.code != 'EEXIST') { - throw err; +function createPropertyApplier$8(structure) { + const { instance: { template } } = structure; + return function(arg) { + const argKeys = Object.keys(arg); + const propSetters = this[PROP_SETTERS$8]; + const allKeys = this[ALL_KEYS$8]; + // don't accept unknown props + for (const key of argKeys) { + if (!(key in propSetters)) { + throwNoProperty$8(structure, key); + } + } + // checking each name so that we would see inenumerable initializers as well + let normalCount = 0; + let normalFound = 0; + let normalMissing = 0; + let specialFound = 0; + for (const key of allKeys) { + const set = propSetters[key]; + if (set.special) { + if (key in arg) { + specialFound++; + } + } else { + normalCount++; + if (key in arg) { + normalFound++; + } else if (set.required) { + normalMissing++; + } } } - } -} - -function createDirectorySync(path$1) { - const exists = findDirectorySync(path$1); - if (!exists) { - const { root, dir } = path.parse(path$1); - createDirectorySync(dir); - try { - fs.mkdirSync(path$1); - } catch (err) { - /* c8 ignore next 3 */ - if (err.code != 'EEXIST') { - throw err; + if (normalMissing !== 0 && specialFound === 0) { + const missing = allKeys.filter(k => propSetters[k].required && !(k in arg)); + throwMissingInitializers$8(structure, missing); + } + if (specialFound + normalFound > argKeys.length) { + // some props aren't enumerable + for (const key of allKeys) { + if (key in arg) { + if (!argKeys.includes(key)) { + argKeys.push(key); + } + } } } - } -} - -async function findDirectory(path) { - return findFile(path); -} - -function findDirectorySync(path) { - return findFileSync(path); -} - -async function deleteDirectory(dir) { - try { - const list = await promises.readdir(dir); - for (const name of list) { - const path$1 = path.join(dir, name); - const info = await findFile(path$1, false); - if (info?.isDirectory()) { - await deleteDirectory(path$1); - } else if (info) { - await deleteFile(path$1); + // apply default values unless all properties are initialized + if (normalFound < normalCount && specialFound === 0) { + if (template) { + if (template[MEMORY$8]) { + this[COPIER$8](template); + } + this[POINTER_VISITOR$8]?.(copyPointer$8, { vivificate: true, source: template }); } } - await promises.rmdir(dir); - } catch (err) { - if (err.code !== 'ENOENT') { - throw err; + for (const key of argKeys) { + const set = propSetters[key]; + set.call(this, arg[key]); } - } + return argKeys.length; + }; } -function deleteDirectorySync(dir) { - try { - const list = fs.readdirSync(dir); - for (const name of list) { - const path$1 = path.join(dir, name); - const info = findFileSync(path$1, false); - if (info?.isDirectory()) { - deleteDirectorySync(path$1); - } else if (info) { - deleteFileSync(path$1); - } - } - fs.rmdirSync(dir); - } catch (err) { - if (err.code !== 'ENOENT') { - throw err; +function needSlots$8(members) { + for (const { type } of members) { + switch (type) { + case MemberType$8.Object: + case MemberType$8.Comptime: + case MemberType$8.Type: + case MemberType$8.Literal: + return true; } } + return false; } -async function delay(ms) { - await new Promise(r => setTimeout(r, ms)); +function getSelf$8() { + return this; } -function delaySync(ms) { - const buffer = new SharedArrayBuffer(8); - const ta = new BigInt64Array(buffer); - Atomics.wait(ta, 0, 0n, ms); +function useAllStructureTypes$8() { + usePrimitive$8(); + useArray$8(); + useStruct$8(); + useExternStruct$8(); + usePackedStruct$8(); + useArgStruct$8(); + useExternUnion$8(); + useBareUnion$8(); + useTaggedUnion$8(); + useErrorUnion$8(); + useErrorSet$8(); + useEnumeration$8(); + useOptional$8(); + usePointer$8(); + useSlice$8(); + useVector$8(); + useOpaque$8(); } -function md5(text) { - const hash = crypto.createHash('md5'); - hash.update(text); - return hash.digest('hex'); -} +let ObjectCache$8 = class ObjectCache { + [0] = null; + [1] = null; -let isGNU; + find(dv, writable) { + const key = (writable) ? 0 : 1; + const map = this[key]; + return map?.get(dv); + } -function getPlatform() { - let platform = os.platform(); - if (platform === 'linux') { - // differentiate glibc from musl - if (isGNU === undefined) { - /* c8 ignore next 3 */ - if (process.versions?.electron || process.__nwjs) { - isGNU = true; - } else { - try { - child_process.execFileSync('getconf', [ 'GNU_LIBC_VERSION' ], { stdio: 'pipe' }); - isGNU = true; - /* c8 ignore next 3 */ - } catch (err) { - isGNU = false; - } - } - } - /* c8 ignore next 3 */ - if (!isGNU) { - platform += '-musl'; + save(dv, writable, object) { + const key = (writable) ? 0 : 1; + let map = this[key]; + if (!map) { + map = this[key] = new WeakMap(); } + map.set(dv, object); + return object; } - return platform; -} +}; -function getArch() { - return os.arch(); -} +let currentGlobalSet; +let currentErrorClass; -function normalizePath(url$1) { - let archive; - const parts = url.fileURLToPath(url$1).split(path.sep).map((part) => { - if (part === 'app.asar') { - archive = 'asar'; - return part + '.unpacked'; +function defineErrorSet$8(structure, env) { + const { + name, + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + if (!currentErrorClass) { + currentErrorClass = class ZigError extends ZigErrorBase {}; + currentGlobalSet = defineErrorSet$8({ ...structure, name: 'anyerror' }, env); + } + if (currentGlobalSet && name === 'anyerror') { + structure.constructor = currentGlobalSet; + structure.typedArray = getTypedArrayClass$8(member); + return currentGlobalSet; + } + const errorClass = currentErrorClass; + const { get, set } = getDescriptor$8(member, env); + const expected = [ 'string', 'number' ]; + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor[CLASS]) { + set.call(this, arg); + } else if (arg && typeof(arg) === 'object' && !isErrorJSON(arg)) { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$8(structure, expected, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); } - return part; - }); - const path$1 = parts.join(path.sep); - return { path: path$1, archive } + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'number' || typeof(arg) === 'string') { + return constructor[arg]; + } else if (arg instanceof constructor[CLASS]) { + return constructor[Number(arg)]; + } else if (isErrorJSON(arg)) { + return constructor[`Error: ${arg.error}`]; + } else if (!getDataView$8(structure, arg, env)) { + throwInvalidInitializer$8(structure, expected, arg); + } else { + return false; + } + }; + // items are inserted when static members get attached in static.js + const constructor = structure.constructor = createConstructor$8(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: get }, + }; + const staticDescriptors = { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + [CLASS]: { value: errorClass }, + // the PROPS array is normally set in static.js; it needs to be set here for anyerror + // so we can add names to it as error sets are defined + [PROPS$8]: (name === 'anyerror') ? { value: [] } : undefined, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } -async function compile(srcPath, modPath, options) { - const srcInfo = (srcPath) ? await findFile(srcPath) : null; - if (srcInfo === undefined) { - throw new Error(`Source file not found: ${srcPath}`); - } - if (srcInfo?.isDirectory()) { - srcPath = path.join(srcPath, '?'); +function isErrorJSON(arg) { + return typeof(arg) === 'object' && typeof(arg.error) === 'string' && Object.keys(arg).length === 1 ; +} + +class ZigErrorBase extends Error { + constructor(name, number) { + super(deanimalizeErrorName(name)); + this.number = number; } - const config = createConfig(srcPath, modPath, options); - const { moduleDir, outputPath } = config; - let changed = false; - if (srcPath) { - const srcFileMap = await findMatchingFiles(moduleDir, /.\..*$/); - // see if the (re-)compilation is necessary - const soInfo = await findFile(outputPath); - if (soInfo) { - for (const [ name, info ] of srcFileMap) { - if (info.mtime > soInfo.mtime) { - changed = true; - break; - } - } + + [Symbol.toPrimitive](hint) { + if (hint === 'string') { + return Error.prototype.toString.call(this, hint); } else { - changed = true; - } - if (!changed) { - // rebuild when exporter or build files have changed - const zigFolder = absolute('../zig'); - const zigFileMap = await findMatchingFiles(zigFolder, /\.zig$/); - for (const [ path, info ] of zigFileMap) { - if (info.mtime > soInfo.mtime) { - changed = true; - break; - } - } + return this.number; } - if (changed) { - // add custom build file - for (const [ path$1, info ] of srcFileMap) { - switch (path.basename(path$1)) { - case 'build.zig': - config.buildFilePath = path$1; - break; - case 'build.zig.zon': - config.packageConfigPath = path$1; - break; - } - } - const { zigCmd, moduleBuildDir } = config; - // only one process can compile a given file at a time - const pidPath = `${moduleBuildDir}.pid`; - await acquireLock(pidPath); - try { - // create config file - await createProject(config, moduleBuildDir); - // then run the compiler - await runCompiler(zigCmd, moduleBuildDir); - } finally { - if (config.clean) { - await deleteDirectory(moduleBuildDir); - } - await releaseLock(pidPath); - } - } + } + + toJSON() { + return { error: this.message }; } - return { outputPath, changed } } -function compileSync(srcPath, modPath, options) { - const srcInfo = (srcPath) ? findFileSync(srcPath) : null; - if (srcInfo === undefined) { - throw new Error(`Source file not found: ${srcPath}`); +function throwNoInitializer$8(structure) { + const { name } = structure; + throw new TypeError(`An initializer must be provided to the constructor of ${name}, even when the intended value is undefined`); +} + +function throwBufferSizeMismatch$8(structure, dv, target = null) { + const { name, type, byteSize } = structure; + const actual = dv.byteLength; + const s = (byteSize !== 1) ? 's' : ''; + if (type === StructureType$8.Slice && !target) { + throw new TypeError(`${name} has elements that are ${byteSize} byte${s} in length, received ${actual}`); + } else { + const total = (type === StructureType$8.Slice) ? target.length * byteSize : byteSize; + throw new TypeError(`${name} has ${total} byte${s}, received ${actual}`); } - if (srcInfo?.isDirectory()) { - srcPath = path.join(srcPath, '?'); +} + +function throwBufferExpected$8(structure) { + const { type, byteSize, typedArray } = structure; + const s = (byteSize !== 1) ? 's' : ''; + const acceptable = [ 'ArrayBuffer', 'DataView' ].map(addArticle$8); + if (typedArray) { + acceptable.push(addArticle$8(typedArray.name)); } - const config = createConfig(srcPath, modPath, options); - const { moduleDir, outputPath } = config; - let changed = false; - if (srcPath) { - const srcFileMap = findMatchingFilesSync(moduleDir, /.\..*$/); - // see if the (re-)compilation is necessary - const soInfo = findFileSync(outputPath); - if (soInfo) { - for (const [ path, info ] of srcFileMap) { - if (info.mtime > soInfo.mtime) { - changed = true; - break; - } - } - } else { - changed = true; - } - if (!changed) { - // rebuild when exporter or build files have changed - const zigFolder = absolute('../zig'); - const zigFileMap = findMatchingFilesSync(zigFolder, /\.zig$/); - for (const [ path, info ] of zigFileMap) { - if (info.mtime > soInfo.mtime) { - changed = true; - break; - } - } - } - if (changed) { - // add custom build file - for (const [ path$1, info ] of srcFileMap) { - switch (path.basename(path$1)) { - case 'build.zig': - config.buildFilePath = path$1; - break; - case 'build.zig.zon': - config.packageConfigPath = path$1; - break; - } - } - const { zigCmd, moduleBuildDir } = config; - // only one process can compile a given file at a time - const pidPath = `${moduleBuildDir}.pid`; - acquireLockSync(pidPath); - try { - // create config file - createProjectSync(config, moduleBuildDir); - // then run the compiler - runCompilerSync(zigCmd, moduleBuildDir); - } finally { - if (config.clean) { - deleteDirectorySync(moduleBuildDir); - } - releaseLockSync(pidPath); - } - } + if (type === StructureType$8.Slice) { + throw new TypeError(`Expecting ${formatList$8(acceptable)} that can accommodate items ${byteSize} byte${s} in length`); + } else { + throw new TypeError(`Expecting ${formatList$8(acceptable)} that is ${byteSize} byte${s} in length`); } - return { outputPath, changed } } -async function runCompiler(zigCmd, soBuildDir) { - const options = { - cwd: soBuildDir, - windowsHide: true, - }; - return new Promise((resolve, reject) => { - child_process.exec(zigCmd, options, (err, stdout, stderr) => { - if (err) { - const log = stderr; - if (log) { - const logPath = path.join(soBuildDir, 'log'); - promises.writeFile(logPath, log); - err = new Error(`Zig compilation failed\n\n${log}`); - } - reject(err); - } else { - resolve(); - } - }); - }); +function throwEnumExpected$8(structure, arg) { + const { name } = structure; + if (typeof(arg) === 'number' || typeof(arg) === 'bigint') { + throw new TypeError(`Value given does not correspond to an item of enum ${name}: ${arg}`); + } else { + throw new TypeError(`Enum item of the type ${name} expected, received ${arg}`); + } } -function runCompilerSync(zigCmd, soBuildDir) { - const options = { - cwd: soBuildDir, - windowsHide: true, - stdio: 'pipe', - }; - try { - child_process.execSync(zigCmd, options); - } catch (err) { - const log = err.stderr; - if (log) { - const logPath = path.join(soBuildDir, 'log'); - fs.writeFileSync(logPath, log); +function throwErrorExpected$8(structure, arg) { + const { name } = structure; + const type = typeof(arg); + if (type === 'string' || type === 'number' || isErrorJSON(arg)) { + if (isErrorJSON(arg)) { + arg = `{ error: ${JSON.stringify(arg.error)} }`; } - throw new Error(`Zig compilation failed\n\n${log}`); + throw new TypeError(`Error ${type} does not corresponds to any error in error set ${name}: ${arg}`); + } else { + throw new TypeError(`Error of the type ${name} expected, received ${arg}`); } } -function formatProjectConfig(config) { - const lines = []; - const fields = [ - 'moduleName', 'modulePath', 'moduleDir', 'exporterPath', 'stubPath', 'outputPath', - 'useLibc', 'isWASM', - ]; - for (const [ name, value ] of Object.entries(config)) { - if (fields.includes(name)) { - const snakeCase = name.replace(/[A-Z]+/g, m => '_' + m.toLowerCase()); - lines.push(`pub const ${snakeCase} = ${JSON.stringify(value)};`); - } - } - return lines.join('\n'); +function throwNotInErrorSet$8(structure) { + const { name } = structure; + throw new TypeError(`Error given is not a part of error set ${name}`); } -async function createProject(config, dir) { - await createDirectory(dir); - const content = formatProjectConfig(config); - const cfgFilePath = path.join(dir, 'build-cfg.zig'); - await promises.writeFile(cfgFilePath, content); - const buildFilePath = path.join(dir, 'build.zig'); - await copyFile(config.buildFilePath, buildFilePath); - if (config.packageConfigPath) { - const packageConfigPath = path.join(dir, 'build.zig.zon'); - await copyFile(config.packageConfigPath, packageConfigPath); +function throwMultipleUnionInitializers$8(structure) { + const { name } = structure; + throw new TypeError(`Only one property of ${name} can be given a value`); +} + +function throwInactiveUnionProperty$8(structure, name, currentName) { + throw new TypeError(`Accessing property ${name} when ${currentName} is active`); +} + +function throwMissingUnionInitializer$8(structure, arg, exclusion) { + const { name, instance: { members } } = structure; + const missing = members.slice(0, exclusion ? -1 : undefined).map(m => m.name); + throw new TypeError(`${name} needs an initializer for one of its union properties: ${missing.join(', ')}`); +} + +function throwInvalidInitializer$8(structure, expected, arg) { + const { name } = structure; + const acceptable = []; + if (Array.isArray(expected)) { + for (const type of expected) { + acceptable.push(addArticle$8(type)); + } + } else { + acceptable.push(addArticle$8(expected)); } + const received = getDescription$8(arg); + throw new TypeError(`${name} expects ${formatList$8(acceptable)} as argument, received ${received}`); } -function createProjectSync(config, dir) { - createDirectorySync(dir); - const content = formatProjectConfig(config); - const cfgFilePath = path.join(dir, 'build-cfg.zig'); - fs.writeFileSync(cfgFilePath, content); - const buildFilePath = path.join(dir, 'build.zig'); - copyFileSync(config.buildFilePath, buildFilePath); - if (config.packageConfigPath) { - const packageConfigPath = path.join(dir, 'build.zig.zon'); - copyFileSync(config.packageConfigPath, packageConfigPath); +function throwInvalidArrayInitializer$8(structure, arg, shapeless = false) { + const { instance: { members: [ member ] }, type, typedArray } = structure; + const acceptable = []; + const primitive = getPrimitiveType$8(member); + if (primitive) { + let object; + switch (member.structure?.type) { + case StructureType$8.Enumeration: object = 'enum item'; break; + case StructureType$8.ErrorSet: object = 'error'; break; + default: object = primitive; + } + acceptable.push(`array of ${object}s`); + } else { + acceptable.push(`array of objects`); + } + if (typedArray) { + acceptable.push(typedArray.name); + } + if (type === StructureType$8.Slice && shapeless) { + acceptable.push(`length`); } + throwInvalidInitializer$8(structure, acceptable.join(' or '), arg); } -const cwd = process.cwd(); - -function getCachePath(options) { - const { - cacheDir = path.join(cwd, 'zigar-cache'), - } = options; - return cacheDir; -} - -function getModuleCachePath(srcPath, options) { - const { - optimize, - } = options; - const src = path.parse(srcPath); - const folder = path.basename(src.dir).slice(0, 16).trim() + '-' + md5(src.dir).slice(0, 8); - const cacheDir = getCachePath(options); - return path.join(cacheDir, folder, optimize, `${src.name}.zigar`); +function throwArrayLengthMismatch$8(structure, target, arg) { + const { name, length, instance: { members: [ member ] } } = structure; + const { structure: { constructor: elementConstructor} } = member; + const { length: argLength, constructor: argConstructor } = arg; + // get length from object whech it's a slice + const actualLength = target?.length ?? length; + const s = (actualLength !== 1) ? 's' : ''; + let received; + if (argConstructor === elementConstructor) { + received = `only a single one`; + } else if (argConstructor.child === elementConstructor) { + received = `a slice/array that has ${argLength}`; + } else { + received = `${argLength} initializer${argLength > 1 ? 's' : ''}`; + } + throw new TypeError(`${name} has ${actualLength} element${s}, received ${received}`); } -function createConfig(srcPath, modPath, options = {}) { - const { - platform = getPlatform(), - arch = getArch(), - optimize = 'Debug', - isWASM = false, - useLibc = isWASM ? false : true, - clean = false, - buildDir = path.join(os.tmpdir(), 'zigar-build'), - zigCmd = (() => { - // translate from names used by Node to those used by Zig - const cpuArchs = { - arm: 'arm', - arm64: 'aarch64', - ia32: 'x86', - loong64: 'loong64', - mips: 'mips', - mipsel: 'mipsel', - ppc: 'powerpc', - ppc64: 'powerpc64', - s390: undefined, - s390x: 's390x', - x64: 'x86_64', - }; - const osTags = { - aix: 'aix', - darwin: 'macos', - freebsd: 'freebsd', - linux: 'linux-gnu', - openbsd: 'openbsd', - sunos: 'solaris', - win32: 'windows', - }; - const cpuArch = cpuArchs[arch] ?? arch; - const osTag = osTags[platform] ?? platform; - const args = [ - `build`, - `-Doptimize=${optimize}`, - `-Dtarget=${cpuArch}-${osTag}`, - ]; - return `zig ${args.join(' ')}`; - })(), - } = options; - const suffix = isWASM ? 'wasm' : 'c'; - const src = path.parse(srcPath ?? ''); - const mod = path.parse(modPath ?? ''); - const moduleName = mod.name || src.name; - const modulePath = (src.name !== '?') ? srcPath : undefined; - const moduleDir = src.dir; - const modulePrefix = path.basename(moduleName).slice(0, 16); - const moduleHash = md5(`${moduleDir}/${moduleName}`).slice(0, 8); - const moduleBuildDir = path.join(buildDir, modulePrefix + '-' + moduleHash); - const outputPath = (() => { - if (!modPath && isWASM) { - // save output in build folder - return path.join(moduleBuildDir, optimize, `${src.name}.wasm`); - } else { - const extensions = { - darwin: 'dylib', - win32: 'dll', - }; - const ext = extensions[platform] || 'so'; - return path.join(modPath, `${platform}.${arch}.${ext}`); - } - })(); - const exporterPath = absolute(`../zig/exporter-${suffix}.zig`); - const stubPath = absolute(`../zig/stub-${suffix}.zig`); - const buildFilePath = absolute(`../zig/build.zig`); - return { - platform, - arch, - optimize, - moduleName, - modulePath, - moduleDir, - moduleBuildDir, - exporterPath, - stubPath, - buildFilePath, - packageConfigPath: undefined, - outputPath, - clean, - zigCmd, - useLibc, - isWASM, - }; +function throwMissingInitializers$8(structure, missing) { + const { name } = structure; + throw new TypeError(`Missing initializers for ${name}: ${missing.join(', ')}`); } -function absolute(relpath) { - // import.meta.url don't always yield the right URL when transpiled to CommonJS - // just use __dirname as it's going to be there - /* c8 ignore next 2 */ - if (typeof(__dirname) === 'string') { - return path.resolve(__dirname, relpath); +function throwNoProperty$8(structure, propName) { + const { name, instance: { members } } = structure; + const member = members.find(m => m.name === propName); + if (member) { + throw new TypeError(`Comptime value cannot be changed: ${propName}`); } else { - return url.fileURLToPath(new URL(relpath, (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))); + throw new TypeError(`${name} does not have a property with that name: ${propName}`); } } -const optionsForCompile = { - optimize: { - type: 'string', - enum: [ 'Debug', 'ReleaseSmall', 'ReleaseFast', 'ReleaseSafe' ], - title: 'Zig optimization mode', - }, - omitFunctions: { - type: 'boolean', - title: 'Omit all Zig functions', - }, - omitVariables: { - type: 'boolean', - title: 'Omit all variables', - }, - omitExports: { - type: 'boolean', - title: 'Omit export statements', - }, - useLibc: { - type: 'boolean', - title: 'Link in C standard library', - }, - topLevelAwait: { - type: 'boolean', - title: 'Use top-level await to load WASM file', - }, - buildDir: { - type: 'string', - title: 'Root directory where temporary build directories are placed', - }, - cacheDir: { - type: 'string', - title: 'Directory where compiled library files are placed', - }, - zigCmd: { - type: 'string', - title: 'Zig command used to build libraries', - }, - sourceFiles: { - type: 'object', - title: 'Map of modules to source files/directories', - }, - clean: { - type: 'boolean', - title: 'Remove temporary build directory after compilation finishes', - }, - targets: { - type: 'object', - title: 'List of cross-compilation targets', - }, -}; - -const optionsForTranspile = { - useReadFile: { - type: 'boolean', - title: 'Enable the use of readFile() to Load WASM file when library is used in Node.js', - }, - embedWASM: { - type: 'boolean', - title: 'Embed WASM file in JavaScript source code', - }, - stripWASM: { - type: 'boolean', - title: 'Remove unnecessary code from WASM file', - }, - keepNames: { - type: 'boolean', - title: 'Keep names of function in WASM binary when stripping', - }, -}; +function throwArgumentCountMismatch$8(structure, actual) { + const { name, instance: { members } } = structure; + const argCount = members.length - 1; + const s = (argCount !== 1) ? 's' : ''; + throw new Error(`${name} expects ${argCount} argument${s}, received ${actual}`); +} -const allOptions = { - ...optionsForCompile, - ...optionsForTranspile, -}; +function rethrowArgumentError$8(structure, index, err) { + const { name, instance: { members } } = structure; + // Zig currently does not provide the argument name + const argName = `args[${index}]`; + const argCount = members.length - 1; + const prefix = (index !== 0) ? '..., ' : ''; + const suffix = (index !== argCount - 1) ? ', ...' : ''; + const argLabel = prefix + argName + suffix; + const newError = new err.constructor(`${name}(${argLabel}): ${err.message}`); + newError.stack = err.stack; + throw newError; +} -function extractOptions(searchParams, availableOptions) { - const options = {}; - const names = Object.keys(availableOptions); - for (const [ name, string ] of searchParams) { - const key = getCamelCase(name, names); - const option = availableOptions[key]; - if (!option) { - throwUnknownOption(name); - } - if (key === 'optimize') { - options[key] = getCamelCase(string, [ 'Debug', 'ReleaseSafe', 'ReleaseFast', 'ReleaseSmall' ]); - } else { - switch (option.type) { - case 'boolean': - options[key] = !!parseInt(string); - break; - case 'number': - options[key] = parseInt(string); - break; - default: - options[key] = string; - } - } - } - return options; +function throwNoCastingToPointer$8(structure) { + throw new TypeError(`Non-slice pointers can only be created with the help of the new operator`); } -function getCamelCase(name, names) { - for (const nameCC of names) { - const nameSC = nameCC.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase(); - const nameKC = nameSC.replace(/_/g, '-'); - if (name === nameKC || name === nameSC || name === nameCC) { - return nameCC; - } - } - return name; +function throwConstantConstraint$8(structure, pointer) { + const { name: target } = structure; + const { constructor: { name } } = pointer; + throw new TypeError(`Conversion of ${name} to ${target} requires an explicit cast`); } -function throwUnknownOption(key) { - const adjective = (allOptions[key]) ? 'Unavailable' : 'Unrecognized'; - throw new Error(`${adjective} option: ${key}`); +function throwMisplacedSentinel$8(structure, value, index, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}, found at ${index}`); } -async function findConfigFile(name, dir) { - const path$1 = path.join(dir, name); - const info = await findFile(path$1); - if (info?.isFile()) { - return path$1; - } else { - const parent = path.dirname(dir); - if (parent !== dir) { - return findConfigFile(name, parent); - } - } +function throwMissingSentinel$8(structure, value, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}`); } -function findConfigFileSync(name, dir) { - const path$1 = path.join(dir, name); - const info = findFileSync(path$1); - if (info?.isFile()) { - return path$1; +function throwTypeMismatch$8(expected, arg) { + const received = getDescription$8(arg); + throw new TypeError(`Expected ${addArticle$8(expected)}, received ${received}`) +} + +function throwInaccessiblePointer$8() { + throw new TypeError(`Pointers within an untagged union are not accessible`); +} + +function throwNullPointer$8() { + throw new TypeError(`Null pointer`); +} + +function throwInvalidPointerTarget$8(structure, arg) { + const { name } = structure; + let target; + if (arg != null) { + const type = typeof(arg); + const noun = (type === 'object' && arg.constructor !== Object) ? `${arg.constructor.name} object`: type; + const a = article$8(noun); + target = `${a} ${noun}`; } else { - const parent = path.dirname(dir); - if (parent !== dir) { - return findConfigFileSync(name, parent); - } + target = arg + ''; } + throw new TypeError(`${name} cannot point to ${target}`) } -async function loadConfigFile(cfgPath, availableOptions) { - const text = await loadFile(cfgPath); - return processConfigFile(text, cfgPath, availableOptions); +function throwFixedMemoryTargetRequired$8(structure, arg) { + throw new TypeError(`Pointers in fixed memory cannot point to garbage-collected object`); } -function loadConfigFileSync(cfgPath, availableOptions) { - const text = loadFileSync(cfgPath); - return processConfigFile(text, cfgPath, availableOptions); + +function throwOverflow$8(member, value) { + const typeName = getTypeName$8(member); + throw new TypeError(`${typeName} cannot represent the value given: ${value}`); } -function processConfigFile(text, cfgPath, availableOptions) { - const options = JSON.parse(text); - for (const [ key, value ] of Object.entries(options)) { - const option = availableOptions[key]; - if (!option) { - throwUnknownOption(key); - } - if (typeof(value) !== option.type) { - throw new Error(`${key} is expected to be a ${option.type}, received: ${value}`); - } - } - options.sourceFiles = getAbsoluteMapping(options.sourceFiles, path.dirname(cfgPath)); - return options; +function throwOutOfBound$8(member, index) { + const { name } = member; + throw new RangeError(`Index exceeds the size of ${name ?? 'array'}: ${index}`); } -function getAbsoluteMapping(sourceFiles, cfgDir) { - if (!sourceFiles) { - return; - } - const map = {}; - for (const [ module, source ] of Object.entries(sourceFiles)) { - const modulePath = path.resolve(cfgDir, module); - const sourcePath = path.resolve(cfgDir, source); - map[modulePath] = sourcePath; +function rethrowRangeError$8(member, index, err) { + if (err instanceof RangeError) { + throwOutOfBound$8(member, index); + } else { + throw err; } - return map; } -function findSourceFile(modulePath, options) { - const { sourceFiles } = options; - return sourceFiles?.[modulePath]; +function throwNotUndefined$8(member) { + const { name } = member; + throw new RangeError(`Property ${name} can only be undefined`); } -function addMethods(s, env) { - const add = (target, { methods }, pushThis) => { - const descriptors = {}; - const re = /^(get|set)\s+([\s\S]+)/; - for (const method of methods) { - const f = env.createCaller(method, pushThis); - const m = re.exec(f.name); - if (m) { - // getter/setter - const type = m[1], propName = m[2]; - const argRequired = (type === 'get') ? 0 : 1; - const argCount = getArgumentCount(method, pushThis); - // need to match arg count, since instance methods also show up as static methods - if (argCount === argRequired) { - let descriptor = descriptors[propName]; - if (!descriptor) { - descriptor = descriptors[propName] = { configurable: true, enumerable: true }; - } - descriptor[type] = f; - } - } else { - descriptors[f.name] = { value: f, configurable: true, writable: true }; - } - } - defineProperties$8(target, descriptors); - }; - add(s.constructor, s.static, false); - add(s.constructor.prototype, s.instance, true); +function throwNotOnByteBoundary$8(member) { + const { name, structure: { name: { struct }} } = member; + throw new TypeError(`Unable to create ${struct} as it is not situated on a byte boundary: ${name}`); } -function getArgumentCount(method, pushThis) { - const { argStruct: { instance: { members } } } = method; - return members.length - (pushThis ? 2 : 1); +function throwReadOnly$8() { + throw new TypeError(`Unable to modify read-only object`); } -function addStaticMembers(structure, env) { - const { - type, - constructor, - static: { members, template }, - } = structure; - if (members.length === 0) { - return; - } - const descriptors = {}; - for (const member of members) { - descriptors[member.name] = getDescriptor$8(member, env); - } - defineProperties$8(constructor, { - valueOf: { value: getValueOf$8 }, - toJSON: { value: convertToJSON$8 }, - ...descriptors, - [Symbol.iterator]: { value: getStructIterator$8 }, - // static variables are objects stored in the static template's slots - [SLOTS$8]: { value: template[SLOTS$8] }, - [PROPS$8]: { value: members.map(m => m.name) }, - [NORMALIZER$8]: { value: normalizeStruct$8 }, - }); - if (type === StructureType$8.Enumeration) { - const enums = constructor[ITEMS$8]; - for (const { name, slot } of members) { - if (name !== undefined) { - // place item in hash to facilitate lookup, - const item = constructor[SLOTS$8][slot]; - if (item instanceof constructor) { - // attach name to item so tagged union code can quickly find it - defineProperties$8(item, { [NAME$8]: { value: name } }); - const index = item[Symbol.toPrimitive](); - enums[index] = enums[name] = item; - } - } else { - // non-exhaustive enum - defineProperties$8(constructor, { [MORE$8]: { value: true } }); - } - } - } else if (type === StructureType$8.ErrorSet) { - const allErrors = getGlobalErrorSet$8(); - const errors = constructor[ITEMS$8]; - for (const { name, slot } of members) { - let error = constructor[SLOTS$8][slot]; - const index = Number(error); - const previous = allErrors[index]; - if (previous) { - if (!(previous instanceof constructor)) { - // error already exists in a previously defined set - // see if we should make that set a subclass or superclass of this one - const otherSet = previous.constructor; - const otherErrors = Object.values(otherSet[SLOTS$8]); - const errorIndices = Object.values(constructor[SLOTS$8]).map(e => Number(e)); - if (otherErrors.every(e => errorIndices.includes(Number(e)))) { - // this set contains the all errors of the other one, so it's a superclass - Object.setPrototypeOf(otherSet.prototype, constructor.prototype); - } else { - // make this set a subclass of the other - Object.setPrototypeOf(constructor.prototype, otherSet.prototype); - for (const otherError of otherErrors) { - if (errorIndices.includes(Number(otherError))) { - // this set should be this error object's class - Object.setPrototypeOf(otherError, constructor.prototype); - } - } - } - } - error = constructor[SLOTS$8][slot] = previous; - } else { - // set error message (overriding prototype) and add to hash - defineProperties$8(error, { message: { value: deanimalizeErrorName(name) } }); - allErrors[index] = allErrors[error.message] = allErrors[`${error}`] = error; - } - errors[index] = errors[error.message] = errors[`${error}`] = error; - } - } +function throwReadOnlyTarget$8(structure) { + const { name } = structure; + throw new TypeError(`${name} cannot point to a read-only object`); } -class Environment { - context; - contextStack = []; - consolePending = []; - consoleTimeout = 0; - viewMap = new WeakMap(); - initPromise; - abandoned = false; - released = false; - littleEndian = true; - runtimeSafety = true; - comptime = false; - /* COMPTIME-ONLY */ - slotNumbers = {}; - slots = {}; - structures = []; - /* COMPTIME-ONLY-END */ - imports; - console = globalThis.console; - - /* - Functions to be defined in subclass: +function throwAccessingOpaque$8(structure) { + const { name } = structure; + throw new TypeError(`Unable to access opaque structure ${name}`); +} - getBufferAddress(buffer: ArrayBuffer): bigint|number { - // return a buffer's address - } - allocateHostMemory(len: number, align: number): DataView { - // allocate memory and remember its address - } - allocateShadowMemory(len: number, align: number): DataView { - // allocate memory for shadowing objects - } - freeHostMemory(address: bigint|number, len: number, align: number): void { - // free previously allocated memory - } - freeShadowMemory(address: bigint|number, len: number, align: number): void { - // free memory allocated for shadow - } - allocateFixedMemory(len: number, align: number): DataView { - // allocate fixed memory and keep a reference to it - } - freeFixedMemory(address: bigint|number, len: number, align: number): void { - // free previously allocated fixed memory return the reference - } - obtainFixedView(address: bigint|number, len: number): DataView { - // obtain a data view of memory at given address - } - releaseFixedView(dv: DataView): void { - // release allocated memory stored in data view, doing nothing if data view - // does not contain fixed memory or if memory is static - } - inFixedMemory(object: object): boolean { - // return true/false depending on whether object is in fixed memory - } - copyBytes(dst: DataView, address: bigint|number, len: number): void { - // copy memory at given address into destination view - } - findSentinel(address: bigint|number, bytes: DataView): number { - // return offset where sentinel value is found - } - getMemoryOffset(address: bigint|number) number { - // return offset of address relative to start of module memory - } - recreateAddress(reloc: number) number { - // recreate address of memory belonging to module - } +function throwCreatingOpaque$8(structure) { + const { name } = structure; + throw new TypeError(`Unable to create instance of ${name}, as it is opaque`); +} - getTargetAddress(target: object, cluster: object|undefined) { - // return the address of target's buffer if correctly aligned +function warnImplicitArrayCreation$8(structure, arg) { + const created = addArticle$8(structure.typedArray.name); + const source = addArticle$8(arg.constructor.name); + console.warn(`Implicitly creating ${created} from ${source}`); +} + +function deanimalizeErrorName(name) { + // deal with snake_case first + let s = name.replace(/_/g, ' '); + // then camelCase, using a try block in case Unicode regex fails + try { + s = s.replace(/(\p{Uppercase}+)(\p{Lowercase}*)/gu, (m0, m1, m2) => { + if (m1.length === 1) { + return ` ${m1.toLocaleLowerCase()}${m2}`; + } else { + if (m2) { + const acronym = m1.substring(0, m1.length - 1); + const letter = m1.charAt(m1.length - 1).toLocaleLowerCase(); + return ` ${acronym} ${letter}${m2}`; + } else { + return ` ${m1}`; + } + } + }).trimStart(); + /* c8 ignore next 2 */ + } catch (err) { } - */ + return s.charAt(0).toLocaleUpperCase() + s.substring(1); +} - startContext() { - if (this.context) { - this.contextStack.push(this.context); - } - this.context = new CallContext(); +function getDescription$8(arg) { + const type = typeof(arg); + let s; + if (type === 'object') { + s = (arg) ? Object.prototype.toString.call(arg) : 'null'; + } else { + s = type; } + return addArticle$8(s); +} - endContext() { - this.context = this.contextStack.pop(); +function addArticle$8(noun) { + return `${article$8(noun)} ${noun}`; +} + +function article$8(noun) { + return /^\W*[aeiou]/i.test(noun) ? 'an' : 'a'; +} + +function formatList$8(list, conj = 'or') { + const sep = ` ${conj} `; + if (list.length > 2) { + return list.slice(0, -1).join(', ') + sep + list[list.length - 1]; + } else { + return list.join(sep); } +} - allocateMemory(len, align = 0, fixed = false) { - if (fixed) { - return this.allocateFixedMemory(len, align); +function getBoolAccessor$8(access, member) { + return cacheMethod$8(access, member, () => { + if (isByteAligned$8(member)) { + const { byteSize } = member; + const typeName = getTypeName$8({ type: MemberType$8.Int, bitSize: byteSize * 8 }); + if (access === 'get') { + const get = DataView.prototype[`get${typeName}`]; + return function(offset, littleEndian) { + return !!get.call(this, offset, littleEndian); + }; + } else { + const set = DataView.prototype[`set${typeName}`]; + const T = (byteSize > 4) ? 1n : 1; + const F = (byteSize > 4) ? 0n : 0; + return function(offset, value, littleEndian) { + set.call(this, offset, value ? T : F, littleEndian); + }; + } } else { - return this.allocateRelocMemory(len, align); + return getExtendedTypeAccessor$8(access, member); } - } + }); +} - allocateRelocMemory(len, align) { - return this.obtainView(new ArrayBuffer(len), 0, len); - } +function getNumericAccessor$8(access, member) { + return cacheMethod$8(access, member, (name) => { + if (DataView.prototype[name]) { + return DataView.prototype[name]; + } else { + return getExtendedTypeAccessor$8(access, member); + } + }); +} - registerMemory(dv, targetDV = null, targetAlign = undefined) { - const { memoryList } = this.context; - const address = this.getViewAddress(dv); - const index = findMemoryIndex(memoryList, address); - memoryList.splice(index, 0, { address, dv, len: dv.byteLength, targetDV, targetAlign }); - return address; - } +const factories$p = {}; - unregisterMemory(address) { - const { memoryList } = this.context; - const index = findMemoryIndex(memoryList, address); - const prev = memoryList[index - 1]; - if (prev?.address === address) { - memoryList.splice(index - 1, 1); - } +function useExtendedBool$8() { + factories$p[MemberType$8.Bool] = getExtendedBoolAccessor$8; +} + +function useExtendedInt$8() { + factories$p[MemberType$8.Int] = getExtendedIntAccessor$8; +} + +function useExtendedUint$8() { + factories$p[MemberType$8.Uint] = getExtendedUintAccessor$8; +} + +function useExtendedFloat$8() { + factories$p[MemberType$8.Float] = getExtendedFloatAccessor$8; +} + +function getExtendedTypeAccessor$8(access, member) { + const f = factories$p[member.type]; + return f(access, member); +} + +function getExtendedBoolAccessor$8(access, member) { + const { bitOffset } = member; + const bitPos = bitOffset & 0x07; + const mask = 1 << bitPos; + const get = DataView.prototype.getInt8; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + return !!(n & mask); + }; + } else { + const set = DataView.prototype.setInt8; + return function(offset, value) { + const n = get.call(this, offset); + const b = (value) ? n | mask : n & ~mask; + set.call(this, offset, b); + }; } +} - findMemory(address, len) { - // check for null address (=== can't be used since address can be both number and bigint) - if (this.context) { - const { memoryList } = this.context; - const index = findMemoryIndex(memoryList, address); - const entry = memoryList[index - 1]; - if (entry?.address === address && entry.len === len) { - return entry.targetDV ?? entry.dv; - } else if (entry?.address <= address && address < add(entry.address, entry.len)) { - const offset = Number(address - entry.address); - const targetDV = entry.targetDV ?? entry.dv; - const isOpaque = len === undefined; - if (isOpaque) { - len = targetDV.byteLength - offset; - } - const dv = this.obtainView(targetDV.buffer, targetDV.byteOffset + offset, len); - if (isOpaque) { - // opaque structure--need to save the alignment - dv[ALIGN$8] = entry.targetAlign; - } - return dv; - } - } - // not found in any of the buffers we've seen--assume it's fixed memory - return this.obtainFixedView(address, len ?? 0); +function getExtendedIntAccessor$8(access, member) { + if (isByteAligned$8(member)) { + return getAlignedIntAccessor$8(access, member) + } else { + return getUnalignedIntAccessor$8(access, member); } +} - getViewAddress(dv) { - const address = this.getBufferAddress(dv.buffer); - return add(address, dv.byteOffset); +function getExtendedUintAccessor$8(access, member) { + if (isByteAligned$8(member)) { + return getAlignedUintAccessor$8(access, member) + } else { + return getUnalignedUintAccessor$8(access, member); } +} - obtainView(buffer, offset, len) { - let entry = this.viewMap.get(buffer); - if (!entry) { - const dv = new DataView(buffer, offset, len); - this.viewMap.set(buffer, dv); - return dv; - } - if (entry instanceof DataView) { - // only one view created thus far--see if that's the matching one - if (entry.byteOffset === offset && entry.byteLength === len) { - return entry; - } else { - // no, need to replace the entry with a hash keyed by `offset:len` - const dv = entry; - const key = `${dv.byteOffset}:${dv.byteLength}`; - entry = { [key]: dv }; - this.viewMap.set(buffer, entry); - } - } - const key = `${offset}:${len}`; - let dv = entry[key]; - if (!dv) { - dv = entry[key] = new DataView(buffer, offset, len); - } - return dv; +function getExtendedFloatAccessor$8(access, member) { + if (isByteAligned$8(member)) { + return getAlignedFloatAccessor$8(access, member) + } else { + return getUnalignedFloatAccessor$8(access, member); } +} - captureView(address, len, copy) { - if (copy) { - // copy content into reloctable memory - const dv = this.allocateRelocMemory(len, 0); - if (len > 0) { - this.copyBytes(dv, address, len); +function getDataView$8(structure, arg, env) { + const { type, byteSize, typedArray } = structure; + let dv; + // not using instanceof just in case we're getting objects created in other contexts + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView') { + dv = arg; + } else if (tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + dv = env.obtainView(arg, 0, arg.byteLength); + } else if (typedArray && tag === typedArray.name || (tag === 'Uint8ClampedArray' && typedArray === Uint8Array)) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else if (tag === 'Uint8Array' && typeof(Buffer) === 'function' && arg instanceof Buffer) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else { + const memory = arg?.[MEMORY$8]; + if (memory) { + const { constructor, instance: { members: [ member ] } } = structure; + if (arg instanceof constructor) { + return memory; + } else if (type === StructureType$8.Array || type === StructureType$8.Slice || type === StructureType$8.Vector) { + const { byteSize: elementSize, structure: { constructor: Child } } = member; + const number = findElements$8(arg, Child); + if (number !== undefined) { + if (type === StructureType$8.Slice || number * elementSize === byteSize) { + return memory; + } else { + throwArrayLengthMismatch$8(structure, null, arg); + } + } } - return dv; - } else { - // link into fixed memory - return this.obtainFixedView(address, len); } } - - castView(structure, dv, writable) { - const { constructor, hasPointer } = structure; - const object = constructor.call(ENVIRONMENT$8, dv, { writable }); - if (hasPointer) { - // acquire targets of pointers - this.acquirePointerTargets(object); - } - return object; + if (dv && byteSize !== undefined) { + checkDataViewSize$8(dv, structure); } + return dv; +} - /* COMPTIME-ONLY */ - getSlotNumber(scope, key) { - let slotNumber = this.slotNumbers[scope]; - if (!slotNumber) { - slotNumber = this.slotNumbers[scope] = { next: 0, map: {} }; - } - let slot = slotNumber.map[key]; - if (slot === undefined) { - slot = slotNumber.map[key] = slotNumber.next++; - } - return slot; +function checkDataView$8(dv) { + if (dv?.[Symbol.toStringTag] !== 'DataView') { + throwTypeMismatch$8('a DataView', dv); } - - readSlot(target, slot) { - const slots = target ? target[SLOTS$8] : this.slots; - return slots?.[slot]; + return dv; +} + +function checkDataViewSize$8(dv, structure) { + const { byteSize, type } = structure; + const multiple = type === StructureType$8.Slice; + if (multiple ? dv.byteLength % byteSize !== 0 : dv.byteLength !== byteSize) { + throwBufferSizeMismatch$8(structure, dv); } +} - writeSlot(target, slot, value) { - const slots = target ? target[SLOTS$8] : this.slots; - if (slots) { - slots[slot] = value; +function setDataView$8(dv, structure, copy, handlers) { + const { byteSize, type, sentinel } = structure; + const multiple = type === StructureType$8.Slice; + if (!this[MEMORY$8]) { + const { shapeDefiner } = handlers; + checkDataViewSize$8(dv, structure); + const len = dv.byteLength / byteSize; + const source = { [MEMORY$8]: dv }; + sentinel?.validateData(source, len); + shapeDefiner.call(this, copy ? null : dv, len); + if (copy) { + this[COPIER$8](source); + } + } else { + const byteLength = multiple ? byteSize * this.length : byteSize; + if (dv.byteLength !== byteLength) { + throwBufferSizeMismatch$8(structure, dv, this); } + const source = { [MEMORY$8]: dv }; + sentinel?.validateData(source, this.length); + this[COPIER$8](source); } +} - createTemplate(dv) { - return { - [MEMORY$8]: dv, - [SLOTS$8]: {} - }; +function findElements$8(arg, Child) { + // casting to a array/slice + const { constructor: Arg } = arg; + if (Arg === Child) { + // matching object + return 1; + } else if (Arg.child === Child) { + // matching slice/array + return arg.length; } +} - beginStructure(def) { - const { - type, - name, - length, - byteSize, - align, - isConst, - hasPointer, - } = def; - return { - constructor: null, - typedArray: null, - type, - name, - length, - byteSize, - align, - isConst, - hasPointer, - instance: { - members: [], - methods: [], - template: null, - }, - static: { - members: [], - methods: [], - template: null, - }, - }; +function requireDataView$8(structure, arg, env) { + const dv = getDataView$8(structure, arg, env); + if (!dv) { + throwBufferExpected$8(structure); } + return dv; +} - attachMember(structure, member, isStatic = false) { - const target = (isStatic) ? structure.static : structure.instance; - target.members.push(member); +function getTypedArrayClass$8(member) { + const { type: memberType, byteSize } = member; + if (memberType === MemberType$8.Int) { + switch (byteSize) { + case 1: return Int8Array; + case 2: return Int16Array; + case 4: return Int32Array; + case 8: return BigInt64Array; + } + } else if (memberType === MemberType$8.Uint) { + switch (byteSize) { + case 1: return Uint8Array; + case 2: return Uint16Array; + case 4: return Uint32Array; + case 8: return BigUint64Array; + } + } else if (memberType === MemberType$8.Float) { + switch (byteSize) { + case 4: return Float32Array; + case 8: return Float64Array; + } + } else if (memberType === MemberType$8.Object) { + return member.structure.typedArray; } + return null; +} - attachMethod(structure, method, isStaticOnly = false) { - structure.static.methods.push(method); - if (!isStaticOnly) { - structure.instance.methods.push(method); +function isTypedArray$8(arg, TypedArray) { + const tag = arg?.[Symbol.toStringTag]; + return (!!TypedArray && tag === TypedArray.name); +} + +function isCompatible$8(arg, constructor) { + const tags = constructor[COMPAT$8]; + if (tags) { + const tag = arg?.[Symbol.toStringTag]; + if (tags.includes(tag)) { + return true; } } - - attachTemplate(structure, template, isStatic = false) { - const target = (isStatic) ? structure.static : structure.instance; - target.template = template; + if (constructor.child) { + if (findElements$8(arg, constructor.child) !== undefined) { + return true; + } } + return false; +} - endStructure(structure) { - this.structures.push(structure); - this.finalizeStructure(structure); - for (const structure of this.structures) { - this.acquireDefaultPointers(structure); +function getCompatibleTags$8(structure) { + const { typedArray } = structure; + const tags = []; + if (typedArray) { + tags.push(typedArray.name); + tags.push('DataView'); + if (typedArray === Uint8Array || typedArray === Int8Array) { + tags.push('Uint8ClampedArray'); + tags.push('ArrayBuffer'); + tags.push('SharedArrayBuffer'); } } + return tags; +} + +function isBuffer$8(arg, typedArray) { + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView' || tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + return true; + } else if (typedArray && tag === typedArray.name) { + return true; + } else { + return false; + } +} - defineFactoryArgStruct() { - useBool$8(); - useObject$8(); - useArgStruct$8(); - const options = this.beginStructure({ - type: StructureType$8.Struct, - name: 'Options', - byteSize: 2, - hasPointer: false, - }); - this.attachMember(options, { - type: MemberType$8.Bool, - name: 'omitFunctions', - bitOffset: 0, - bitSize: 1, - byteSize: 1, - }); - this.attachMember(options, { - type: MemberType$8.Bool, - name: 'omitVariables', - bitOffset: 8, - bitSize: 1, - byteSize: 1, - }); - this.finalizeShape(options); - const structure = this.beginStructure({ - type: StructureType$8.ArgStruct, - name: 'factory', - byteSize: 2, - hasPointer: false, - }); - this.attachMember(structure, { - type: MemberType$8.Object, - name: '0', - bitOffset: 0, - bitSize: 16, - byteSize: 2, - slot: 0, - structure: options, - }); - this.attachMember(structure, { - type: MemberType$8.Void, - name: 'retval', - bitOffset: 16, - bitSize: 0, - byteSize: 0 - }); - this.finalizeShape(structure); - return structure.constructor; +function getTypeName$8(member) { + const { type, bitSize, byteSize } = member; + if (type === MemberType$8.Int) { + return `${bitSize <= 32 ? '' : 'Big' }Int${bitSize}`; + } else if (type === MemberType$8.Uint) { + return `${bitSize <= 32 ? '' : 'Big' }Uint${bitSize}`; + } else if (type === MemberType$8.Float) { + return `Float${bitSize}`; + } else if (type === MemberType$8.Bool) { + const boolSize = (byteSize !== undefined) ? byteSize * 8 : 1; + return `Bool${boolSize}`; + } else if (type === MemberType$8.Void) { + return `Null`; } +} - acquireStructures(options) { - const { - omitFunctions = false, - omitVariables = isElectron(), - } = options; - createGlobalErrorSet(); - const thunkId = this.getFactoryThunk(); - const ArgStruct = this.defineFactoryArgStruct(); - const args = new ArgStruct([ { omitFunctions, omitVariables } ]); - this.comptime = true; - this.invokeThunk(thunkId, args); - this.comptime = false; - } +function getBigIntDescriptor$8(bitSize) { + const getWord = DataView.prototype.getBigUint64; + const setWord = DataView.prototype.setBigUint64; + const wordCount = Math.ceil(bitSize / 64); + return { + get: function(offset, littleEndian) { + let n = 0n; + if (littleEndian) { + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; + } + } else { + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; + } + } + return n; + }, + set: function(offset, value, littleEndian) { + let n = value; + const mask = 0xFFFFFFFFFFFFFFFFn; + if (littleEndian) { + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } + } else { + n <<= BigInt(wordCount * 64 - bitSize); + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } + } + return n; + }, + }; +} - getRootModule() { - const root = this.structures[this.structures.length - 1]; - return root.constructor; +function getAlignedIntAccessor$8(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$8({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const signMask = (bitSize <= 32) ? 2 ** (bitSize - 1) : 2n ** BigInt(bitSize - 1); + const valueMask = (bitSize <= 32) ? signMask - 1 : signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$8(bitSize); + const signMask = 2n ** BigInt(bitSize - 1); + const valueMask = signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } } +} - hasMethods() { - // all methods are static, so there's no need to check instance methods - return !!this.structures.find(s => s.static.methods.length > 0); +function getAlignedUintAccessor$8(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$8({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const valueMask = (bitSize <= 32) ? (2 ** bitSize) - 1 : (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$8(bitSize); + const valueMask = (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } } +} - exportStructures() { - this.prepareObjectsForExport(); - const { structures, runtimeSafety, littleEndian } = this; - return { - structures, - options: { runtimeSafety, littleEndian }, - keys: { MEMORY: MEMORY$8, SLOTS: SLOTS$8, CONST: CONST$8 } - }; +function getUnalignedIntAccessor$8(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + // sub-8-bit numbers have real use cases + const signMask = 2 ** (bitSize - 1); + const valueMask = signMask - 1; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return (s & valueMask) - (s & signMask); + }; + } else { + const outsideMask = 0xFF ^ ((valueMask | signMask) << bitPos); + return function(offset, value) { + let b = get.call(this, offset); + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + b = (b & outsideMask) | (n << bitPos); + set.call(this, offset, b); + }; + } } + return getUnalignedNumericAccessor$8(access, member); +} - prepareObjectsForExport() { - const objects = findAllObjects(this.structures, SLOTS$8); - const list = []; - for (const object of objects) { - if (object[MEMORY$8]) { - if (this.inFixedMemory(object)) { - // replace fixed memory - const dv = object[MEMORY$8]; - const address = this.getViewAddress(dv); - const offset = this.getMemoryOffset(address); - const len = dv.byteLength; - const relocDV = this.captureView(address, len, true); - relocDV.reloc = offset; - object[MEMORY$8] = relocDV; - list.push({ offset, len, owner: object, replaced: false }); - } - } +function getUnalignedUintAccessor$8(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + const valueMask = (2 ** bitSize - 1); + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return s & valueMask; + }; + } else { + const outsideMask = 0xFF ^ (valueMask << bitPos); + return function(offset, value) { + const n = get.call(this, offset); + const b = (n & outsideMask) | ((value & valueMask) << bitPos); + set.call(this, offset, b); + }; } - // larger memory blocks come first - list.sort((a, b) => b.len - a.len); - for (const a of list) { - if (!a.replaced) { - for (const b of list) { - if (a !== b && !b.replaced) { - if (a.offset <= b.offset && b.offset < a.offset + a.len) { - // B is inside A--replace it with a view of A's buffer - const dv = a.owner[MEMORY$8]; - const pos = b.offset - a.offset + dv.byteOffset; - const newDV = this.obtainView(dv.buffer, pos, b.len); - newDV.reloc = b.offset; - b.owner[MEMORY$8] = newDV; - b.replaced = true; - } + } + return getUnalignedNumericAccessor$8(access, member); +} + +function getAlignedFloatAccessor$8(access, member) { + const { bitSize, byteSize } = member; + if (bitSize === 16) { + const buf = new DataView(new ArrayBuffer(4)); + const set = DataView.prototype.setUint16; + const get = DataView.prototype.getUint16; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >>> 15; + const exp = (n & 0x7C00) >> 10; + const frac = n & 0x03FF; + if (exp === 0) { + return (sign) ? -0 : 0; + } else if (exp === 0x1F) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; } - } + } + const n32 = (sign << 31) | ((exp - 15 + 127) << 23) | (frac << 13); + buf.setUint32(0, n32, littleEndian); + return buf.getFloat32(0, littleEndian); } - } - } - - useStructures() { - const module = this.getRootModule(); - // add fixed memory object to list so they can be unlinked - const objects = findAllObjects(this.structures, SLOTS$8); - for (const object of objects) { - if (object[MEMORY$8] && this.inFixedMemory(object)) { - this.variables.push({ object }); + } else { + return function(offset, value, littleEndian) { + buf.setFloat32(0, value, littleEndian); + const n = buf.getUint32(0, littleEndian); + const sign = n >>> 31; + const exp = (n & 0x7F800000) >> 23; + const frac = n & 0x007FFFFF; + const exp16 = (exp - 127 + 15); + let n16; + if (exp === 0) { + n16 = sign << 15; + } else if (exp === 0xFF) { + n16 = sign << 15 | 0x1F << 10 | (frac ? 1 : 0); + } else if (exp16 >= 31) { + n16 = sign << 15 | 0x1F << 10; + } else { + n16 = sign << 15 | exp16 << 10 | (frac >> 13); + } + set.call(this, offset, n16, littleEndian); } } - // clear comptime-only variables - this.slots = {}; - this.structures = []; - module.__zigar = this.getControlObject(); - return module; - } - /* COMPTIME-ONLY-END */ - - finalizeShape(structure) { - const f = getStructureFactory(structure.type); - const constructor = f(structure, this); - if (typeof(constructor) === 'function') { - defineProperties$8(constructor, { - name: { value: structure.name, configurable: true }, - }); - if (!constructor.prototype.hasOwnProperty(Symbol.toStringTag)) { - defineProperties$8(constructor.prototype, { - [Symbol.toStringTag]: { value: structure.name, configurable: true }, - }); + } else if (bitSize === 80) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + return w1 | w2 << 32n | w3 << 64n; + }; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 79n; + const exp = (n & 0x7FFF0000000000000000n) >> 64n; + const frac = n & 0x00007FFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } + } + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; + } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 11n) + BigInt((frac & (2n**11n - 1n)) >= 2n**10n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); } - } - } - - finalizeStructure(structure) { - addStaticMembers(structure, this); - addMethods(structure, this); - } - - createCaller(method, useThis) { - const { name, argStruct, thunkId } = method; - const { constructor } = argStruct; - const self = this; - let f; - if (useThis) { - f = function(...args) { - return self.invokeThunk(thunkId, new constructor([ this, ...args ])); - }; } else { - f = function(...args) { - return self.invokeThunk(thunkId, new constructor(args)); - }; + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n80; + if (exp === 0n) { + n80 = sign << 79n | (frac << 11n); + } else if (exp === 0x07FFn) { + n80 = sign << 79n | 0x7FFFn << 64n | (frac ? 0x00002000000000000000n : 0n) | 0x00008000000000000000n; + // ^ bit 61 ^ bit 63 + } else { + n80 = sign << 79n | (exp - 1023n + 16383n) << 64n | (frac << 11n) | 0x00008000000000000000n; + } + set.call(this, offset, n80, littleEndian); + } } - Object.defineProperty(f, 'name', { value: name }); - return f; - } - - - getShadowAddress(target, cluster) { - if (cluster) { - const dv = target[MEMORY$8]; - if (cluster.address === undefined) { - const shadow = this.createClusterShadow(cluster); - cluster.address = this.getViewAddress(shadow[MEMORY$8]); + } else if (bitSize === 128) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + const w4 = BigInt(this.getUint32(offset + (littleEndian ? 12 : byteSize - 16), littleEndian)); + return w1 | w2 << 32n | w3 << 64n | w4 << 96n; + }; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + const w4 = (value >> 96n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + this.setUint32(offset + (littleEndian ? 12 : byteSize - 16), Number(w4), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 127n; + const exp = (n & 0x7FFF0000000000000000000000000000n) >> 112n; + const frac = n & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } + } + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; + } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 60n) + BigInt((frac & (2n**60n - 1n)) >= 2n**59n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); } - return add(cluster.address, dv.byteOffset); } else { - const shadow = this.createShadow(target); - return this.getViewAddress(shadow[MEMORY$8]); + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n128; + if (exp === 0n) { + n128 = sign << 127n | (frac << 60n); + } else if (exp === 0x07FFn) { + n128 = sign << 127n | 0x7FFFn << 112n | (frac ? 1n : 0n); + } else { + n128 = sign << 127n | (exp - 1023n + 16383n) << 112n | (frac << 60n); + } + set.call(this, offset, n128, littleEndian); + } } } +} - createShadow(object) { - const dv = object[MEMORY$8]; - // use the alignment of the structure; in the case of an opaque pointer's target, - // try to the alignment specified when the memory was allocated - const align = object.constructor[ALIGN$8] ?? dv[ALIGN$8]; - const shadow = Object.create(object.constructor.prototype); - const shadowDV = shadow[MEMORY$8] = this.allocateShadowMemory(dv.byteLength, align); - shadow[ATTRIBUTES] = { - address: this.getViewAddress(shadowDV), - len: shadowDV.byteLength, - align, +function getUnalignedFloatAccessor$8(access, member) { + return getUnalignedNumericAccessor$8(access, member); +} + +function getUnalignedNumericAccessor$8(access, member) { + // pathological usage scenario--handle it anyway by copying the bitSize into a + // temporary buffer, bit-aligning the data + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + const byteSize = [ 1, 2, 4, 8 ].find(b => b * 8 >= bitSize) ?? Math.ceil(bitSize / 64) * 64; + const buf = new DataView(new ArrayBuffer(byteSize)); + if (access === 'get') { + const getAligned = getNumericAccessor$8('get', { ...member, byteSize }); + const copyBits = getBitAlignFunction$8(bitPos, bitSize, true); + return function(offset, littleEndian) { + copyBits(buf, this, offset); + return getAligned.call(buf, 0, littleEndian); + }; + } else { + const setAligned = getNumericAccessor$8('set', { ...member, byteSize }); + const applyBits = getBitAlignFunction$8(bitPos, bitSize, false); + return function(offset, value, littleEndian) { + setAligned.call(buf, 0, value, littleEndian); + applyBits(this, buf, offset); }; - return this.addShadow(shadow, object, align); } +} - addShadow(shadow, object, align) { - let { shadowMap } = this.context; - if (!shadowMap) { - shadowMap = this.context.shadowMap = new Map(); - } - shadowMap.set(shadow, object); - this.registerMemory(shadow[MEMORY$8], object[MEMORY$8], align); - return shadow; - } +const methodCache$8 = {}; - removeShadow(dv) { - const { shadowMap } = this.context; - if (shadowMap) { - for (const [ shadow ] of shadowMap) { - if (shadow[MEMORY$8] === dv) { - shadowMap.delete(shadow); - break; - } - } +function cacheMethod$8(access, member, cb) { + const { type, bitOffset, bitSize, structure } = member; + const bitPos = bitOffset & 0x07; + const typeName = getTypeName$8(member); + const suffix = isByteAligned$8(member) ? `` : `Bit${bitPos}`; + const isInt = type === MemberType$8.Int || type === MemberType$8.Uint; + let name = `${access}${typeName}${suffix}`; + let isSize = false, originalName = name; + if (isInt && bitSize === 64) { + const zigTypeName = structure?.name; + if (zigTypeName === 'usize' || zigTypeName === 'isize') { + name += 'Size'; + isSize = true; } } - - updateShadows() { - const { shadowMap } = this.context; - if (!shadowMap) { - return; + let fn = methodCache$8[name]; + if (!fn) { + if (isInt && access === 'set') { + // add auto-conversion between number and bigint + const Primitive = getPrimitiveClass$8(member); + const set = cb(originalName); + fn = function(offset, value, littleEndian) { + set.call(this, offset, Primitive(value), littleEndian); + }; + } else if (isSize && access === 'get') { + // use number instead of bigint where possible + const get = cb(originalName); + const min = BigInt(Number.MIN_SAFE_INTEGER); + const max = BigInt(Number.MAX_SAFE_INTEGER); + fn = function(offset, littleEndian) { + const value = get.call(this, offset, littleEndian); + if (min <= value && value <= max) { + return Number(value); + } else { + return value; + } + }; + } else { + fn = cb(name); } - for (const [ shadow, object ] of shadowMap) { - shadow[COPIER$8](object); + if (fn && fn.name !== name) { + Object.defineProperty(fn, 'name', { value: name, configurable: true, writable: false }); } + methodCache$8[name] = fn; } + return fn; +} - updateShadowTargets() { - const { shadowMap } = this.context; - if (!shadowMap) { - return; - } - for (const [ shadow, object ] of shadowMap) { - object[COPIER$8](shadow); - } - } +function useAllExtendedTypes$8() { + useExtendedBool$8(); + useExtendedInt$8(); + useExtendedUint$8(); + useExtendedFloat$8(); +} - releaseShadows() { - const { shadowMap } = this.context; - if (!shadowMap) { - return; - } - for (const [ shadow ] of shadowMap) { - const { address, len, align } = shadow[ATTRIBUTES]; - this.freeShadowMemory(address, len, align); - } - } +const MemberType$8 = { + Void: 0, + Bool: 1, + Int: 2, + Uint: 3, + Float: 4, + Object: 5, + Type: 6, + Comptime: 7, + Static: 8, + Literal: 9, + Null: 10, + Undefined: 11, +}; - acquirePointerTargets(args) { - const env = this; - const pointerMap = new Map(); - const callback = function({ isActive, isMutable }) { - const pointer = this[POINTER$8]; - if (pointerMap.get(pointer)) { - return; - } else { - pointerMap.set(pointer, true); - } - const writable = !pointer.constructor.const; - const currentTarget = pointer[SLOTS$8][0]; - let newTarget, location; - if (isActive(this)) { - const Target = pointer.constructor.child; - if (!currentTarget || isMutable(this)) { - // obtain address and length from memory - location = pointer[LOCATION_GETTER$8](); - if (!isInvalidAddress(location.address)) { - // get view of memory that pointer points to - const len = (Target[SIZE$8] !== undefined) ? location.length * Target[SIZE$8] : undefined; - const dv = env.findMemory(location.address, len); - // create the target - newTarget = Target.call(ENVIRONMENT$8, dv, { writable }); - } else { - newTarget = null; - } - } else { - newTarget = currentTarget; - } - } - // acquire objects pointed to by pointers in target - currentTarget?.[POINTER_VISITOR$8]?.(callback, { vivificate: true, isMutable: () => writable }); - if (newTarget !== currentTarget) { - newTarget?.[POINTER_VISITOR$8]?.(callback, { vivificate: true, isMutable: () => writable }); - pointer[SLOTS$8][0] = newTarget; - if (env.inFixedMemory(pointer)) { - pointer[FIXED_LOCATION$8] = location; - } - } - }; - args[POINTER_VISITOR$8](callback, { vivificate: true }); +function isReadOnly$8(type) { + switch (type) { + case MemberType$8.Type: + case MemberType$8.Comptime: + case MemberType$8.Literal: + return true; + default: + return false; } +} - /* COMPTIME-ONLY */ - acquireDefaultPointers(structure) { - const { constructor, hasPointer, instance: { template } } = structure; - if (hasPointer && template && template[MEMORY$8]) { - // create a placeholder for retrieving default pointers - const placeholder = Object.create(constructor.prototype); - placeholder[MEMORY$8] = template[MEMORY$8]; - placeholder[SLOTS$8] = template[SLOTS$8]; - this.acquirePointerTargets(placeholder); - } - } - /* COMPTIME-ONLY-END */ +const factories$o = {}; + +function useVoid$8() { + factories$o[MemberType$8.Void] = getVoidDescriptor$8; } -class CallContext { - pointerProcessed = new Map(); - memoryList = []; - shadowMap = null; - /* WASM-ONLY */ - call = 0; - /* WASM-ONLY-END */ +function useBool$8() { + factories$o[MemberType$8.Bool] = getBoolDescriptor$8; } -function findSortedIndex(array, value, cb) { - let low = 0; - let high = array.length; - if (high === 0) { - return 0; - } - while (low < high) { - const mid = Math.floor((low + high) / 2); - const value2 = cb(array[mid]); - if (value2 <= value) { - low = mid + 1; - } else { - high = mid; - } - } - return high; +function useInt$8() { + factories$o[MemberType$8.Int] = getIntDescriptor$8; } -function findMemoryIndex(array, address) { - return findSortedIndex(array, address, m => m.address); +function useUint$8() { + factories$o[MemberType$8.Uint] = getUintDescriptor$8; } -function add(address, len) { - return address + ((typeof(address) === 'bigint') ? BigInt(len) : len); +function useFloat$8() { + factories$o[MemberType$8.Float] = getFloatDescriptor$8; } -function isInvalidAddress(address) { - if (typeof(address) === 'bigint') { - return address === 0xaaaaaaaaaaaaaaaan; - } else { - return address === 0xaaaaaaaa; - } +function useObject$8() { + factories$o[MemberType$8.Object] = getObjectDescriptor$8; } -function isElectron() { - return typeof(process) === 'object' - && typeof(process?.versions) === 'object' - && !!process.versions?.electron; +function useType$8() { + factories$o[MemberType$8.Type] = getTypeDescriptor$8; } -class WebAssemblyEnvironment extends Environment { - imports = { - getFactoryThunk: { argType: '', returnType: 'i' }, - allocateExternMemory: { argType: 'ii', returnType: 'i' }, - freeExternMemory: { argType: 'iii' }, - allocateShadowMemory: { argType: 'cii', returnType: 'v' }, - freeShadowMemory: { argType: 'ciii' }, - runThunk: { argType: 'iv', returnType: 'v' }, - isRuntimeSafetyActive: { argType: '', returnType: 'b' }, - }; - exports = { - allocateHostMemory: { argType: 'ii', returnType: 'v' }, - freeHostMemory: { argType: 'iii' }, - captureString: { argType: 'ii', returnType: 'v' }, - captureView: { argType: 'iib', returnType: 'v' }, - castView: { argType: 'vvb', returnType: 'v' }, - getSlotNumber: { argType: 'ii', returnType: 'i' }, - readSlot: { argType: 'vi', returnType: 'v' }, - writeSlot: { argType: 'viv' }, - getViewAddress: { argType: 'v', returnType: 'i' }, - beginDefinition: { returnType: 'v' }, - insertInteger: { argType: 'vsi', alias: 'insertProperty' }, - insertBoolean: { argType: 'vsb', alias: 'insertProperty' }, - insertString: { argType: 'vss', alias: 'insertProperty' }, - insertObject: { argType: 'vsv', alias: 'insertProperty' }, - beginStructure: { argType: 'v', returnType: 'v' }, - attachMember: { argType: 'vvb' }, - attachMethod: { argType: 'vvb' }, - createTemplate: { argType: 'v', returnType: 'v' }, - attachTemplate: { argType: 'vvb' }, - finalizeShape: { argType: 'v' }, - endStructure: { argType: 'v' }, - startCall: { argType: 'iv', returnType: 'i' }, - endCall: { argType: 'iv', returnType: 'i' }, - }; - nextValueIndex = 1; - valueTable = { 0: null }; - valueIndices = new Map; - memory = null; - // WASM is always little endian - littleEndian = true; +function useComptime$8() { + factories$o[MemberType$8.Comptime] = getComptimeDescriptor$8; +} - allocateHostMemory(len, align) { - // allocate memory in both JavaScript and WASM space - const constructor = { [ALIGN$8]: align }; - const copier = getMemoryCopier$8(len); - const dv = this.allocateRelocMemory(len, align); - const shadowDV = this.allocateShadowMemory(len, align); - // create a shadow for the relocatable memory - const object = { constructor, [MEMORY$8]: dv, [COPIER$8]: copier }; - const shadow = { constructor, [MEMORY$8]: shadowDV, [COPIER$8]: copier }; - shadow[ATTRIBUTES] = { address: this.getViewAddress(shadowDV), len, align }; - this.addShadow(shadow, object, align); - return shadowDV; - } +function useStatic$8() { + factories$o[MemberType$8.Static] = getStaticDescriptor$8; +} - freeHostMemory(address, len, align) { - const dv = this.findMemory(address, len); - this.removeShadow(dv); - this.unregisterMemory(address); - this.freeShadowMemory(address, len, align); - } +function useLiteral$8() { + factories$o[MemberType$8.Literal] = getLiteralDescriptor$8; +} - getBufferAddress(buffer) { - return 0; - } +function useNull$8() { + factories$o[MemberType$8.Null] = getNullDescriptor$8; +} - allocateFixedMemory(len, align) { - if (len === 0) { - return new DataView(this.memory.buffer, 0, 0); - } - const address = this.allocateExternMemory(len, align); - const dv = this.obtainFixedView(address, len); - dv[ALIGN$8] = align; - return dv; - } +function useUndefined$8() { + factories$o[MemberType$8.Undefined] = getUndefinedDescriptor$8; +} - freeFixedMemory(address, len, align) { - if (len === 0) { - return; - } - this.freeExternMemory(address, len, align); - } +const transformers = {}; - obtainFixedView(address, len) { - const { memory } = this; - if (len === 0 && address === -1431655766) { // 0xAAAAAAAA - address = 0; - } - const dv = this.obtainView(memory.buffer, address, len); - dv[MEMORY$8] = { memory, address, len }; - return dv; - } +function useEnumerationTransform() { + transformers[StructureType$8.Enumeration] = transformEnumerationDescriptor; +} - releaseFixedView(dv) { - dv.buffer; - const address = dv.byteOffset; - const len = dv.byteLength; - // only allocated memory would have align attached - const align = dv[ALIGN$8]; - if (align !== undefined) { - this.freeFixedMemory(address, len, align); - } - } +function useErrorSetTransform() { + transformers[StructureType$8.ErrorSet] = transformErrorSetDescriptor; +} - inFixedMemory(object) { - // reconnect any detached buffer before checking - if (!this.memory) { - return false; - } - restoreMemory$8.call(object); - return object[MEMORY$8].buffer === this.memory.buffer; - } +function isByteAligned$8({ bitOffset, bitSize, byteSize }) { + return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; +} - copyBytes(dst, address, len) { - const { memory } = this; - const src = new DataView(memory.buffer, address, len); - const copy = getCopyFunction$8(len); - copy(dst, src); - } +function getDescriptor$8(member, env) { + const f = factories$o[member.type]; + return f(member, env); +} - findSentinel(address, bytes) { - const { memory } = this; - const len = bytes.byteLength; - const end = memory.buffer.byteLength - len + 1; - for (let i = address; i < end; i += len) { - const dv = new DataView(memory.buffer, i, len); - let match = true; - for (let j = 0; j < len; j++) { - const a = dv.getUint8(j); - const b = bytes.getUint8(j); - if (a !== b) { - match = false; - break; +function transformDescriptor(descriptor, member) { + const { structure } = member; + const t = transformers[structure?.type]; + return (t) ? t(descriptor, structure) : descriptor; +} + +function getVoidDescriptor$8(member, env) { + const { runtimeSafety } = env; + return { + get: function() { + return undefined; + }, + set: (runtimeSafety) + ? function(value) { + if (value !== undefined) { + throwNotUndefined$8(member); } } - if (match) { - return (i - address) / len; - } - } + : function() {}, } +} - captureString(address, len) { - const { buffer } = this.memory; - const ta = new Uint8Array(buffer, address, len); - return decodeText$8(ta); +function getNullDescriptor$8(member, env) { + return { + get: function() { + return null; + }, } +} - getTargetAddress(target, cluster) { - if (this.inFixedMemory(target)) { - return this.getViewAddress(target[MEMORY$8]); - } - if (target[MEMORY$8].byteLength === 0) { - // it's a null pointer/empty slice - return 0; - } - // relocatable buffers always need shadowing - return false; +function getUndefinedDescriptor$8(member, env) { + return { + get: function() { + return undefined; + }, } +} - clearExchangeTable() { - if (this.nextValueIndex !== 1) { - this.nextValueIndex = 1; - this.valueTable = { 0: null }; - this.valueIndices = new Map(); - } - } +function getBoolDescriptor$8(member, env) { + return getDescriptorUsing$8(member, env, getBoolAccessor$8) +} - getObjectIndex(object) { - if (object) { - let index = this.valueIndices.get(object); - if (index === undefined) { - index = this.nextValueIndex++; - this.valueIndices.set(object, index); - this.valueTable[index] = object; - } - return index; - } else { - return 0; - } - } +function getIntDescriptor$8(member, env) { + const getDataViewAccessor = addRuntimeCheck$8(env, getNumericAccessor$8); + const descriptor = getDescriptorUsing$8(member, env, getDataViewAccessor); + return transformDescriptor(descriptor, member); +} - fromWebAssembly(type, arg) { - switch (type) { - case 'v': - case 's': return this.valueTable[arg]; - case 'i': return arg; - case 'b': return !!arg; - } - } +function getUintDescriptor$8(member, env) { + const getDataViewAccessor = addRuntimeCheck$8(env, getNumericAccessor$8); + const descriptor = getDescriptorUsing$8(member, env, getDataViewAccessor); + return transformDescriptor(descriptor, member); +} - toWebAssembly(type, arg) { - switch (type) { - case 'v': - case 's': return this.getObjectIndex(arg); - case 'i': return arg; - case 'b': return arg ? 1 : 0; +function addRuntimeCheck$8(env, getDataViewAccessor) { + return function (access, member) { + const { + runtimeSafety = true, + } = env; + const accessor = getDataViewAccessor(access, member); + if (runtimeSafety && access === 'set') { + const { min, max } = getIntRange$8(member); + return function(offset, value, littleEndian) { + if (value < min || value > max) { + throwOverflow$8(member, value); + } + accessor.call(this, offset, value, littleEndian); + }; } - } + return accessor; + }; +} - exportFunction(fn, argType = '', returnType = '') { - if (!fn) { - return () => {}; - } - return (...args) => { - args = args.map((arg, i) => this.fromWebAssembly(argType.charAt(i), arg)); - const retval = fn.apply(this, args); - return this.toWebAssembly(returnType, retval); - }; - } +function getFloatDescriptor$8(member, env) { + return getDescriptorUsing$8(member, env, getNumericAccessor$8) +} - importFunction(fn, argType = '', returnType = '') { - let needCallContext = false; - if (argType.startsWith('c')) { - needCallContext = true; - argType = argType.slice(1); +function transformEnumerationDescriptor(int, structure) { + const findEnum = function(value) { + const { constructor } = structure; + // the enumeration constructor returns the object for the int value + const item = constructor(value); + if (!item) { + throwEnumExpected$8(structure, value); } - return (...args) => { - args = args.map((arg, i) => this.toWebAssembly(argType.charAt(i), arg)); - if (needCallContext) { - args = [ this.context.call, ...args ]; + return item + }; + return { + get: (int.get.length === 0) + ? function getEnum(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } + return findEnum(value); } - const retval = fn.apply(this, args); - return this.fromWebAssembly(returnType, retval); - }; - } - - exportFunctions() { - const imports = {}; - for (const [ name, { argType, returnType, alias } ] of Object.entries(this.exports)) { - const fn = this[alias ?? name]; - imports[`_${name}`] = this.exportFunction(fn, argType, returnType); - } - return imports; - } + : function getEnumElement(index) { + const value = int.get.call(this, index); + return findEnum(value); + }, + set: (int.set.length === 1) + ? function setEnum(value, hint) { + if (hint !== 'number') { + const item = findEnum(value); + // call Symbol.toPrimitive directly as enum can be bigint or number + value = item[Symbol.toPrimitive](); + } + int.set.call(this, value); + } + : function setEnumElement(index, value) { + const item = findEnum(value); + int.set.call(this, index, item[Symbol.toPrimitive]()); + }, + }; +} - importFunctions(exports) { - for (const [ name, fn ] of Object.entries(exports)) { - const info = this.imports[name]; - if (info) { - const { argType, returnType } = info; - this[name] = this.importFunction(fn, argType, returnType); +function transformErrorSetDescriptor(int, structure) { + const findError = function(value) { + const { constructor } = structure; + const item = constructor(value); + if (!item) { + if (value instanceof Error) { + throwNotInErrorSet$8(structure); + } else { + throwErrorExpected$8(structure, value); } - } - } + } + return item + }; + return { + get: (int.get.length === 0) + ? function getError(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } + return findError(value); + } + : function getErrorElement(index) { + const value = int.get.call(this, index); + return findError(value); + }, + set: (int.set.length === 1) + ? function setError(value, hint) { + if (hint !== 'number') { + const item = findError(value); + value = Number(item); + } + int.set.call(this, value); + } + : function setError(index, value) { + const item = findError(value); + value = Number(item); + int.set.call(this, index, value); + }, + }; +} - async instantiateWebAssembly(source) { - const res = await source; - const env = this.exportFunctions(); - const wasi = this.getWASI(); - const imports = { env, wasi_snapshot_preview1: wasi }; - if (res[Symbol.toStringTag] === 'Response') { - return WebAssembly.instantiateStreaming(res, imports); - } else { - return WebAssembly.instantiate(res, imports); - } +function isValueExpected$8(structure) { + switch (structure.type) { + case StructureType$8.Primitive: + case StructureType$8.ErrorUnion: + case StructureType$8.Optional: + case StructureType$8.Enumeration: + case StructureType$8.ErrorSet: + return true; + default: + return false; } +} - loadModule(source) { - return this.initPromise = (async () => { - const { instance } = await this.instantiateWebAssembly(source); - const { memory, _initialize } = instance.exports; - this.importFunctions(instance.exports); - this.trackInstance(instance); - this.runtimeSafety = this.isRuntimeSafetyActive(); - this.memory = memory; - _initialize?.(); - })(); - } +function getValue$8(slot) { + const object = this[SLOTS$8][slot] ?? this[VIVIFICATOR$8](slot); + return object[GETTER$8](); +} + +function getObject$8(slot) { + const object = this[SLOTS$8][slot] ?? this[VIVIFICATOR$8](slot); + return object; +} - trackInstance(instance) { - // use WeakRef to detect whether web-assembly instance has been gc'ed - const ref = new WeakRef(instance); - Object.defineProperty(this, 'released', { get: () => !ref.deref(), enumerable: true }); - } +function setValue$8(slot, value) { + const object = this[SLOTS$8][slot] ?? this[VIVIFICATOR$8](slot); + object[SETTER$8](value); +} - linkVariables(writeBack) { - // linkage occurs when WASM compilation is complete and functions have been imported - // nothing needs to happen when WASM is not used - if (this.initPromise) { - this.initPromise = this.initPromise.then(() => super.linkVariables(writeBack)); - } +function bindSlot$8(slot, { get, set }) { + if (slot !== undefined) { + return { + get: function() { + return get.call(this, slot); + }, + set: (set) + ? function(arg) { + return set.call(this, slot, arg); + } + : undefined, + }; + } else { + // array accessors + return { get, set }; } +} - /* COMPTIME-ONLY */ - beginDefinition() { - return {}; - } +function getObjectDescriptor$8(member, env) { + const { structure, slot } = member; + return bindSlot$8(slot, { + get: isValueExpected$8(structure) ? getValue$8 : getObject$8, + set: setValue$8, + }); +} - insertProperty(def, name, value) { - def[name] = value; - } - /* COMPTIME-ONLY-END */ +function getType$8(slot) { + // unsupported types will have undefined structure + const structure = this[SLOTS$8][slot]; + return structure?.constructor; +} - getMemoryOffset(address) { - // WASM address space starts at 0 - return address; - } +function getTypeDescriptor$8(member, env) { + const { slot } = member; + return bindSlot$8(slot, { get: getType$8 }); +} - recreateAddress(reloc) { - return reloc; - } +function getComptimeDescriptor$8(member, env) { + const { slot, structure } = member; + return bindSlot$8(slot, { + get: isValueExpected$8(structure) ? getValue$8 : getObject$8, + }); +} - startCall(call, args) { - this.startContext(); - // call context, used by allocateShadowMemory and freeShadowMemory - this.context.call = call; - if (args[POINTER_VISITOR$8]) { - this.updatePointerAddresses(args); - } - // return address of shadow for argumnet struct - const address = this.getShadowAddress(args); - this.updateShadows(); - return address; - } +function getStaticDescriptor$8(member, env) { + const { slot, structure } = member; + return bindSlot$8(slot, { + get: isValueExpected$8(structure) ? getValue$8 : getObject$8, + set: setValue$8, + }); +} - endCall(call, args) { - this.updateShadowTargets(); - if (args[POINTER_VISITOR$8]) { - this.acquirePointerTargets(args); - } - this.releaseShadows(); - // restore the previous context if there's one - this.endContext(); - if (!this.context && this.flushConsole) { - this.flushConsole(); - } - } +function getLiteral$8(slot) { + const object = this[SLOTS$8][slot]; + return object.string; +} - async runThunk(thunkId, args) { - // wait for compilation - await this.initPromise; - // invoke runThunk() from WASM code - return this.runThunk(thunkId, args); - } +function getLiteralDescriptor$8(member, env) { + const { slot } = member; + return bindSlot$8(slot, { get: getLiteral$8 }); +} - invokeThunk(thunkId, args) { - // wasm-exporter.zig will invoke startCall() with the context address and the args - // we can't do pointer fix up here since we need the context in order to allocate - // memory from the WebAssembly allocator; pointer target acquisition will happen in - // endCall() - const err = this.runThunk(thunkId, args); - // errors returned by exported Zig functions are normally written into the - // argument object and get thrown when we access its retval property (a zig error union) - // error strings returned by the thunk are due to problems in the thunking process - // (i.e. bugs in export.zig) - if (err) { - if (err[Symbol.toStringTag] === 'Promise') { - // getting a promise, WASM is not yet ready - // wait for fulfillment, then either return result or throw - return err.then((err) => { - if (err) { - throwZigError(err); +function getDescriptorUsing$8(member, env, getDataViewAccessor) { + const { + littleEndian = true, + } = env; + const { bitOffset, byteSize } = member; + const getter = getDataViewAccessor('get', member); + const setter = getDataViewAccessor('set', member); + if (bitOffset !== undefined) { + const offset = bitOffset >> 3; + return { + get: function getValue() { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return getter.call(this[MEMORY$8], offset, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$8.call(this)) { + return getter.call(this[MEMORY$8], offset, littleEndian); + } else { + throw err; } - return args.retval; - }); - } else { - throwZigError(err); + } + /* WASM-ONLY-END*/ + }, + set: function setValue(value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return setter.call(this[MEMORY$8], offset, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$8.call(this)) { + return setter.call(this[MEMORY$8], offset, value, littleEndian); + } else { + throw err; + } + } + /* WASM-ONLY-END*/ } } - return args.retval; - } - - getWASI() { - return { - proc_exit: (rval) => { - }, - fd_write: (fd, iovs_ptr, iovs_count, written_ptr) => { - if (fd === 1 || fd === 2) { - const dv = new DataView(this.memory.buffer); - let written = 0; - for (let i = 0, p = iovs_ptr; i < iovs_count; i++, p += 8) { - const buf_ptr = dv.getUint32(p, true); - const buf_len = dv.getUint32(p + 4, true); - const buf = new DataView(this.memory.buffer, buf_ptr, buf_len); - this.writeToConsole(buf); - written += buf_len; + } else { + return { + get: function getElement(index) { + try { + return getter.call(this[MEMORY$8], index * byteSize, littleEndian); + } catch (err) { + /* WASM-ONLY */ + if (err instanceof TypeError && restoreMemory$8.call(this)) { + return getter.call(this[MEMORY$8], index * byteSize, littleEndian); + } else { + /* WASM-ONLY-END */ + rethrowRangeError$8(member, index, err); + /* WASM-ONLY */ } - dv.setUint32(written_ptr, written, true); - return 0; - } else { - return 1; + /* WASM-ONLY-END */ } }, - random_get: (buf, buf_len) => { - const dv = new DataView(this.memory.buffer); - for (let i = 0; i < buf_len; i++) { - dv.setUint8(Math.floor(256 * Math.random())); + set: function setElement(index, value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END */ + return setter.call(this[MEMORY$8], index * byteSize, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$8.call(this)) { + return setter.call(this[MEMORY$8], index * byteSize, value, littleEndian); + } else { + rethrowRangeError$8(member, index, err); + } } - return 0; + /* WASM-ONLY-END */ }, - }; + } } } +function useAllMemberTypes$8() { + useVoid$8(); + useNull$8(); + useUndefined$8(); + useBool$8(); + useInt$8(); + useUint$8(); + useFloat$8(); + useObject$8(); + useType$8(); + useComptime$8(); + useStatic$8(); + useLiteral$8(); +} + +process.cwd(); + useAllMemberTypes$8(); useAllStructureTypes$8(); useAllExtendedTypes$8(); -/* COMPTIME-ONLY-END */ - -function createEnvironment(source) { - return new WebAssemblyEnvironment(); -} const MEMORY$7 = Symbol('memory'); const SLOTS$7 = Symbol('slots'); @@ -10640,11 +15574,6 @@ function useAllMemberTypes$7() { process.cwd(); -function findSourceFile$1(modulePath, options) { - const { sourceFiles } = options; - return sourceFiles?.[modulePath]; -} - useAllMemberTypes$7(); useAllStructureTypes$7(); useAllExtendedTypes$7(); diff --git a/zigar-compiler/dist/index.js b/zigar-compiler/dist/index.js index 03d9e11b..745928cf 100644 --- a/zigar-compiler/dist/index.js +++ b/zigar-compiler/dist/index.js @@ -6,219 +6,113 @@ import { sep, dirname, parse, join, basename, resolve } from 'path'; import { fileURLToPath } from 'url'; import { createHash } from 'crypto'; -const MEMORY$7 = Symbol('memory'); -const SLOTS$7 = Symbol('slots'); -const PARENT$7 = Symbol('parent'); -const NAME$7 = Symbol('name'); -const TAG$7 = Symbol('tag'); -const ITEMS$7 = Symbol('items'); -const PROPS$7 = Symbol('props'); -const GETTER$7 = Symbol('getter'); -const SETTER$7 = Symbol('setter'); -const ELEMENT_GETTER$7 = Symbol('elementGetter'); -const ELEMENT_SETTER$7 = Symbol('elementSetter'); -const LOCATION_GETTER$7 = Symbol('addressGetter'); -const LOCATION_SETTER$7 = Symbol('addressSetter'); -const TARGET_GETTER$7 = Symbol('targetGetter'); -const TARGET_SETTER$7 = Symbol('targetSetter'); -const FIXED_LOCATION$7 = Symbol('fixedLocation'); -const PROP_GETTERS$7 = Symbol('propGetters'); -const PROP_SETTERS$7 = Symbol('propSetters'); -const ALL_KEYS$7 = Symbol('allKeys'); -const LENGTH$7 = Symbol('length'); -const PROXY$7 = Symbol('proxy'); -const COMPAT$7 = Symbol('compat'); -const SIZE$7 = Symbol('size'); -const ALIGN$7 = Symbol('align'); -const ARRAY$7 = Symbol('array'); -const POINTER$7 = Symbol('pointer'); -const CONST$7 = Symbol('const'); -const CONST_PROTOTYPE$7 = Symbol('constProto'); -const COPIER$7 = Symbol('copier'); -const RESETTER$7 = Symbol('resetter'); -const NORMALIZER$7 = Symbol('normalizer'); -const VIVIFICATOR$7 = Symbol('vivificator'); -const POINTER_VISITOR$7 = Symbol('pointerVisitor'); -const ENVIRONMENT$7 = Symbol('environment'); +const MEMORY$a = Symbol('memory'); +const SLOTS$a = Symbol('slots'); +const PARENT$a = Symbol('parent'); +const NAME$a = Symbol('name'); +const CLASS$2 = Symbol('class'); +const PROPS$a = Symbol('props'); +const GETTER$a = Symbol('getter'); +const SETTER$a = Symbol('setter'); +const LOCATION_GETTER$a = Symbol('addressGetter'); +const FIXED_LOCATION$a = Symbol('fixedLocation'); +const SIZE$a = Symbol('size'); +const ALIGN$a = Symbol('align'); +const POINTER$a = Symbol('pointer'); +const CONST$a = Symbol('const'); +const COPIER$a = Symbol('copier'); +const NORMALIZER$a = Symbol('normalizer'); +const VIVIFICATOR$a = Symbol('vivificator'); +const POINTER_VISITOR$a = Symbol('pointerVisitor'); +const ENVIRONMENT$a = Symbol('environment'); const ATTRIBUTES = Symbol('attributes'); -const MORE$7 = Symbol('more'); - -function getDestructor$7(env) { - return function() { - const dv = this[MEMORY$7]; - this[MEMORY$7] = null; - if (this[SLOTS$7]) { - this[SLOTS$7] = {}; - } - env.releaseFixedView(dv); - }; -} - -function getBitAlignFunction$7(bitPos, bitSize, toAligned) { - if (bitPos + bitSize <= 8) { - const mask = (2 ** bitSize) - 1; - if (toAligned) { - // from single byte - return function(dest, src, offset) { - const n = src.getUint8(offset); - const b = (n >> bitPos) & mask; - dest.setUint8(0, b); - }; - } else { - // to single byte - const destMask = 0xFF ^ (mask << bitPos); - return function(dest, src, offset) { - const n = src.getUint8(0); - const d = dest.getUint8(offset); - const b = (d & destMask) | ((n & mask) << bitPos); - dest.setUint8(offset, b); - }; - } - } else { - const leadBits = 8 - bitPos; - const leadMask = (2 ** leadBits) - 1; - if (toAligned) { - const trailBits = bitSize % 8; - const trailMask = (2 ** trailBits) - 1; - return function(dest, src, offset) { - let i = offset, j = 0; - let n = src.getUint8(i++), b; - let bitBuf = (n >> bitPos) & leadMask; - let bitCount = leadBits; - let remaining = bitSize; - do { - if (remaining > bitCount) { - n = src.getUint8(i++); - bitBuf = bitBuf | (n << bitCount); - //bitCount += 8; - } - b = (remaining >= 8) ? bitBuf & 0xFF : bitBuf & trailMask; - dest.setUint8(j++, b); - bitBuf >>= 8; - //bitCount -= 8; - remaining -= 8; - } while (remaining > 0); - } - } else { - const trailBits = (bitSize - leadBits) % 8; - const trailMask = (2 ** trailBits) - 1; - const destMask1 = 0xFF ^ (leadMask << bitPos); - const destMask2 = 0xFF ^ trailMask; - return function(dest, src, offset) { - let i = 0, j = offset; - // preserve bits ahead of bitPos - let d = dest.getUint8(j), n, b; - let bitBuf = d & destMask1; - let bitCount = bitPos; - let remaining = bitSize + bitCount; - do { - if (remaining > bitCount) { - n = src.getUint8(i++); - bitBuf = bitBuf | (n << bitCount); - bitCount += 8; - } - if (remaining >= 8) { - b = bitBuf & 0xFF; - } else { - // preserve bits at the destination sitting behind the trailing bits - d = dest.getUint8(j); - b = (d & destMask2) | (bitBuf & trailMask); - } - dest.setUint8(j++, b); - bitBuf >>= 8; - bitCount -= 8; - remaining -= 8; - } while (remaining > 0); - } - } - } -} +const MORE$a = Symbol('more'); -function getMemoryCopier$7(size, multiple = false) { - const copy = getCopyFunction$7(size, multiple); +function getMemoryCopier$a(size, multiple = false) { + const copy = getCopyFunction$a(size, multiple); return function(target) { /* WASM-ONLY */ - restoreMemory$7.call(this); - restoreMemory$7.call(target); + restoreMemory$a.call(this); + restoreMemory$a.call(target); /* WASM-ONLY-END */ - const src = target[MEMORY$7]; - const dest = this[MEMORY$7]; + const src = target[MEMORY$a]; + const dest = this[MEMORY$a]; copy(dest, src); }; } -function getCopyFunction$7(size, multiple = false) { +function getCopyFunction$a(size, multiple = false) { if (!multiple) { - const copier = copiers$7[size]; + const copier = copiers$a[size]; if (copier) { return copier; } } - if (!(size & 0x07)) return copy8x$7; - if (!(size & 0x03)) return copy4x$7; - if (!(size & 0x01)) return copy2x$7; - return copy1x$7; + if (!(size & 0x07)) return copy8x$a; + if (!(size & 0x03)) return copy4x$a; + if (!(size & 0x01)) return copy2x$a; + return copy1x$a; } -const copiers$7 = { - 1: copy1$7, - 2: copy2$7, - 4: copy4$7, - 8: copy8$7, - 16: copy16$7, - 32: copy32$7, +const copiers$a = { + 1: copy1$a, + 2: copy2$a, + 4: copy4$a, + 8: copy8$a, + 16: copy16$a, + 32: copy32$a, }; -function copy1x$7(dest, src) { +function copy1x$a(dest, src) { for (let i = 0, len = dest.byteLength; i < len; i++) { dest.setInt8(i, src.getInt8(i)); } } -function copy2x$7(dest, src) { +function copy2x$a(dest, src) { for (let i = 0, len = dest.byteLength; i < len; i += 2) { dest.setInt16(i, src.getInt16(i, true), true); } } -function copy4x$7(dest, src) { +function copy4x$a(dest, src) { for (let i = 0, len = dest.byteLength; i < len; i += 4) { dest.setInt32(i, src.getInt32(i, true), true); } } -function copy8x$7(dest, src) { +function copy8x$a(dest, src) { for (let i = 0, len = dest.byteLength; i < len; i += 8) { dest.setInt32(i, src.getInt32(i, true), true); dest.setInt32(i + 4, src.getInt32(i + 4, true), true); } } -function copy1$7(dest, src) { +function copy1$a(dest, src) { dest.setInt8(0, src.getInt8(0)); } -function copy2$7(dest, src) { +function copy2$a(dest, src) { dest.setInt16(0, src.getInt16(0, true), true); } -function copy4$7(dest, src) { +function copy4$a(dest, src) { dest.setInt32(0, src.getInt32(0, true), true); } -function copy8$7(dest, src) { +function copy8$a(dest, src) { dest.setInt32(0, src.getInt32(0, true), true); dest.setInt32(4, src.getInt32(4, true), true); } -function copy16$7(dest, src) { +function copy16$a(dest, src) { dest.setInt32(0, src.getInt32(0, true), true); dest.setInt32(4, src.getInt32(4, true), true); dest.setInt32(8, src.getInt32(8, true), true); dest.setInt32(12, src.getInt32(12, true), true); } -function copy32$7(dest, src) { +function copy32$a(dest, src) { dest.setInt32(0, src.getInt32(0, true), true); dest.setInt32(4, src.getInt32(4, true), true); dest.setInt32(8, src.getInt32(8, true), true); @@ -229,117 +123,25 @@ function copy32$7(dest, src) { dest.setInt32(28, src.getInt32(28, true), true); } -function getMemoryResetter$7(offset, size) { - const reset = getResetFunction$7(size); - return function() { - /* WASM-ONLY */ - restoreMemory$7.call(this); - /* WASM-ONLY-END */ - const dest = this[MEMORY$7]; - reset(dest, offset, size); - }; -} - -function getResetFunction$7(size) { - const resetter = resetters$7[size]; - if (resetter) { - return resetter; - } - if (!(size & 0x07)) return reset8x$7; - if (!(size & 0x03)) return reset4x$7; - if (!(size & 0x01)) return reset2x$7; - return reset1x$7; -} - -const resetters$7 = { - 1: reset1$7, - 2: reset2$7, - 4: reset4$7, - 8: reset8$7, - 16: reset16$7, - 32: reset32$7, -}; - -function reset1x$7(dest, offset, size) { - for (let i = offset, limit = offset + size; i < limit; i++) { - dest.setInt8(i, 0); - } -} - -function reset2x$7(dest, offset, size) { - for (let i = offset, limit = offset + size; i < limit; i += 2) { - dest.setInt16(i, 0, true); - } -} - -function reset4x$7(dest, offset, size) { - for (let i = offset, limit = offset + size; i < limit; i += 4) { - dest.setInt32(i, 0, true); - } -} - -function reset8x$7(dest, offset, size) { - for (let i = offset, limit = offset + size; i < limit; i += 8) { - dest.setInt32(i, 0, true); - dest.setInt32(i + 4, 0, true); - } -} - -function reset1$7(dest, offset) { - dest.setInt8(offset, 0); -} - -function reset2$7(dest, offset) { - dest.setInt16(offset, 0, true); -} - -function reset4$7(dest, offset) { - dest.setInt32(offset, 0, true); -} - -function reset8$7(dest, offset) { - dest.setInt32(offset + 0, 0, true); - dest.setInt32(offset + 4, 0, true); -} - -function reset16$7(dest, offset) { - dest.setInt32(offset + 0, 0, true); - dest.setInt32(offset + 4, 0, true); - dest.setInt32(offset + 8, 0, true); - dest.setInt32(offset + 12, 0, true); -} - -function reset32$7(dest, offset) { - dest.setInt32(offset + 0, 0, true); - dest.setInt32(offset + 4, 0, true); - dest.setInt32(offset + 8, 0, true); - dest.setInt32(offset + 12, 0, true); - dest.setInt32(offset + 16, 0, true); - dest.setInt32(offset + 20, 0, true); - dest.setInt32(offset + 24, 0, true); - dest.setInt32(offset + 28, 0, true); -} - -function restoreMemory$7() { - const dv = this[MEMORY$7]; - const source = dv[MEMORY$7]; +function restoreMemory$a() { + const dv = this[MEMORY$a]; + const source = dv[MEMORY$a]; if (!source || dv.buffer.byteLength !== 0) { return false; } const { memory, address, len } = source; const newDV = new DataView(memory.buffer, address, len); - newDV[MEMORY$7] = source; - this[MEMORY$7] = newDV; + newDV[MEMORY$a] = source; + this[MEMORY$a] = newDV; return true; } -const decoders$7 = {}; -const encoders$7 = {}; +const decoders$a = {}; -function decodeText$7(arrays, encoding = 'utf-8') { - let decoder = decoders$7[encoding]; +function decodeText$a(arrays, encoding = 'utf-8') { + let decoder = decoders$a[encoding]; if (!decoder) { - decoder = decoders$7[encoding] = new TextDecoder(encoding); + decoder = decoders$a[encoding] = new TextDecoder(encoding); } let array; if (Array.isArray(arrays)) { @@ -364,46 +166,11 @@ function decodeText$7(arrays, encoding = 'utf-8') { return decoder.decode(array); } -function encodeText$7(text, encoding = 'utf-8') { - switch (encoding) { - case 'utf-16': { - const { length } = text; - const ta = new Uint16Array(length); - for (let i = 0; i < length; i++) { - ta[i] = text.charCodeAt(i); - } - return ta; - } - default: { - let encoder = encoders$7[encoding]; - if (!encoder) { - encoder = encoders$7[encoding] = new TextEncoder(); - } - return encoder.encode(text); - } - } -} - -function encodeBase64$7(dv) { - const ta = new Uint8Array(dv.buffer, dv.byteOffset, dv.byteLength); - const bstr = String.fromCharCode.apply(null, ta); - return btoa(bstr); -} - -function decodeBase64$7(str) { - const bstr = atob(str); - const ta = new Uint8Array(bstr.length); - for (let i = 0; i < ta.byteLength; i++) { - ta[i] = bstr.charCodeAt(i); - } - return new DataView(ta.buffer); -} - -function getValueOf$7() { +function getValueOf$a() { const map = new Map(); const options = { error: 'throw' }; const process = function(value) { - const normalizer = value?.[NORMALIZER$7]; + const normalizer = value?.[NORMALIZER$a]; if (normalizer) { let result = map.get(value); if (result === undefined) { @@ -418,26 +185,26 @@ function getValueOf$7() { return process(this); } -const INT_MAX$7 = BigInt(Number.MAX_SAFE_INTEGER); -const INT_MIN$7 = BigInt(Number.MIN_SAFE_INTEGER); +const INT_MAX$a = BigInt(Number.MAX_SAFE_INTEGER); +const INT_MIN$a = BigInt(Number.MIN_SAFE_INTEGER); -function convertToJSON$7() { +function convertToJSON$a() { const map = new Map(); const options = { error: 'return' }; const process = function(value) { - const normalizer = value?.[NORMALIZER$7]; + const normalizer = value?.[NORMALIZER$a]; if (normalizer) { - if (value instanceof Error) { - return { error: value.message }; - } let result = map.get(value); if (result === undefined) { result = normalizer.call(value, process, options); + if (typeof(result?.toJSON) === 'function') { + result = result.toJSON(); + } map.set(value, result); } return result; } else { - if (typeof(value) === 'bigint' && INT_MIN$7 <= value && value <= INT_MAX$7) { + if (typeof(value) === 'bigint' && INT_MIN$a <= value && value <= INT_MAX$a) { return Number(value); } return value; @@ -446,12 +213,7 @@ function convertToJSON$7() { return process(this); } -function normalizeValue$7(cb, options) { - const value = handleError$7(() => this.$, options); - return cb(value); -} - -function handleError$7(cb, options = {}) { +function handleError$a(cb, options = {}) { const { error = 'throw' } = options; try { return cb(); @@ -464,6138 +226,15349 @@ function handleError$7(cb, options = {}) { } } -function getDataViewDescriptor$7(structure, handlers = {}) { - return markAsSpecial$7({ - get() { - /* WASM-ONLY */ - restoreMemory$7.call(this); - /* WASM-ONLY-END */ - return this[MEMORY$7]; - }, - set(dv) { - checkDataView$7(dv); - setDataView$7.call(this, dv, structure, true, handlers); - }, - }); +function always$a() { + return true; } -function getBase64Descriptor$7(structure, handlers = {}) { - return markAsSpecial$7({ - get() { - return encodeBase64$7(this.dataView); - }, - set(str) { - if (typeof(str) !== 'string') { - throwTypeMismatch$7('string', str); - } - const dv = decodeBase64$7(str); - setDataView$7.call(this, dv, structure, false, handlers); - } - }); +function normalizeStruct$a(cb, options) { + const object = {}; + for (const [ name, value ] of getStructEntries$a.call(this, options)) { + object[name] = cb(value); + } + return object; } -function getStringDescriptor$7(structure, handlers = {}) { - const { sentinel, instance: { members }} = structure; - const { byteSize: charSize } = members[0]; - return markAsSpecial$7({ - get() { - const dv = this.dataView; - const TypedArray = (charSize === 1) ? Int8Array : Int16Array; - const ta = new TypedArray(dv.buffer, dv.byteOffset, this.length); - const s = decodeText$7(ta, `utf-${charSize * 8}`); - return (sentinel?.value === undefined) ? s : s.slice(0, -1); - }, - set(str) { - if (typeof(str) !== 'string') { - throwTypeMismatch$7('a string', str); - } - if (sentinel?.value !== undefined) { - if (str.charCodeAt(str.length - 1) !== sentinel.value) { - str = str + String.fromCharCode(sentinel.value); - } - } - const ta = encodeText$7(str, `utf-${charSize * 8}`); - const dv = new DataView(ta.buffer); - setDataView$7.call(this, dv, structure, false, handlers); - }, - }); +function getStructEntries$a(options) { + return { + [Symbol.iterator]: getStructEntriesIterator$a.bind(this, options), + length: this[PROPS$a].length, + }; } -function getTypedArrayDescriptor$7(structure, handlers = {}) { - const { typedArray } = structure; - return markAsSpecial$7({ - get() { - const dv = this.dataView; - const length = dv.byteLength / typedArray.BYTES_PER_ELEMENT; - return new typedArray(dv.buffer, dv.byteOffset, length); - }, - set(ta) { - if (!isTypedArray$7(ta, typedArray)) { - throwTypeMismatch$7(typedArray.name, ta); +function getStructIterator$a(options) { + const entries = getStructEntries$a.call(this, options); + return entries[Symbol.iterator](); +} + +function getStructEntriesIterator$a(options) { + const self = this; + const props = this[PROPS$a]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + value = [ current, handleError$a(() => self[current], options) ]; + done = false; + } else { + done = true; } - const dv = new DataView(ta.buffer, ta.byteOffset, ta.byteLength); - setDataView$7.call(this, dv, structure, true, handlers); + return { value, done }; }, - }); + }; +} + +function getChildVivificator$k(structure) { + const { instance: { members } } = structure; + const objectMembers = {}; + for (const member of members.filter(m => m.type === MemberType$a.Object)) { + objectMembers[member.slot] = member; + } + return function vivificateChild(slot, writable = true) { + const member = objectMembers[slot]; + const { bitOffset, byteSize, structure: { constructor } } = member; + const dv = this[MEMORY$a]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + (bitOffset >> 3); + let len = byteSize; + if (len === undefined) { + if (bitOffset & 7) { + throwNotOnByteBoundary$a(member); + } + len = member.bitSize >> 3; + } + const childDV = new DataView(dv.buffer, offset, len); + const object = this[SLOTS$a][slot] = constructor.call(PARENT$a, childDV, { writable }); + return object; + } } -function markAsSpecial$7({ get, set }) { - get.special = set.special = true; - return { get, set }; +function getPointerVisitor$k(structure, visitorOptions = {}) { + const { + isChildActive = always$a, + isChildMutable = always$a, + } = visitorOptions; + const { instance: { members } } = structure; + const pointerMembers = members.filter(m => m.structure.hasPointer); + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$a, + isMutable = always$a, + } = options; + const childOptions = { + ...options, + isActive: (object) => { + // make sure parent object is active, then check whether the child is active + return isActive(this) && isChildActive.call(this, object); + }, + isMutable: (object) => { + return isMutable(this) && isChildMutable.call(this, object); + }, + }; + for (const { slot } of pointerMembers) { + if (source) { + // when src is a the struct's template, most slots will likely be empty, + // since pointer fields aren't likely to have default values + const srcChild = source[SLOTS$a]?.[slot]; + if (!srcChild) { + continue; + } + childOptions.source = srcChild; + } + const child = this[SLOTS$a][slot] ?? (vivificate ? this[VIVIFICATOR$a](slot) : null); + if (child) { + child[POINTER_VISITOR$a](cb, childOptions); + } + } + }; } -function definePointer$7(structure, env) { +function defineArgStruct$a(structure, env) { const { byteSize, align, - instance: { members: [ member ] }, - isConst, + instance: { members }, + hasPointer, } = structure; - const { - runtimeSafety = true, - } = env; - const { structure: targetStructure } = member; - const { sentinel } = targetStructure; - const isTargetSlice = (targetStructure.type === StructureType$7.Slice); - const isTargetPointer = (targetStructure.type === StructureType$7.Pointer); - const hasLength = isTargetSlice && !sentinel; - const addressSize = (hasLength) ? byteSize / 2 : byteSize; - const { get: getAddress, set: setAddress } = getDescriptor$7({ - type: MemberType$7.Uint, - bitOffset: 0, - bitSize: addressSize * 8, - byteSize: addressSize, - structure: { byteSize: addressSize }, - }, env); - const { get: getLength, set: setLength } = (hasLength) ? getDescriptor$7({ - type: MemberType$7.Uint, - bitOffset: addressSize * 8, - bitSize: addressSize * 8, - byteSize: addressSize, - structure: { name: 'usize', byteSize: addressSize }, - }, env) : {}; - const updateTarget = function() { - const prevLocation = this[FIXED_LOCATION$7]; - if (prevLocation) { - const location = this[LOCATION_GETTER$7](); - if (location.address !== prevLocation.address || location.length !== prevLocation.length) { - const { constructor: Target } = targetStructure; - const dv = env.findMemory(location.address, location.length * Target[SIZE$7]); - const target = Target.call(ENVIRONMENT$7, dv, { writable: !isConst }); - this[SLOTS$7][0] = target; - this[FIXED_LOCATION$7] = location; - } - } + const hasObject = !!members.find(m => m.type === MemberType$a.Object); + const constructor = structure.constructor = function(args) { + const dv = env.allocateMemory(byteSize, align); + this[MEMORY$a] = dv; + if (hasObject) { + this[SLOTS$a] = {}; + } + initializer.call(this, args); }; - const getTargetObject = function() { - updateTarget.call(this); - return this[SLOTS$7][0] ?? throwNullPointer$7(); + const argNames = members.slice(0, -1).map(m => m.name); + const argCount = argNames.length; + const initializer = function(args) { + if (args.length !== argCount) { + throwArgumentCountMismatch$a(structure, args.length); + } + for (const [ index, name ] of argNames.entries()) { + try { + this[name] = args[index]; + } catch (err) { + rethrowArgumentError$a(structure, index, err); + } + } }; - const setTargetObject = function(arg) { - if (env.inFixedMemory(this)) { - // the pointer sits in fixed memory--apply the change immediately - if (env.inFixedMemory(arg)) { - const loc = { - address: env.getViewAddress(arg[MEMORY$7]), - length: (hasLength) ? arg.length : 1 - }; - addressSetter.call(this, loc); - this[FIXED_LOCATION$7] = loc; - } else { - throwFixedMemoryTargetRequired$7(); - } - } - this[SLOTS$7][0] = arg; - }; - const getTarget = isValueExpected$7(targetStructure) - ? function() { - const target = getTargetObject.call(this); - return target[GETTER$7](); - } - : getTargetObject; - const setTarget = function(value) { - updateTarget.call(this); - const object = this[SLOTS$7][0] ?? throwNullPointer$7(); - return object[SETTER$7](value); - }; - const alternateCaster = function(arg, options) { - const Target = targetStructure.constructor; - if ((this === ENVIRONMENT$7 || this === PARENT$7) || arg instanceof constructor) { - // casting from buffer to pointer is allowed only if request comes from the runtime - // casting from writable to read-only is also allowed - return false; - } else if (isPointerOf$7(arg, Target)) { - // const/non-const casting - return new constructor(Target(arg['*'], { writable: !isConst }), options); - } else if (isTargetSlice) { - // allow casting to slice through constructor of its pointer - return new constructor(Target(arg), options); - } else { - throwNoCastingToPointer$7(); - } - }; - const finalizer = function() { - const handlers = (isTargetPointer) ? {} : proxyHandlers$f; - const proxy = new Proxy(this, handlers); - // hide the proxy so console wouldn't display a recursive structure - Object.defineProperty(this, PROXY$7, { value: proxy }); - return proxy; - }; - const initializer = function(arg) { - const Target = targetStructure.constructor; - if (isPointerOf$7(arg, Target)) { - // initialize with the other pointer'structure target - if (!isConst && arg.constructor.const) { - throwConstantConstraint$7(structure, arg); - } - arg = arg[SLOTS$7][0]; - } - if (arg instanceof Target) { - /* wasm-only */ - restoreMemory$7.call(arg); - /* wasm-only-end */ - if (isConst && !arg[CONST$7]) { - // create read-only version - arg = Target(arg, { writable: false }); - } else if (!isConst && arg[CONST$7]) { - throwReadOnlyTarget$7(structure); - } - } else if (isCompatible$7(arg, Target)) { - // autocast to target type - const dv = getDataView$7(targetStructure, arg, env); - arg = Target(dv, { writable: !isConst }); - } else if (arg !== undefined && !arg[MEMORY$7]) { - // autovivificate target object - const fixed = env.inFixedMemory(this); - const autoObj = new Target(arg, { writable: !isConst, fixed }); - if (runtimeSafety) { - // creation of a new slice using a typed array is probably - // not what the user wants; it's more likely that the intention - // is to point to the typed array but there's a mismatch (e.g. u32 vs i32) - if (targetStructure.typedArray && isBuffer$7(arg?.buffer)) { - warnImplicitArrayCreation$7(targetStructure, arg); - } - } - arg = autoObj; - } else if (arg !== undefined) { - throwInvalidPointerTarget$7(structure, arg); - } - this[TARGET_SETTER$7](arg); - }; - const constructor = structure.constructor = createConstructor$7(structure, { initializer, alternateCaster, finalizer }, env); - const addressSetter = function({ address, length }) { - setAddress.call(this, address); - setLength?.call(this, length); - }; - const addressGetter = function() { - const address = getAddress.call(this); - const length = (getLength) - ? getLength.call(this) - : (sentinel) - ? (address) ? env.findSentinel(address, sentinel.bytes) + 1 : 0 - : 1; - return { address, length }; - }; - const instanceDescriptors = { - '*': { get: getTarget, set: setTarget }, - '$': { get: getProxy$7, set: initializer }, - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - [TARGET_GETTER$7]: { value: getTargetObject }, - [TARGET_SETTER$7]: { value: setTargetObject }, - [LOCATION_GETTER$7]: { value: addressGetter }, - [LOCATION_SETTER$7]: { value: addressSetter }, - [POINTER_VISITOR$7]: { value: visitPointer$7 }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [VIVIFICATOR$7]: { value: throwNullPointer$7 }, - [NORMALIZER$7]: { value: normalizePointer$7 }, - [FIXED_LOCATION$7]: { value: undefined, writable: true }, - }; - const staticDescriptors = { - child: { get: () => targetStructure.constructor }, - const: { value: isConst }, - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, + const memberDescriptors = {}; + for (const member of members) { + memberDescriptors[member.name] = getDescriptor$a(member, env); + } + const isChildMutable = function(object) { + return (object === this.retval); }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); + defineProperties$a(constructor.prototype, { + ...memberDescriptors, + [COPIER$a]: { value: getMemoryCopier$a(byteSize) }, + [VIVIFICATOR$a]: hasObject && { value: getChildVivificator$k(structure) }, + [POINTER_VISITOR$a]: hasPointer && { value: getPointerVisitor$k(structure, { isChildMutable }) }, + }); + defineProperties$a(constructor, { + [ALIGN$a]: { value: align }, + [SIZE$a]: { value: byteSize }, + }); + return constructor; } -function normalizePointer$7(cb) { - let target; - try { - target = this['*']; - } catch (err) { - target = Symbol.for('inaccessible'); +function appendEnumeration$2(enumeration, name, item) { + if (name !== undefined) { + // enum can have static variables + if (item instanceof enumeration) { + // attach name to item so tagged union code can quickly find it + defineProperties$a(item, { [NAME$a]: { value: name } }); + // call toPrimitive directly since enum can be bigint or number + const index = item[Symbol.toPrimitive](); + defineProperties$a(enumeration, { + [index]: { value: item }, + [name]: { value: item }, + }); + } + } else { + // non-exhaustive enum + defineProperties$a(enumeration, { [MORE$a]: { value: true } }); } - return cb(target); } -function getProxy$7() { - return this[PROXY$7]; +function getPrimitiveClass$a({ type, bitSize }) { + if (type === MemberType$a.Int || type === MemberType$a.Uint) { + if (bitSize <= 32) { + return Number; + } else { + return BigInt; + } + } else if (type === MemberType$a.Float) { + return Number; + } else if (type === MemberType$a.Bool) { + return Boolean; + } } -function copyPointer$7({ source }) { - const target = source[SLOTS$7][0]; - if (target) { - this[TARGET_SETTER$7](target); - } +const StructureType$a = { + Primitive: 0, + Array: 1, + Struct: 2, + ExternStruct: 3, + PackedStruct: 4, + ArgStruct: 5, + ExternUnion: 6, + BareUnion: 7, + TaggedUnion: 8, + ErrorUnion: 9, + ErrorSet: 10, + Enumeration: 11, + Optional: 12, + Pointer: 13, + Slice: 14, + Vector: 15, + Opaque: 16, + Function: 17, +}; + +const factories$w = {}; + +function useArgStruct$a() { + factories$w[StructureType$a.ArgStruct] = defineArgStruct$a; } -function resetPointer$7({ isActive }) { - if (this[SLOTS$7][0] && !isActive(this)) { - this[SLOTS$7][0] = undefined; - } +function getStructureFactory(type) { + const f = factories$w[type]; + return f; } -function disablePointer$7() { - const disabledProp = { get: throwInaccessiblePointer$7, set: throwInaccessiblePointer$7 }; - const disabledFunc = { value: throwInaccessiblePointer$7 }; - defineProperties$7(this[POINTER$7], { - '*': disabledProp, - '$': disabledProp, - [GETTER$7]: disabledFunc, - [SETTER$7]: disabledFunc, - [TARGET_GETTER$7]: disabledFunc, - }); +function flagMemberUsage(member, features) { + const { type } = member; + switch (type) { + case MemberType$a.Bool: + features.useBool = true; + if (!isByteAligned$a(member)) { + features.useExtendedBool = true; + } + break; + case MemberType$a.Int: + features.useInt = true; + if(!isByteAligned$a(member) || !hasStandardIntSize(member)) { + features.useExtendedInt = true; + } + break; + case MemberType$a.Uint: + features.useUint = true; + if(!isByteAligned$a(member) || !hasStandardIntSize(member)) { + features.useExtendedUint = true; + } + break; + case MemberType$a.Float: + features.useFloat = true; + if (!isByteAligned$a(member) || !hasStandardFloatSize(member)) { + features.useExtendedFloat = true; + } + break; + case MemberType$a.Object: + features.useObject = true; + break; + case MemberType$a.Void: + features.useVoid = true; + break; + case MemberType$a.Null: + features.useNull = true; + break; + case MemberType$a.Undefined: + features.useUndefined = true; + break; + case MemberType$a.Type: + features.useType = true; + break; + case MemberType$a.Comptime: + features.useComptime = true; + break; + case MemberType$a.Static: + features.useStatic = true; + break; + case MemberType$a.Literal: + features.useLiteral = true; + break; + } } -function visitPointer$7(fn, options = {}) { - const { - source, - isActive = always$7, - isMutable = always$7, - } = options; - fn.call(this, { source, isActive, isMutable }); +function flagStructureUsage(structure, features) { + const { type } = structure; + const [ name ] = Object.entries(StructureType$a).find(a => a[1] === type); + features[`use${name}`] = true; + for (const members of [ structure.instance.members, structure.static.members ]) { + for (const member of members) { + flagMemberUsage(member, features); + } + } } -function isPointerOf$7(arg, Target) { - return (arg?.constructor?.child === Target && arg['*']); +function getFeaturesUsed(structures) { + const features = {}; + for (const structure of structures) { + flagStructureUsage(structure, features); + } + return Object.keys(features); } -const proxyHandlers$f = { - get(pointer, name) { - if (name === POINTER$7) { - return pointer; - } else if (name in pointer) { - return pointer[name]; - } else { - const target = pointer[TARGET_GETTER$7](); - return target[name]; - } - }, - set(pointer, name, value) { - if (name in pointer) { - pointer[name] = value; - } else { - const target = pointer[TARGET_GETTER$7](); - target[name] = value; - } - return true; - }, - deleteProperty(pointer, name) { - if (name in pointer) { - delete pointer[name]; - } else { - const target = pointer[TARGET_GETTER$7](); - delete target[name]; +function defineProperties$a(object, descriptors) { + for (const [ name, descriptor ] of Object.entries(descriptors)) { + if (descriptor) { + const { + set, + get, + value, + enumerable, + configurable = true, + writable = true, + } = descriptor; + Object.defineProperty(object, name, (get) + ? { get, set, configurable, enumerable } + : { value, configurable, enumerable, writable } + ); } - return true; - }, - has(pointer, name) { - if (name in pointer) { - return true; - } else { - const target = pointer[TARGET_GETTER$7](); - return name in target; + } + for (const symbol of Object.getOwnPropertySymbols(descriptors)) { + const descriptor = descriptors[symbol]; + if (descriptor) { + Object.defineProperty(object, symbol, descriptor); } - }, -}; - -function always$7() { - return true; -} - -function never$7() { - return false; + } } -function defineStructShape$7(structure, env) { - const { - byteSize, - align, - instance: { members }, - hasPointer, - } = structure; - const memberDescriptors = {}; - for (const member of members) { - const { get, set } = getDescriptor$7(member, env); - memberDescriptors[member.name] = { get, set, configurable: true, enumerable: true }; - if (member.isRequired && set) { - set.required = true; +function findAllObjects(structures, SLOTS) { + const list = []; + const found = new Map(); + const find = (object) => { + if (!object || found.get(object)) { + return; } - } - const hasObject = !!members.find(m => m.type === MemberType$7.Object); - const propApplier = createPropertyApplier$7(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$7](arg); - if (hasPointer) { - this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); + found.set(object, true); + list.push(object); + if (object[SLOTS]) { + for (const child of Object.values(object[SLOTS])) { + find(child); } - } else if (arg && typeof(arg) === 'object') { - propApplier.call(this, arg); - } else if (arg !== undefined) { - throwInvalidInitializer$7(structure, 'object', arg); } }; - const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); - const instanceDescriptors = { - $: { get: getSelf$7, set: initializer }, - dataView: getDataViewDescriptor$7(structure), - base64: getBase64Descriptor$7(structure), - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - ...memberDescriptors, - [Symbol.iterator]: { value: getStructIterator$7 }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, - [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$f(structure, always$7) }, - [NORMALIZER$7]: { value: normalizeStruct$7 }, - [PROPS$7]: { value: members.map(m => m.name) }, - }; - const staticDescriptors = { - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, + for (const structure of structures) { + find(structure.instance.template); + find(structure.static.template); + } + return list; +} + +let currentGlobalSet$2; + +function appendErrorSet(errorSet, name, es) { + // our Zig export code places error set instance into the static template, which we can't + // use since all errors need to have the same parent class; here we get the error number + // and create the actual error object if hasn't been created already for an earlier set + const number = es[GETTER$a]('number'); + let error = currentGlobalSet$2[number]; + if (!error) { + const errorClass = errorSet[CLASS$2]; + error = new errorClass(name, number); + } + const string = String(error); + const descriptors = { + [number]: { value: error }, + [string]: { value: error }, + [name]: { value: error }, }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); + defineProperties$a(errorSet, descriptors); + defineProperties$a(currentGlobalSet$2, descriptors); + // add name to prop list + currentGlobalSet$2[PROPS$a].push(name); } -function normalizeStruct$7(cb, options) { - const object = {}; - for (const [ name, value ] of getStructEntries$7.call(this, options)) { - object[name] = cb(value); +function resetGlobalErrorSet() { + currentGlobalSet$2 = undefined; +} + +function throwArgumentCountMismatch$a(structure, actual) { + const { name, instance: { members } } = structure; + const argCount = members.length - 1; + const s = (argCount !== 1) ? 's' : ''; + throw new Error(`${name} expects ${argCount} argument${s}, received ${actual}`); +} + +function rethrowArgumentError$a(structure, index, err) { + const { name, instance: { members } } = structure; + // Zig currently does not provide the argument name + const argName = `args[${index}]`; + const argCount = members.length - 1; + const prefix = (index !== 0) ? '..., ' : ''; + const suffix = (index !== argCount - 1) ? ', ...' : ''; + const argLabel = prefix + argName + suffix; + const newError = new err.constructor(`${name}(${argLabel}): ${err.message}`); + newError.stack = err.stack; + throw newError; +} + +function throwOutOfBound$a(member, index) { + const { name } = member; + throw new RangeError(`Index exceeds the size of ${name ?? 'array'}: ${index}`); +} + +function rethrowRangeError$a(member, index, err) { + if (err instanceof RangeError) { + throwOutOfBound$a(member, index); + } else { + throw err; } - return object; } -function getStructEntries$7(options) { - return { - [Symbol.iterator]: getStructEntriesIterator$7.bind(this, options), - length: this[PROPS$7].length, - }; +function throwNotOnByteBoundary$a(member) { + const { name, structure: { name: { struct }} } = member; + throw new TypeError(`Unable to create ${struct} as it is not situated on a byte boundary: ${name}`); } -function getStructIterator$7(options) { - const entries = getStructEntries$7.call(this, options); - return entries[Symbol.iterator](); +function throwZigError(name) { + throw new Error(deanimalizeErrorName$2(name)); } -function getStructEntriesIterator$7(options) { - const self = this; - const props = this[PROPS$7]; - let index = 0; - return { - next() { - let value, done; - if (index < props.length) { - const current = props[index++]; - value = [ current, handleError$7(() => self[current], options) ]; - done = false; +function deanimalizeErrorName$2(name) { + // deal with snake_case first + let s = name.replace(/_/g, ' '); + // then camelCase, using a try block in case Unicode regex fails + try { + s = s.replace(/(\p{Uppercase}+)(\p{Lowercase}*)/gu, (m0, m1, m2) => { + if (m1.length === 1) { + return ` ${m1.toLocaleLowerCase()}${m2}`; } else { - done = true; + if (m2) { + const acronym = m1.substring(0, m1.length - 1); + const letter = m1.charAt(m1.length - 1).toLocaleLowerCase(); + return ` ${acronym} ${letter}${m2}`; + } else { + return ` ${m1}`; + } } - return { value, done }; - }, - }; -} - -function getChildVivificator$f(structure) { - const { instance: { members } } = structure; - const objectMembers = {}; - for (const member of members.filter(m => m.type === MemberType$7.Object)) { - objectMembers[member.slot] = member; + }).trimStart(); + /* c8 ignore next 2 */ + } catch (err) { } - return function vivificateChild(slot, writable = true) { - const member = objectMembers[slot]; - const { bitOffset, byteSize, structure: { constructor } } = member; - const dv = this[MEMORY$7]; - const parentOffset = dv.byteOffset; - const offset = parentOffset + (bitOffset >> 3); - let len = byteSize; - if (len === undefined) { - if (bitOffset & 7) { - throwNotOnByteBoundary$7(member); + return s.charAt(0).toLocaleUpperCase() + s.substring(1); +} + +function getBoolAccessor$a(access, member) { + return cacheMethod$a(access, member, () => { + if (isByteAligned$a(member)) { + const { byteSize } = member; + const typeName = getTypeName$a({ type: MemberType$a.Int, bitSize: byteSize * 8 }); + if (access === 'get') { + const get = DataView.prototype[`get${typeName}`]; + return function(offset, littleEndian) { + return !!get.call(this, offset, littleEndian); + }; + } else { + const set = DataView.prototype[`set${typeName}`]; + const T = (byteSize > 4) ? 1n : 1; + const F = (byteSize > 4) ? 0n : 0; + return function(offset, value, littleEndian) { + set.call(this, offset, value ? T : F, littleEndian); + }; } - len = member.bitSize >> 3; + } else { + return getExtendedTypeAccessor$a(access, member); } - const childDV = new DataView(dv.buffer, offset, len); - const object = this[SLOTS$7][slot] = constructor.call(PARENT$7, childDV, { writable }); - return object; + }); +} + +const factories$v = {}; + +function getExtendedTypeAccessor$a(access, member) { + const f = factories$v[member.type]; + return f(access, member); +} + +function getTypeName$a(member) { + const { type, bitSize, byteSize } = member; + if (type === MemberType$a.Int) { + return `${bitSize <= 32 ? '' : 'Big' }Int${bitSize}`; + } else if (type === MemberType$a.Uint) { + return `${bitSize <= 32 ? '' : 'Big' }Uint${bitSize}`; + } else if (type === MemberType$a.Float) { + return `Float${bitSize}`; + } else if (type === MemberType$a.Bool) { + const boolSize = (byteSize !== undefined) ? byteSize * 8 : 1; + return `Bool${boolSize}`; + } else if (type === MemberType$a.Void) { + return `Null`; } } -function getPointerVisitor$f(structure, visitorOptions = {}) { - const { - isChildActive = always$7, - isChildMutable = always$7, - } = visitorOptions; - const { instance: { members } } = structure; - const pointerMembers = members.filter(m => m.structure.hasPointer); - return function visitPointers(cb, options = {}) { - const { - source, - vivificate = false, - isActive = always$7, - isMutable = always$7, - } = options; - const childOptions = { - ...options, - isActive: (object) => { - // make sure parent object is active, then check whether the child is active - return isActive(this) && isChildActive.call(this, object); - }, - isMutable: (object) => { - return isMutable(this) && isChildMutable.call(this, object); - }, - }; - for (const { slot } of pointerMembers) { - if (source) { - // when src is a the struct's template, most slots will likely be empty, - // since pointer fields aren't likely to have default values - const srcChild = source[SLOTS$7]?.[slot]; - if (!srcChild) { - continue; - } - childOptions.source = srcChild; - } - const child = this[SLOTS$7][slot] ?? (vivificate ? this[VIVIFICATOR$7](slot) : null); - if (child) { - child[POINTER_VISITOR$7](cb, childOptions); - } - } - }; -} +const methodCache$a = {}; -function defineArgStruct$7(structure, env) { - const { - byteSize, - align, - instance: { members }, - hasPointer, - } = structure; - const hasObject = !!members.find(m => m.type === MemberType$7.Object); - const constructor = structure.constructor = function(args) { - const dv = env.allocateMemory(byteSize, align); - this[MEMORY$7] = dv; - if (hasObject) { - this[SLOTS$7] = {}; +function cacheMethod$a(access, member, cb) { + const { type, bitOffset, bitSize, structure } = member; + const bitPos = bitOffset & 0x07; + const typeName = getTypeName$a(member); + const suffix = isByteAligned$a(member) ? `` : `Bit${bitPos}`; + const isInt = type === MemberType$a.Int || type === MemberType$a.Uint; + let name = `${access}${typeName}${suffix}`; + let isSize = false, originalName = name; + if (isInt && bitSize === 64) { + const zigTypeName = structure?.name; + if (zigTypeName === 'usize' || zigTypeName === 'isize') { + name += 'Size'; + isSize = true; } - initializer.call(this, args); - }; - const argNames = members.slice(0, -1).map(m => m.name); - const argCount = argNames.length; - const initializer = function(args) { - if (args.length !== argCount) { - throwArgumentCountMismatch$7(structure, args.length); + } + let fn = methodCache$a[name]; + if (!fn) { + if (isInt && access === 'set') { + // add auto-conversion between number and bigint + const Primitive = getPrimitiveClass$a(member); + const set = cb(originalName); + fn = function(offset, value, littleEndian) { + set.call(this, offset, Primitive(value), littleEndian); + }; + } else if (isSize && access === 'get') { + // use number instead of bigint where possible + const get = cb(originalName); + const min = BigInt(Number.MIN_SAFE_INTEGER); + const max = BigInt(Number.MAX_SAFE_INTEGER); + fn = function(offset, littleEndian) { + const value = get.call(this, offset, littleEndian); + if (min <= value && value <= max) { + return Number(value); + } else { + return value; + } + }; + } else { + fn = cb(name); } - for (const [ index, name ] of argNames.entries()) { - try { - this[name] = args[index]; - } catch (err) { - rethrowArgumentError$7(structure, index, err); - } + if (fn && fn.name !== name) { + Object.defineProperty(fn, 'name', { value: name, configurable: true, writable: false }); } - }; - const memberDescriptors = {}; - for (const member of members) { - memberDescriptors[member.name] = getDescriptor$7(member, env); + methodCache$a[name] = fn; } - const isChildMutable = function(object) { - return (object === this.retval); - }; - defineProperties$7(constructor.prototype, { - ...memberDescriptors, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, - [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$f(structure, { isChildMutable }) }, - }); - defineProperties$7(constructor, { - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, - }); - return constructor; + return fn; } -function defineArray$7(structure, env) { - const { - length, - byteSize, - align, - instance: { members: [ member ] }, - hasPointer, - } = structure; - const { get, set } = getDescriptor$7(member, env); - const hasStringProp = canBeString$7(member); - const propApplier = createPropertyApplier$7(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$7](arg); - if (hasPointer) { - this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); - } - } else { - if (typeof(arg) === 'string' && hasStringProp) { - arg = { string: arg }; - } - if (arg?.[Symbol.iterator]) { - arg = transformIterable$7(arg); - if (arg.length !== length) { - throwArrayLengthMismatch$7(structure, this, arg); - } - let i = 0; - for (const value of arg) { - set.call(this, i++, value); - } - } else if (arg && typeof(arg) === 'object') { - if (propApplier.call(this, arg) === 0) { - throwInvalidArrayInitializer$7(structure, arg); - } - } else if (arg !== undefined) { - throwInvalidArrayInitializer$7(structure, arg); - } - } - }; - const finalizer = createArrayProxy$7; - const constructor = structure.constructor = createConstructor$7(structure, { initializer, finalizer }, env); - const typedArray = structure.typedArray = getTypedArrayClass$7(member); - const hasObject = member.type === MemberType$7.Object; - const instanceDescriptors = { - $: { get: getProxy$7, set: initializer }, - length: { value: length }, - dataView: getDataViewDescriptor$7(structure), - base64: getBase64Descriptor$7(structure), - string: hasStringProp && getStringDescriptor$7(structure), - typedArray: typedArray && getTypedArrayDescriptor$7(structure), - get: { value: get }, - set: { value: set }, - entries: { value: getArrayEntries$7 }, - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - [Symbol.iterator]: { value: getArrayIterator$7 }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$e(structure) }, - [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$e() }, - [NORMALIZER$7]: { value: normalizeArray$7 }, - }; - const staticDescriptors = { - child: { get: () => member.structure.constructor }, - [COMPAT$7]: { value: getCompatibleTags$7(structure) }, - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, - }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); +const MemberType$a = { + Void: 0, + Bool: 1, + Int: 2, + Uint: 3, + Float: 4, + Object: 5, + Type: 6, + Comptime: 7, + Static: 8, + Literal: 9, + Null: 10, + Undefined: 11, +}; + +function isReadOnly$a(type) { + switch (type) { + case MemberType$a.Type: + case MemberType$a.Comptime: + case MemberType$a.Literal: + return true; + default: + return false; + } } -function createArrayProxy$7() { - const proxy = new Proxy(this, proxyHandlers$e); - // hide the proxy so console wouldn't display a recursive structure - Object.defineProperty(this, PROXY$7, { value: proxy }); - return proxy; +const factories$u = {}; + +function useBool$a() { + factories$u[MemberType$a.Bool] = getBoolDescriptor$a; } -function canBeString$7(member) { - return member.type === MemberType$7.Uint && [ 8, 16 ].includes(member.bitSize); +function useObject$a() { + factories$u[MemberType$a.Object] = getObjectDescriptor$a; } -function normalizeArray$7(cb, options) { - const array = []; - for (const [ index, value ] of getArrayEntries$7.call(this, options)) { - array.push(cb(value)); - } - return array; +function isByteAligned$a({ bitOffset, bitSize, byteSize }) { + return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; } -function getArrayIterator$7() { - const self = this[ARRAY$7] ?? this; - const length = this.length; - let index = 0; - return { - next() { - let value, done; - if (index < length) { - const current = index++; - value = self.get(current); - done = false; - } else { - done = true; - } - return { value, done }; - }, - }; +function hasStandardIntSize({ bitSize }) { + return bitSize === 8 || bitSize === 16 || bitSize === 32 || bitSize === 64; } -function getArrayEntriesIterator$7(options) { - const self = this[ARRAY$7] ?? this; - const length = this.length; - let index = 0; - return { - next() { - let value, done; - if (index < length) { - const current = index++; - value = [ current, handleError$7(() => self.get(current), options) ]; - done = false; - } else { - done = true; - } - return { value, done }; - }, - }; +function hasStandardFloatSize({ bitSize }) { + return bitSize === 32 || bitSize === 64; } -function getArrayEntries$7(options) { - return { - [Symbol.iterator]: getArrayEntriesIterator$7.bind(this, options), - length: this.length, - }; +function getDescriptor$a(member, env) { + const f = factories$u[member.type]; + return f(member, env); } -function getChildVivificator$e(structure) { - const { instance: { members: [ member ]} } = structure; - const { byteSize, structure: elementStructure } = member; - return function getChild(index, writable = true) { - const { constructor } = elementStructure; - const dv = this[MEMORY$7]; - const parentOffset = dv.byteOffset; - const offset = parentOffset + byteSize * index; - const childDV = new DataView(dv.buffer, offset, byteSize); - const object = this[SLOTS$7][index] = constructor.call(PARENT$7, childDV, { writable }); - return object; - }; +function getBoolDescriptor$a(member, env) { + return getDescriptorUsing$a(member, env, getBoolAccessor$a) } -function getPointerVisitor$e(structure) { - return function visitPointers(cb, options = {}) { - const { - source, - vivificate = false, - isActive = always$7, - isMutable = always$7, - } = options; - const childOptions = { - ...options, - isActive: () => isActive(this), - isMutable: () => isMutable(this), - }; - for (let i = 0, len = this.length; i < len; i++) { - // no need to check for empty slots, since that isn't possible - if (source) { - childOptions.source = source?.[SLOTS$7][i]; - } - const child = this[SLOTS$7][i] ?? (vivificate ? this[VIVIFICATOR$7](i) : null); - if (child) { - child[POINTER_VISITOR$7](cb, childOptions); - } - } - }; +function isValueExpected$a(structure) { + switch (structure.type) { + case StructureType$a.Primitive: + case StructureType$a.ErrorUnion: + case StructureType$a.Optional: + case StructureType$a.Enumeration: + case StructureType$a.ErrorSet: + return true; + default: + return false; + } } -function transformIterable$7(arg) { - if (typeof(arg.length) === 'number') { - // it's an array of sort - return arg; - } - const iterator = arg[Symbol.iterator](); - const first = iterator.next(); - const length = first.value?.length; - if (typeof(length) === 'number' && Object.keys(first.value).join() === 'length') { - // return generator with length attached - return Object.assign((function*() { - let result; - while (!(result = iterator.next()).done) { - yield result.value; - } - })(), { length }); +function getValue$a(slot) { + const object = this[SLOTS$a][slot] ?? this[VIVIFICATOR$a](slot); + return object[GETTER$a](); +} + +function getObject$a(slot) { + const object = this[SLOTS$a][slot] ?? this[VIVIFICATOR$a](slot); + return object; +} + +function setValue$a(slot, value) { + const object = this[SLOTS$a][slot] ?? this[VIVIFICATOR$a](slot); + object[SETTER$a](value); +} + +function bindSlot$a(slot, { get, set }) { + if (slot !== undefined) { + return { + get: function() { + return get.call(this, slot); + }, + set: (set) + ? function(arg) { + return set.call(this, slot, arg); + } + : undefined, + }; } else { - const array = []; - let result = first; - while (!result.done) { - array.push(result.value); - result = iterator.next(); - } - return array; + // array accessors + return { get, set }; } } -const proxyHandlers$e = { - get(array, name) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - return array.get(index); - } else { - switch (name) { - case 'get': - if (!array[ELEMENT_GETTER$7]) { - array[ELEMENT_GETTER$7] = array.get.bind(array); +function getObjectDescriptor$a(member, env) { + const { structure, slot } = member; + return bindSlot$a(slot, { + get: isValueExpected$a(structure) ? getValue$a : getObject$a, + set: setValue$a, + }); +} + +function getDescriptorUsing$a(member, env, getDataViewAccessor) { + const { + littleEndian = true, + } = env; + const { bitOffset, byteSize } = member; + const getter = getDataViewAccessor('get', member); + const setter = getDataViewAccessor('set', member); + if (bitOffset !== undefined) { + const offset = bitOffset >> 3; + return { + get: function getValue() { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return getter.call(this[MEMORY$a], offset, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$a.call(this)) { + return getter.call(this[MEMORY$a], offset, littleEndian); + } else { + throw err; } - return array[ELEMENT_GETTER$7]; - case 'set': - if (!array[ELEMENT_SETTER$7]) { - array[ELEMENT_SETTER$7] = array.set.bind(array); + } + /* WASM-ONLY-END*/ + }, + set: function setValue(value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return setter.call(this[MEMORY$a], offset, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$a.call(this)) { + return setter.call(this[MEMORY$a], offset, value, littleEndian); + } else { + throw err; } - return array[ELEMENT_SETTER$7]; - case ARRAY$7: - return array; - default: - return array[name]; - } - } - }, - set(array, name, value) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - array.set(index, value); - } else { - switch (name) { - case 'get': - array[ELEMENT_GETTER$7] = value; - break; - case 'set': - array[ELEMENT_SETTER$7] = value; - break; - default: - array[name] = value; - } - } - return true; - }, - deleteProperty(array, name) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - return false; - } else { - switch (name) { - case 'get': - delete array[ELEMENT_GETTER$7]; - break; - case 'set': - delete array[ELEMENT_SETTER$7]; - break; - default: - delete array[name]; + } + /* WASM-ONLY-END*/ } - return true; - } - }, - has(array, name) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - return (index >= 0 && index < array.length); - } else { - return array[name]; - } - }, - ownKeys(array) { - const keys = []; - for (let i = 0, len = array.length; i < len; i++) { - keys.push(`${i}`); } - keys.push('length', PROXY$7); - return keys; - }, - getOwnPropertyDescriptor(array, name) { - const index = (typeof(name) === 'symbol') ? 0 : name|0; - if (index !== 0 || index == name) { - if (index >= 0 && index < array.length) { - return { value: array.get(index), enumerable: true, writable: true, configurable: true }; - } - } else { - return Object.getOwnPropertyDescriptor(array, name); + } else { + return { + get: function getElement(index) { + try { + return getter.call(this[MEMORY$a], index * byteSize, littleEndian); + } catch (err) { + /* WASM-ONLY */ + if (err instanceof TypeError && restoreMemory$a.call(this)) { + return getter.call(this[MEMORY$a], index * byteSize, littleEndian); + } else { + /* WASM-ONLY-END */ + rethrowRangeError$a(member, index, err); + /* WASM-ONLY */ + } + /* WASM-ONLY-END */ + } + }, + set: function setElement(index, value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END */ + return setter.call(this[MEMORY$a], index * byteSize, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$a.call(this)) { + return setter.call(this[MEMORY$a], index * byteSize, value, littleEndian); + } else { + rethrowRangeError$a(member, index, err); + } + } + /* WASM-ONLY-END */ + }, } - }, -}; + } +} -function defineEnumerationShape$7(structure, env) { +function generateCode(definition, params) { + const { structures } = definition; const { - byteSize, - align, - instance: { - members: [ member ], - }, - } = structure; - const { get: getIndex, set: setIndex } = getDescriptor$7(member, env); - // get the enum descriptor instead of the int/uint descriptor - const { get, set } = getDescriptor$7({ ...member, type: MemberType$7.EnumerationItem, structure }, env); - const expected = [ 'string', 'number', 'tagged union' ]; - const propApplier = createPropertyApplier$7(structure); - const initializer = function(arg) { - if (arg && typeof(arg) === 'object') { - if (propApplier.call(this, arg) === 0) { - throwInvalidInitializer$7(structure, expected, arg); - } - } else if (arg !== undefined) { - set.call(this, arg); - } - }; - const alternateCaster = function(arg) { - if (typeof(arg) === 'string' || typeof(arg) === 'number' || typeof(arg) === 'bigint') { - const items = constructor[ITEMS$7]; - let item = items[arg]; - if (!item) { - if (constructor[MORE$7] && typeof(arg) !== 'string') { - // create the item on-the-fly when enum is non-exhaustive - item = items[arg] = new constructor(undefined); - setIndex.call(item, arg); - defineProperties$7(item, { [NAME$7]: { value: `${arg}` } }); + runtimeURL, + binarySource = null, + topLevelAwait = true, + omitExports = false, + declareFeatures = false, + addonDir = null, + } = params; + const features = (declareFeatures) ? getFeaturesUsed(structures) : []; + const exports = getExports(structures); + const lines = []; + const add = manageIndentation(lines); + add(`import {`); + for (const name of [ 'createEnvironment', ...features ]) { + add(`${name},`); + } + add(`} from ${JSON.stringify(runtimeURL)};`); + // reduce file size by only including code of features actually used + // dead-code remover will take out code not referenced here + add(`\n// activate features`); + for (const feature of features) { + add(`${feature}();`); + } + // write out the structures as object literals + addStructureDefinitions(lines, definition); + add(`\n// create runtime environment`); + add(`const env = createEnvironment(${addonDir ? JSON.stringify({ addonDir }, undefined, 2) : null});`); + add(`const __zigar = env.getControlObject();`); + add(`\n// recreate structures`); + add(`env.recreateStructures(structures, options);`); + if (binarySource) { + add(`\n// initiate loading and compilation of WASM bytecodes`); + add(`const source = ${binarySource};`); + add(`env.loadModule(source)`); + // if top level await is used, we don't need to write changes into fixed memory buffers + add(`env.linkVariables(${!topLevelAwait});`); + } + add(`\n// export root namespace and its methods and constants`); + add(`const { constructor } = root;`); + if (!omitExports) { + add(`export { constructor as default, __zigar }`); + // the first two exports are default and __zigar + const exportables = exports.slice(2); + if (exportables.length > 0) { + add(`export const {`); + for (const name of exportables) { + add(`${name},`); + } + add(`} = constructor;`); + } + } + if (topLevelAwait && binarySource) { + add(`await __zigar.init();`); + } + const code = lines.join('\n'); + return { code, exports, structures }; +} + +function addStructureDefinitions(lines, definition) { + const { structures, options, keys } = definition; + const { MEMORY, SLOTS, CONST } = keys; + const add = manageIndentation(lines); + const defaultStructure = { + constructor: null, + typedArray: null, + type: StructureType$a.Primitive, + name: undefined, + byteSize: 0, + align: 0, + isConst: false, + hasPointer: false, + instance: { + members: [], + methods: [], + template: null, + }, + static: { + members: [], + methods: [], + template: null, + }, + }; + add(`\n// structure defaults`); + add(`const s = {`); + for (const [ name, value ] of Object.entries(defaultStructure)) { + switch (name) { + case 'instance': + case 'static': + add(`${name}: {`); + for (const [ name2, value2 ] of Object.entries(value)) { + add(`${name2}: ${JSON.stringify(value2)},`); + } + add(`},`); + break; + default: + add(`${name}: ${JSON.stringify(value)},`); + } + } + add(`};`); + const defaultMember = { + type: MemberType$a.Void, + isRequired: false, + }; + add(`\n// member defaults`); + add(`const m = {`); + for (const [ name, value ] of Object.entries(defaultMember)) { + add(`${name}: ${JSON.stringify(value)},`); + } + add(`};`); + // create empty objects first, to allow objects to reference each other + add(``); + const structureNames = new Map(); + const structureMap = new Map(); + for (const [ index, structure ] of structures.entries()) { + const varname = `s${index}`; + structureNames.set(structure, varname); + structureMap.set(structure.constructor, structure); + } + for (const slice of chunk(structureNames.values(), 10)) { + add(`const ${slice.map(n => `${n} = {}`).join(', ')};`); + } + const objects = findAllObjects(structures, SLOTS); + const objectNames = new Map(); + const views = []; + for (const [ index, object ] of objects.entries()) { + const varname = `o${index}`; + objectNames.set(object, varname); + if (object[MEMORY]) { + views.push(object[MEMORY]); + } + } + for (const slice of chunk(objectNames.values(), 10)) { + add(`const ${slice.map(n => `${n} = {}`).join(', ')};`); + } + // define buffers + const arrayBufferNames = new Map(); + for (const [ index, dv ] of views.entries()) { + if (!arrayBufferNames.get(dv.buffer)) { + const varname = `a${index}`; + arrayBufferNames.set(dv.buffer, varname); + if (dv.buffer.byteLength > 0) { + const ta = new Uint8Array(dv.buffer); + add(`const ${varname} = new Uint8Array([ ${ta.join(', ')} ]);`); + } else { + add(`const ${varname} = new Uint8Array();`); + } + } + } + // add properties to objects + if (objects.length > 0) { + add('\n// define objects'); + for (const object of objects) { + const varname = objectNames.get(object); + const structure = structureMap.get(object.constructor); + const { [MEMORY]: dv, [SLOTS]: slots } = object; + add(`Object.assign(${varname}, {`); + if (structure) { + add(`structure: ${structureNames.get(structure)},`); + } + if (dv) { + const buffer = arrayBufferNames.get(dv.buffer); + const pairs = [ `array: ${buffer}` ]; + if (dv.byteLength < dv.buffer.byteLength) { + pairs.push(`offset: ${dv.byteOffset}`); + pairs.push(`length: ${dv.byteLength}`); + } + add(`memory: { ${pairs.join(', ')} },`); + if (dv.hasOwnProperty('reloc')) { + add(`reloc: ${dv.reloc},`); + if (object[CONST]) { + add(`const: true,`); + } + } + } + const entries = (slots) ? Object.entries(slots).filter(a => a[1]) : []; + if (entries.length > 0) { + add(`slots: {`); + const pairs = entries.map(([slot, child]) => `${slot}: ${objectNames.get(child)}`); + for (const slice of chunk(pairs, 10)) { + add(slice.join(', ') + ','); + } + add(`},`); + } + add(`});`); + } + } + const methods = []; + for (const structure of structures) { + // add static members; instance methods are also static methods, so + // we don't need to add them separately + methods.push(...structure.static.methods); + } + const methodNames = new Map(); + if (methods.length > 0) { + add(`\n// define functions`); + for (const [ index, method ] of methods.entries()) { + const varname = `f${index}`; + methodNames.set(method, varname); + add(`const ${varname} = {`); + for (const [ name, value ] of Object.entries(method)) { + switch (name) { + case 'argStruct': + add(`${name}: ${structureNames.get(value)},`); + break; + default: + add(`${name}: ${JSON.stringify(value)},`); + } + } + add(`};`); + } + } + add('\n// define structures'); + for (const structure of structures) { + const varname = structureNames.get(structure); + add(`Object.assign(${varname}, {`); + add(`...s,`); + for (const [ name, value ] of Object.entries(structure)) { + if (isDifferent(value, defaultStructure[name])) { + switch (name) { + case 'constructor': + case 'typedArray': + case 'sentinel': + break; + case 'instance': + case 'static': { + const { methods, members, template } = value; + add(`${name}: {`); + add(`members: [`); + for (const member of members) { + add(`{`); + add(`...m,`); + for (const [ name, value ] of Object.entries(member)) { + if (isDifferent(value, defaultMember[name])) { + switch (name) { + case 'structure': + add(`${name}: ${structureNames.get(value)},`); + break; + default: + add(`${name}: ${JSON.stringify(value)},`); + } + } + } + add(`},`); + } + add(`],`); + add(`methods: [`); + for (const slice of chunk(methods, 10)) { + add(slice.map(m => methodNames.get(m)).join(', ') + ','); + } + add(`],`); + if (template) { + add(`template: ${objectNames.get(template)}`); + } + add(`},`); + } break; + default: + add(`${name}: ${JSON.stringify(value)},`); + } + } + } + add(`});`); + } + add(`const structures = [`); + for (const slice of chunk([ ...structureNames.values() ], 10)) { + add(slice.join(', ') + ','); + } + add(`];`); + const root = structures[structures.length - 1]; + add(`const root = ${structureNames.get(root)};`); + add(`const options = {`); + for (const [ name, value ] of Object.entries(options)) { + add(`${name}: ${value},`); + } + add(`};`); + return lines; +} + +function getExports(structures) { + const root = structures[structures.length - 1]; + const { constructor } = root; + const exportables = []; + // export only members whose names are legal JS identifiers + const legal = /^[$\w]+$/; + for (const method of root.static.methods) { + if (legal.test(method.name)) { + exportables.push(method.name); + } + } + for (const member of root.static.members) { + // only read-only properties are exportable + if (isReadOnly$a(member.type) && legal.test(member.name)) { + try { + // make sure that getter wouldn't throw (possible with error union) + constructor[member.name]; + exportables.push(member.name); + } catch (err) { + } + } + } + return [ 'default', '__zigar', ...exportables ]; +} + +function manageIndentation(lines) { + let indent = 0; + return (s) => { + if (/^\s*[\]\}]/.test(s)) { + indent--; + } + const lastLine = lines[lines.length - 1]; + if ((lastLine?.endsWith('[') && s.startsWith(']')) + || (lastLine?.endsWith('{') && s.startsWith('}'))) { + lines[lines.length - 1] += s; + } else { + lines.push(' '.repeat(indent * 2) + s); + } + if (/[\[\{]\s*$/.test(s)) { + indent++; + } + }; +} + +function isDifferent(value, def) { + if (value === def) { + return false; + } + if (def == null) { + return value != null; + } + if (typeof(def) === 'object' && typeof(value) === 'object') { + const valueKeys = Object.keys(value); + const defKeys = Object.keys(def); + if (valueKeys.length !== defKeys.length) { + return true; + } + for (const key of defKeys) { + if (isDifferent(value[key], def[key])) { + return true; + } + } + return false; + } + return true; +} + +function* chunk(arr, n) { + if (!Array.isArray(arr)) { + arr = [ ...arr ]; + } + for (let i = 0; i < arr.length; i += n) { + yield arr.slice(i, i + n); + } +} + +async function findFile(path, follow = true) { + try { + return await (follow ? stat(path) : lstat(path)); + } catch (err) { + } +} + +function findFileSync(path, follow = true) { + try { + return follow ? statSync(path) : lstatSync(path); + } catch (err) { + } +} + +async function findMatchingFiles(dir, re) { + const map = new Map(); + const scanned = new Map(); + const scan = async (dir) => { + /* c8 ignore next 3 */ + if (scanned.get(dir)) { + return; + } + scanned.set(dir, true); + try { + const list = await readdir(dir); + for (const name of list) { + if (name.startsWith('.') || name === 'node_modules' || name === 'zig-cache') { + continue; + } + const path = join(dir, name); + const info = await findFile(path); + if (info?.isDirectory()) { + await scan(path); + } else if (info?.isFile() && re.test(name)) { + map.set(path, info); + } + } + /* c8 ignore next 2 */ + } catch (err) { + } + }; + await scan(dir); + return map; +} + +function findMatchingFilesSync(dir, re) { + const map = new Map(); + const scanned = new Map(); + const scan = (dir) => { + /* c8 ignore next 3 */ + if (scanned.get(dir)) { + return; + } + scanned.set(dir, true); + try { + const list = readdirSync(dir); + for (const name of list) { + if (name.startsWith('.') || name === 'node_modules' || name === 'zig-cache') { + continue; + } + const path = join(dir, name); + const info = findFileSync(path); + if (info?.isDirectory()) { + scan(path); + } else if (info?.isFile() && re.test(name)) { + map.set(path, info); + } + } + /* c8 ignore next 2 */ + } catch (err) { + } + }; + scan(dir); + return map; +} + +async function acquireLock(pidPath, staleTime) { + while (true) { + try { + await createDirectory(dirname(pidPath)); + const handle = await open(pidPath, 'wx'); + handle.write(`${process.pid}`); + handle.close(); + break; + } catch (err) { + if (err.code === 'EEXIST') { + if (checkPidFile(pidPath, staleTime)) { + await delay(250); + continue; + } + } else { + throw err; + } + } + } +} + +function acquireLockSync(pidPath, staleTime) { + while (true) { + try { + createDirectorySync(dirname(pidPath)); + const handle = openSync(pidPath, 'wx'); + writeSync(handle, `${process.pid}`); + closeSync(handle); + break; + } catch (err) { + if (err.code === 'EEXIST') { + if (checkPidFile(pidPath, staleTime)) { + delaySync(250); + } + } else { + throw err; + } + } + } +} + +async function releaseLock(pidPath) { + await deleteFile(pidPath); +} + +function releaseLockSync(pidPath) { + deleteFileSync(pidPath); +} + +function checkPidFile(pidPath, staleTime = 60000 * 5) { + let stale = false; + try { + const pid = loadFileSync(pidPath); + if (os.platform() === 'win32') { + execSync(`tasklist /nh /fi "pid eq ${pid}" | findstr .exe`, { stdio: 'pipe' }).toString(); + } else { + execSync(`ps -p ${pid}`).toString(); + } + const last = findFileSync(pidPath)?.mtime || 0; + const diff = new Date() - last; + if (diff > staleTime) { + stale = true; + } + } catch (err) { + stale = true; + } + if (stale) { + deleteFileSync(pidPath); + } + return !stale; +} + +async function copyFile(srcPath, dstPath) { + const info = await stat(srcPath); + const data = await readFile(srcPath); + await writeFile(dstPath, data); + await chmod(dstPath, info.mode); +} + +function copyFileSync(srcPath, dstPath) { + const info = statSync(srcPath); + const data = readFileSync(srcPath); + writeFileSync(dstPath, data); + chmodSync(dstPath, info.mode); +} + +async function loadFile(path, def) { + try { + return await readFile(path, 'utf8'); + } catch (err) { + return def; + } +} + +function loadFileSync(path, def) { + try { + return readFileSync(path, 'utf8'); + } catch (err) { + return def; + } +} + +async function deleteFile(path) { + try { + await unlink(path); + } catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + throw err; + } + } +} + +function deleteFileSync(path) { + try { + unlinkSync(path); + } catch (err) { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { + throw err; + } + } +} + +async function createDirectory(path) { + const exists = await findDirectory(path); + if (!exists) { + const { root, dir } = parse(path); + await createDirectory(dir); + try { + await mkdir(path); + } catch (err) { + /* c8 ignore next 3 */ + if (err.code != 'EEXIST') { + throw err; + } + } + } +} + +function createDirectorySync(path) { + const exists = findDirectorySync(path); + if (!exists) { + const { root, dir } = parse(path); + createDirectorySync(dir); + try { + mkdirSync(path); + } catch (err) { + /* c8 ignore next 3 */ + if (err.code != 'EEXIST') { + throw err; + } + } + } +} + +async function findDirectory(path) { + return findFile(path); +} + +function findDirectorySync(path) { + return findFileSync(path); +} + +async function deleteDirectory(dir) { + try { + const list = await readdir(dir); + for (const name of list) { + const path = join(dir, name); + const info = await findFile(path, false); + if (info?.isDirectory()) { + await deleteDirectory(path); + } else if (info) { + await deleteFile(path); + } + } + await rmdir(dir); + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + } +} + +function deleteDirectorySync(dir) { + try { + const list = readdirSync(dir); + for (const name of list) { + const path = join(dir, name); + const info = findFileSync(path, false); + if (info?.isDirectory()) { + deleteDirectorySync(path); + } else if (info) { + deleteFileSync(path); + } + } + rmdirSync(dir); + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + } +} + +async function delay(ms) { + await new Promise(r => setTimeout(r, ms)); +} + +function delaySync(ms) { + const buffer = new SharedArrayBuffer(8); + const ta = new BigInt64Array(buffer); + Atomics.wait(ta, 0, 0n, ms); +} + +function md5(text) { + const hash = createHash('md5'); + hash.update(text); + return hash.digest('hex'); +} + +let isGNU; + +function getPlatform() { + let platform = os.platform(); + if (platform === 'linux') { + // differentiate glibc from musl + if (isGNU === undefined) { + /* c8 ignore next 3 */ + if (process.versions?.electron || process.__nwjs) { + isGNU = true; + } else { + try { + execFileSync('getconf', [ 'GNU_LIBC_VERSION' ], { stdio: 'pipe' }); + isGNU = true; + /* c8 ignore next 3 */ + } catch (err) { + isGNU = false; + } + } + } + /* c8 ignore next 3 */ + if (!isGNU) { + platform += '-musl'; + } + } + return platform; +} + +function getArch() { + return os.arch(); +} + +function normalizePath(url) { + let archive; + const parts = fileURLToPath(url).split(sep).map((part) => { + if (part === 'app.asar') { + archive = 'asar'; + return part + '.unpacked'; + } + return part; + }); + const path = parts.join(sep); + return { path, archive } +} + +async function compile(srcPath, modPath, options) { + const srcInfo = (srcPath) ? await findFile(srcPath) : null; + if (srcInfo === undefined) { + throw new Error(`Source file not found: ${srcPath}`); + } + if (srcInfo?.isDirectory()) { + srcPath = join(srcPath, '?'); + } + const config = createConfig(srcPath, modPath, options); + const { moduleDir, outputPath } = config; + let changed = false; + if (srcPath) { + const srcFileMap = await findMatchingFiles(moduleDir, /.\..*$/); + // see if the (re-)compilation is necessary + const soInfo = await findFile(outputPath); + if (soInfo) { + for (const [ name, info ] of srcFileMap) { + if (info.mtime > soInfo.mtime) { + changed = true; + break; + } + } + } else { + changed = true; + } + if (!changed) { + // rebuild when exporter or build files have changed + const zigFolder = absolute('../zig'); + const zigFileMap = await findMatchingFiles(zigFolder, /\.zig$/); + for (const [ path, info ] of zigFileMap) { + if (info.mtime > soInfo.mtime) { + changed = true; + break; + } + } + } + if (changed) { + // add custom build file + for (const [ path, info ] of srcFileMap) { + switch (basename(path)) { + case 'build.zig': + config.buildFilePath = path; + break; + case 'build.zig.zon': + config.packageConfigPath = path; + break; + } + } + const { zigCmd, moduleBuildDir } = config; + // only one process can compile a given file at a time + const pidPath = `${moduleBuildDir}.pid`; + await acquireLock(pidPath); + try { + // create config file + await createProject(config, moduleBuildDir); + // then run the compiler + await runCompiler(zigCmd, moduleBuildDir); + } finally { + if (config.clean) { + await deleteDirectory(moduleBuildDir); + } + await releaseLock(pidPath); + } + } + } + return { outputPath, changed } +} + +function compileSync(srcPath, modPath, options) { + const srcInfo = (srcPath) ? findFileSync(srcPath) : null; + if (srcInfo === undefined) { + throw new Error(`Source file not found: ${srcPath}`); + } + if (srcInfo?.isDirectory()) { + srcPath = join(srcPath, '?'); + } + const config = createConfig(srcPath, modPath, options); + const { moduleDir, outputPath } = config; + let changed = false; + if (srcPath) { + const srcFileMap = findMatchingFilesSync(moduleDir, /.\..*$/); + // see if the (re-)compilation is necessary + const soInfo = findFileSync(outputPath); + if (soInfo) { + for (const [ path, info ] of srcFileMap) { + if (info.mtime > soInfo.mtime) { + changed = true; + break; + } + } + } else { + changed = true; + } + if (!changed) { + // rebuild when exporter or build files have changed + const zigFolder = absolute('../zig'); + const zigFileMap = findMatchingFilesSync(zigFolder, /\.zig$/); + for (const [ path, info ] of zigFileMap) { + if (info.mtime > soInfo.mtime) { + changed = true; + break; + } + } + } + if (changed) { + // add custom build file + for (const [ path, info ] of srcFileMap) { + switch (basename(path)) { + case 'build.zig': + config.buildFilePath = path; + break; + case 'build.zig.zon': + config.packageConfigPath = path; + break; + } + } + const { zigCmd, moduleBuildDir } = config; + // only one process can compile a given file at a time + const pidPath = `${moduleBuildDir}.pid`; + acquireLockSync(pidPath); + try { + // create config file + createProjectSync(config, moduleBuildDir); + // then run the compiler + runCompilerSync(zigCmd, moduleBuildDir); + } finally { + if (config.clean) { + deleteDirectorySync(moduleBuildDir); + } + releaseLockSync(pidPath); + } + } + } + return { outputPath, changed } +} + +async function runCompiler(zigCmd, soBuildDir) { + const options = { + cwd: soBuildDir, + windowsHide: true, + }; + return new Promise((resolve, reject) => { + exec(zigCmd, options, (err, stdout, stderr) => { + if (err) { + const log = stderr; + if (log) { + const logPath = join(soBuildDir, 'log'); + writeFile(logPath, log); + err = new Error(`Zig compilation failed\n\n${log}`); + } + reject(err); + } else { + resolve(); + } + }); + }); +} + +function runCompilerSync(zigCmd, soBuildDir) { + const options = { + cwd: soBuildDir, + windowsHide: true, + stdio: 'pipe', + }; + try { + execSync(zigCmd, options); + } catch (err) { + const log = err.stderr; + if (log) { + const logPath = join(soBuildDir, 'log'); + writeFileSync(logPath, log); + } + throw new Error(`Zig compilation failed\n\n${log}`); + } +} + +function formatProjectConfig(config) { + const lines = []; + const fields = [ + 'moduleName', 'modulePath', 'moduleDir', 'exporterPath', 'stubPath', 'outputPath', + 'useLibc', 'isWASM', + ]; + for (const [ name, value ] of Object.entries(config)) { + if (fields.includes(name)) { + const snakeCase = name.replace(/[A-Z]+/g, m => '_' + m.toLowerCase()); + lines.push(`pub const ${snakeCase} = ${JSON.stringify(value)};`); + } + } + return lines.join('\n'); +} + +async function createProject(config, dir) { + await createDirectory(dir); + const content = formatProjectConfig(config); + const cfgFilePath = join(dir, 'build-cfg.zig'); + await writeFile(cfgFilePath, content); + const buildFilePath = join(dir, 'build.zig'); + await copyFile(config.buildFilePath, buildFilePath); + if (config.packageConfigPath) { + const packageConfigPath = join(dir, 'build.zig.zon'); + await copyFile(config.packageConfigPath, packageConfigPath); + } +} + +function createProjectSync(config, dir) { + createDirectorySync(dir); + const content = formatProjectConfig(config); + const cfgFilePath = join(dir, 'build-cfg.zig'); + writeFileSync(cfgFilePath, content); + const buildFilePath = join(dir, 'build.zig'); + copyFileSync(config.buildFilePath, buildFilePath); + if (config.packageConfigPath) { + const packageConfigPath = join(dir, 'build.zig.zon'); + copyFileSync(config.packageConfigPath, packageConfigPath); + } +} + +const cwd = process.cwd(); + +function getCachePath(options) { + const { + cacheDir = join(cwd, 'zigar-cache'), + } = options; + return cacheDir; +} + +function getModuleCachePath(srcPath, options) { + const { + optimize, + } = options; + const src = parse(srcPath); + const folder = basename(src.dir).slice(0, 16).trim() + '-' + md5(src.dir).slice(0, 8); + const cacheDir = getCachePath(options); + return join(cacheDir, folder, optimize, `${src.name}.zigar`); +} + +function createConfig(srcPath, modPath, options = {}) { + const { + platform = getPlatform(), + arch = getArch(), + optimize = 'Debug', + isWASM = false, + useLibc = isWASM ? false : true, + clean = false, + buildDir = join(os.tmpdir(), 'zigar-build'), + zigCmd = (() => { + // translate from names used by Node to those used by Zig + const cpuArchs = { + arm: 'arm', + arm64: 'aarch64', + ia32: 'x86', + loong64: 'loong64', + mips: 'mips', + mipsel: 'mipsel', + ppc: 'powerpc', + ppc64: 'powerpc64', + s390: undefined, + s390x: 's390x', + x64: 'x86_64', + }; + const osTags = { + aix: 'aix', + darwin: 'macos', + freebsd: 'freebsd', + linux: 'linux-gnu', + openbsd: 'openbsd', + sunos: 'solaris', + win32: 'windows', + }; + const cpuArch = cpuArchs[arch] ?? arch; + const osTag = osTags[platform] ?? platform; + const args = [ + `build`, + `-Doptimize=${optimize}`, + `-Dtarget=${cpuArch}-${osTag}`, + ]; + return `zig ${args.join(' ')}`; + })(), + } = options; + const suffix = isWASM ? 'wasm' : 'c'; + const src = parse(srcPath ?? ''); + const mod = parse(modPath ?? ''); + const moduleName = mod.name || src.name; + const modulePath = (src.name !== '?') ? srcPath : undefined; + const moduleDir = src.dir; + const modulePrefix = basename(moduleName).slice(0, 16); + const moduleHash = md5(`${moduleDir}/${moduleName}`).slice(0, 8); + const moduleBuildDir = join(buildDir, modulePrefix + '-' + moduleHash); + const outputPath = (() => { + if (!modPath && isWASM) { + // save output in build folder + return join(moduleBuildDir, optimize, `${src.name}.wasm`); + } else { + const extensions = { + darwin: 'dylib', + win32: 'dll', + }; + const ext = extensions[platform] || 'so'; + return join(modPath, `${platform}.${arch}.${ext}`); + } + })(); + const exporterPath = absolute(`../zig/exporter-${suffix}.zig`); + const stubPath = absolute(`../zig/stub-${suffix}.zig`); + const buildFilePath = absolute(`../zig/build.zig`); + return { + platform, + arch, + optimize, + moduleName, + modulePath, + moduleDir, + moduleBuildDir, + exporterPath, + stubPath, + buildFilePath, + packageConfigPath: undefined, + outputPath, + clean, + zigCmd, + useLibc, + isWASM, + }; +} + +function absolute(relpath) { + // import.meta.url don't always yield the right URL when transpiled to CommonJS + // just use __dirname as it's going to be there + /* c8 ignore next 2 */ + if (typeof(__dirname) === 'string') { + return resolve(__dirname, relpath); + } else { + return fileURLToPath(new URL(relpath, import.meta.url)); + } +} + +const optionsForCompile = { + optimize: { + type: 'string', + enum: [ 'Debug', 'ReleaseSmall', 'ReleaseFast', 'ReleaseSafe' ], + title: 'Zig optimization mode', + }, + omitFunctions: { + type: 'boolean', + title: 'Omit all Zig functions', + }, + omitVariables: { + type: 'boolean', + title: 'Omit all variables', + }, + omitExports: { + type: 'boolean', + title: 'Omit export statements', + }, + useLibc: { + type: 'boolean', + title: 'Link in C standard library', + }, + topLevelAwait: { + type: 'boolean', + title: 'Use top-level await to load WASM file', + }, + buildDir: { + type: 'string', + title: 'Root directory where temporary build directories are placed', + }, + cacheDir: { + type: 'string', + title: 'Directory where compiled library files are placed', + }, + zigCmd: { + type: 'string', + title: 'Zig command used to build libraries', + }, + sourceFiles: { + type: 'object', + title: 'Map of modules to source files/directories', + }, + clean: { + type: 'boolean', + title: 'Remove temporary build directory after compilation finishes', + }, + targets: { + type: 'object', + title: 'List of cross-compilation targets', + }, +}; + +const optionsForTranspile = { + useReadFile: { + type: 'boolean', + title: 'Enable the use of readFile() to Load WASM file when library is used in Node.js', + }, + embedWASM: { + type: 'boolean', + title: 'Embed WASM file in JavaScript source code', + }, + stripWASM: { + type: 'boolean', + title: 'Remove unnecessary code from WASM file', + }, + keepNames: { + type: 'boolean', + title: 'Keep names of function in WASM binary when stripping', + }, +}; + +const allOptions = { + ...optionsForCompile, + ...optionsForTranspile, +}; + +function extractOptions(searchParams, availableOptions) { + const options = {}; + const names = Object.keys(availableOptions); + for (const [ name, string ] of searchParams) { + const key = getCamelCase(name, names); + const option = availableOptions[key]; + if (!option) { + throwUnknownOption(name); + } + if (key === 'optimize') { + options[key] = getCamelCase(string, [ 'Debug', 'ReleaseSafe', 'ReleaseFast', 'ReleaseSmall' ]); + } else { + switch (option.type) { + case 'boolean': + options[key] = !!parseInt(string); + break; + case 'number': + options[key] = parseInt(string); + break; + default: + options[key] = string; + } + } + } + return options; +} + +function getCamelCase(name, names) { + for (const nameCC of names) { + const nameSC = nameCC.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase(); + const nameKC = nameSC.replace(/_/g, '-'); + if (name === nameKC || name === nameSC || name === nameCC) { + return nameCC; + } + } + return name; +} + +function throwUnknownOption(key) { + const adjective = (allOptions[key]) ? 'Unavailable' : 'Unrecognized'; + throw new Error(`${adjective} option: ${key}`); +} + +async function findConfigFile(name, dir) { + const path = join(dir, name); + const info = await findFile(path); + if (info?.isFile()) { + return path; + } else { + const parent = dirname(dir); + if (parent !== dir) { + return findConfigFile(name, parent); + } + } +} + +function findConfigFileSync(name, dir) { + const path = join(dir, name); + const info = findFileSync(path); + if (info?.isFile()) { + return path; + } else { + const parent = dirname(dir); + if (parent !== dir) { + return findConfigFileSync(name, parent); + } + } +} + +async function loadConfigFile(cfgPath, availableOptions) { + const text = await loadFile(cfgPath); + return processConfigFile(text, cfgPath, availableOptions); +} + +function loadConfigFileSync(cfgPath, availableOptions) { + const text = loadFileSync(cfgPath); + return processConfigFile(text, cfgPath, availableOptions); +} + +function processConfigFile(text, cfgPath, availableOptions) { + const options = JSON.parse(text); + for (const [ key, value ] of Object.entries(options)) { + const option = availableOptions[key]; + if (!option) { + throwUnknownOption(key); + } + if (typeof(value) !== option.type) { + throw new Error(`${key} is expected to be a ${option.type}, received: ${value}`); + } + } + options.sourceFiles = getAbsoluteMapping(options.sourceFiles, dirname(cfgPath)); + return options; +} + +function getAbsoluteMapping(sourceFiles, cfgDir) { + if (!sourceFiles) { + return; + } + const map = {}; + for (const [ module, source ] of Object.entries(sourceFiles)) { + const modulePath = resolve(cfgDir, module); + const sourcePath = resolve(cfgDir, source); + map[modulePath] = sourcePath; + } + return map; +} + +function findSourceFile$1(modulePath, options) { + const { sourceFiles } = options; + return sourceFiles?.[modulePath]; +} + +function addMethods(s, env) { + const add = (target, { methods }, pushThis) => { + const descriptors = {}; + const re = /^(get|set)\s+([\s\S]+)/; + for (const method of methods) { + const f = env.createCaller(method, pushThis); + const m = re.exec(f.name); + if (m) { + // getter/setter + const type = m[1], propName = m[2]; + const argRequired = (type === 'get') ? 0 : 1; + const argCount = getArgumentCount(method, pushThis); + // need to match arg count, since instance methods also show up as static methods + if (argCount === argRequired) { + let descriptor = descriptors[propName]; + if (!descriptor) { + descriptor = descriptors[propName] = { configurable: true, enumerable: true }; + } + descriptor[type] = f; + } + } else { + descriptors[f.name] = { value: f, configurable: true, writable: true }; + } + } + defineProperties$a(target, descriptors); + }; + add(s.constructor, s.static, false); + add(s.constructor.prototype, s.instance, true); +} + +function getArgumentCount(method, pushThis) { + const { argStruct: { instance: { members } } } = method; + return members.length - (pushThis ? 2 : 1); +} + +function addStaticMembers(structure, env) { + const { + type, + constructor, + static: { members, template }, + } = structure; + const descriptors = {}; + for (const member of members) { + descriptors[member.name] = getDescriptor$a(member, env); + } + defineProperties$a(constructor, { + valueOf: { value: getValueOf$a }, + toJSON: { value: convertToJSON$a }, + ...descriptors, + [Symbol.iterator]: { value: getStructIterator$a }, + // static variables are objects stored in the static template's slots + [SLOTS$a]: template ? { value: template[SLOTS$a] } : undefined, + // anyerror would have props already + [PROPS$a]: !constructor[PROPS$a] ? { value: members.map(m => m.name) } : undefined, + [NORMALIZER$a]: { value: normalizeStruct$a }, + }); + if (type === StructureType$a.Enumeration) { + for (const { name, slot } of members) { + appendEnumeration$2(constructor, name, constructor[SLOTS$a][slot]); + } + } else if (type === StructureType$a.ErrorSet) { + for (const { name, slot } of members) { + appendErrorSet(constructor, name, constructor[SLOTS$a][slot]); + } + } +} + +class Environment { + context; + contextStack = []; + consolePending = []; + consoleTimeout = 0; + viewMap = new WeakMap(); + initPromise; + abandoned = false; + released = false; + littleEndian = true; + runtimeSafety = true; + comptime = false; + /* COMPTIME-ONLY */ + slotNumbers = {}; + slots = {}; + structures = []; + /* COMPTIME-ONLY-END */ + imports; + console = globalThis.console; + + /* + Functions to be defined in subclass: + + getBufferAddress(buffer: ArrayBuffer): bigint|number { + // return a buffer's address + } + allocateHostMemory(len: number, align: number): DataView { + // allocate memory and remember its address + } + allocateShadowMemory(len: number, align: number): DataView { + // allocate memory for shadowing objects + } + freeHostMemory(address: bigint|number, len: number, align: number): void { + // free previously allocated memory + } + freeShadowMemory(address: bigint|number, len: number, align: number): void { + // free memory allocated for shadow + } + allocateFixedMemory(len: number, align: number): DataView { + // allocate fixed memory and keep a reference to it + } + freeFixedMemory(address: bigint|number, len: number, align: number): void { + // free previously allocated fixed memory return the reference + } + obtainFixedView(address: bigint|number, len: number): DataView { + // obtain a data view of memory at given address + } + releaseFixedView(dv: DataView): void { + // release allocated memory stored in data view, doing nothing if data view + // does not contain fixed memory or if memory is static + } + inFixedMemory(object: object): boolean { + // return true/false depending on whether object is in fixed memory + } + copyBytes(dst: DataView, address: bigint|number, len: number): void { + // copy memory at given address into destination view + } + findSentinel(address: bigint|number, bytes: DataView): number { + // return offset where sentinel value is found + } + getMemoryOffset(address: bigint|number) number { + // return offset of address relative to start of module memory + } + recreateAddress(reloc: number) number { + // recreate address of memory belonging to module + } + + getTargetAddress(target: object, cluster: object|undefined) { + // return the address of target's buffer if correctly aligned + } + */ + + startContext() { + if (this.context) { + this.contextStack.push(this.context); + } + this.context = new CallContext(); + } + + endContext() { + this.context = this.contextStack.pop(); + } + + allocateMemory(len, align = 0, fixed = false) { + if (fixed) { + return this.allocateFixedMemory(len, align); + } else { + return this.allocateRelocMemory(len, align); + } + } + + allocateRelocMemory(len, align) { + return this.obtainView(new ArrayBuffer(len), 0, len); + } + + registerMemory(dv, targetDV = null, targetAlign = undefined) { + const { memoryList } = this.context; + const address = this.getViewAddress(dv); + const index = findMemoryIndex(memoryList, address); + memoryList.splice(index, 0, { address, dv, len: dv.byteLength, targetDV, targetAlign }); + return address; + } + + unregisterMemory(address) { + const { memoryList } = this.context; + const index = findMemoryIndex(memoryList, address); + const prev = memoryList[index - 1]; + if (prev?.address === address) { + memoryList.splice(index - 1, 1); + } + } + + findMemory(address, len) { + // check for null address (=== can't be used since address can be both number and bigint) + if (this.context) { + const { memoryList } = this.context; + const index = findMemoryIndex(memoryList, address); + const entry = memoryList[index - 1]; + if (entry?.address === address && entry.len === len) { + return entry.targetDV ?? entry.dv; + } else if (entry?.address <= address && address < add(entry.address, entry.len)) { + const offset = Number(address - entry.address); + const targetDV = entry.targetDV ?? entry.dv; + const isOpaque = len === undefined; + if (isOpaque) { + len = targetDV.byteLength - offset; + } + const dv = this.obtainView(targetDV.buffer, targetDV.byteOffset + offset, len); + if (isOpaque) { + // opaque structure--need to save the alignment + dv[ALIGN$a] = entry.targetAlign; + } + return dv; + } + } + // not found in any of the buffers we've seen--assume it's fixed memory + return this.obtainFixedView(address, len ?? 0); + } + + getViewAddress(dv) { + const address = this.getBufferAddress(dv.buffer); + return add(address, dv.byteOffset); + } + + obtainView(buffer, offset, len) { + let entry = this.viewMap.get(buffer); + if (!entry) { + const dv = new DataView(buffer, offset, len); + this.viewMap.set(buffer, dv); + return dv; + } + if (entry instanceof DataView) { + // only one view created thus far--see if that's the matching one + if (entry.byteOffset === offset && entry.byteLength === len) { + return entry; + } else { + // no, need to replace the entry with a hash keyed by `offset:len` + const dv = entry; + const key = `${dv.byteOffset}:${dv.byteLength}`; + entry = { [key]: dv }; + this.viewMap.set(buffer, entry); + } + } + const key = `${offset}:${len}`; + let dv = entry[key]; + if (!dv) { + dv = entry[key] = new DataView(buffer, offset, len); + } + return dv; + } + + captureView(address, len, copy) { + if (copy) { + // copy content into reloctable memory + const dv = this.allocateRelocMemory(len, 0); + if (len > 0) { + this.copyBytes(dv, address, len); + } + return dv; + } else { + // link into fixed memory + return this.obtainFixedView(address, len); + } + } + + castView(structure, dv, writable) { + const { constructor, hasPointer } = structure; + const object = constructor.call(ENVIRONMENT$a, dv, { writable }); + if (hasPointer) { + // acquire targets of pointers + this.acquirePointerTargets(object); + } + return object; + } + + /* COMPTIME-ONLY */ + getSlotNumber(scope, key) { + let slotNumber = this.slotNumbers[scope]; + if (!slotNumber) { + slotNumber = this.slotNumbers[scope] = { next: 0, map: {} }; + } + let slot = slotNumber.map[key]; + if (slot === undefined) { + slot = slotNumber.map[key] = slotNumber.next++; + } + return slot; + } + + readSlot(target, slot) { + const slots = target ? target[SLOTS$a] : this.slots; + return slots?.[slot]; + } + + writeSlot(target, slot, value) { + const slots = target ? target[SLOTS$a] : this.slots; + if (slots) { + slots[slot] = value; + } + } + + createTemplate(dv) { + return { + [MEMORY$a]: dv, + [SLOTS$a]: {} + }; + } + + beginStructure(def) { + const { + type, + name, + length, + byteSize, + align, + isConst, + hasPointer, + } = def; + return { + constructor: null, + typedArray: null, + type, + name, + length, + byteSize, + align, + isConst, + hasPointer, + instance: { + members: [], + methods: [], + template: null, + }, + static: { + members: [], + methods: [], + template: null, + }, + }; + } + + attachMember(structure, member, isStatic = false) { + const target = (isStatic) ? structure.static : structure.instance; + target.members.push(member); + } + + attachMethod(structure, method, isStaticOnly = false) { + structure.static.methods.push(method); + if (!isStaticOnly) { + structure.instance.methods.push(method); + } + } + + attachTemplate(structure, template, isStatic = false) { + const target = (isStatic) ? structure.static : structure.instance; + target.template = template; + } + + endStructure(structure) { + this.structures.push(structure); + this.finalizeStructure(structure); + for (const structure of this.structures) { + this.acquireDefaultPointers(structure); + } + } + + defineFactoryArgStruct() { + useBool$a(); + useObject$a(); + useArgStruct$a(); + const options = this.beginStructure({ + type: StructureType$a.Struct, + name: 'Options', + byteSize: 2, + hasPointer: false, + }); + this.attachMember(options, { + type: MemberType$a.Bool, + name: 'omitFunctions', + bitOffset: 0, + bitSize: 1, + byteSize: 1, + }); + this.attachMember(options, { + type: MemberType$a.Bool, + name: 'omitVariables', + bitOffset: 8, + bitSize: 1, + byteSize: 1, + }); + this.finalizeShape(options); + const structure = this.beginStructure({ + type: StructureType$a.ArgStruct, + name: 'factory', + byteSize: 2, + hasPointer: false, + }); + this.attachMember(structure, { + type: MemberType$a.Object, + name: '0', + bitOffset: 0, + bitSize: 16, + byteSize: 2, + slot: 0, + structure: options, + }); + this.attachMember(structure, { + type: MemberType$a.Void, + name: 'retval', + bitOffset: 16, + bitSize: 0, + byteSize: 0 + }); + this.finalizeShape(structure); + return structure.constructor; + } + + acquireStructures(options) { + const { + omitFunctions = false, + omitVariables = isElectron(), + } = options; + resetGlobalErrorSet(); + const thunkId = this.getFactoryThunk(); + const ArgStruct = this.defineFactoryArgStruct(); + const args = new ArgStruct([ { omitFunctions, omitVariables } ]); + this.comptime = true; + this.invokeThunk(thunkId, args); + this.comptime = false; + } + + getRootModule() { + const root = this.structures[this.structures.length - 1]; + return root.constructor; + } + + hasMethods() { + // all methods are static, so there's no need to check instance methods + return !!this.structures.find(s => s.static.methods.length > 0); + } + + exportStructures() { + this.prepareObjectsForExport(); + const { structures, runtimeSafety, littleEndian } = this; + return { + structures, + options: { runtimeSafety, littleEndian }, + keys: { MEMORY: MEMORY$a, SLOTS: SLOTS$a, CONST: CONST$a } + }; + } + + prepareObjectsForExport() { + const objects = findAllObjects(this.structures, SLOTS$a); + const list = []; + for (const object of objects) { + if (object[MEMORY$a]) { + if (this.inFixedMemory(object)) { + // replace fixed memory + const dv = object[MEMORY$a]; + const address = this.getViewAddress(dv); + const offset = this.getMemoryOffset(address); + const len = dv.byteLength; + const relocDV = this.captureView(address, len, true); + relocDV.reloc = offset; + object[MEMORY$a] = relocDV; + list.push({ offset, len, owner: object, replaced: false }); + } + } + } + // larger memory blocks come first + list.sort((a, b) => b.len - a.len); + for (const a of list) { + if (!a.replaced) { + for (const b of list) { + if (a !== b && !b.replaced) { + if (a.offset <= b.offset && b.offset < a.offset + a.len) { + // B is inside A--replace it with a view of A's buffer + const dv = a.owner[MEMORY$a]; + const pos = b.offset - a.offset + dv.byteOffset; + const newDV = this.obtainView(dv.buffer, pos, b.len); + newDV.reloc = b.offset; + b.owner[MEMORY$a] = newDV; + b.replaced = true; + } + } + } + } + } + } + + useStructures() { + const module = this.getRootModule(); + // add fixed memory object to list so they can be unlinked + const objects = findAllObjects(this.structures, SLOTS$a); + for (const object of objects) { + if (object[MEMORY$a] && this.inFixedMemory(object)) { + this.variables.push({ object }); + } + } + // clear comptime-only variables + this.slots = {}; + this.structures = []; + module.__zigar = this.getControlObject(); + return module; + } + /* COMPTIME-ONLY-END */ + + finalizeShape(structure) { + const f = getStructureFactory(structure.type); + const constructor = f(structure, this); + if (typeof(constructor) === 'function') { + defineProperties$a(constructor, { + name: { value: structure.name, configurable: true }, + }); + if (!constructor.prototype.hasOwnProperty(Symbol.toStringTag)) { + defineProperties$a(constructor.prototype, { + [Symbol.toStringTag]: { value: structure.name, configurable: true }, + }); + } + } + } + + finalizeStructure(structure) { + addStaticMembers(structure, this); + addMethods(structure, this); + } + + createCaller(method, useThis) { + const { name, argStruct, thunkId } = method; + const { constructor } = argStruct; + const self = this; + let f; + if (useThis) { + f = function(...args) { + return self.invokeThunk(thunkId, new constructor([ this, ...args ])); + }; + } else { + f = function(...args) { + return self.invokeThunk(thunkId, new constructor(args)); + }; + } + Object.defineProperty(f, 'name', { value: name }); + return f; + } + + + getShadowAddress(target, cluster) { + if (cluster) { + const dv = target[MEMORY$a]; + if (cluster.address === undefined) { + const shadow = this.createClusterShadow(cluster); + cluster.address = this.getViewAddress(shadow[MEMORY$a]); + } + return add(cluster.address, dv.byteOffset); + } else { + const shadow = this.createShadow(target); + return this.getViewAddress(shadow[MEMORY$a]); + } + } + + createShadow(object) { + const dv = object[MEMORY$a]; + // use the alignment of the structure; in the case of an opaque pointer's target, + // try to the alignment specified when the memory was allocated + const align = object.constructor[ALIGN$a] ?? dv[ALIGN$a]; + const shadow = Object.create(object.constructor.prototype); + const shadowDV = shadow[MEMORY$a] = this.allocateShadowMemory(dv.byteLength, align); + shadow[ATTRIBUTES] = { + address: this.getViewAddress(shadowDV), + len: shadowDV.byteLength, + align, + }; + return this.addShadow(shadow, object, align); + } + + addShadow(shadow, object, align) { + let { shadowMap } = this.context; + if (!shadowMap) { + shadowMap = this.context.shadowMap = new Map(); + } + shadowMap.set(shadow, object); + this.registerMemory(shadow[MEMORY$a], object[MEMORY$a], align); + return shadow; + } + + removeShadow(dv) { + const { shadowMap } = this.context; + if (shadowMap) { + for (const [ shadow ] of shadowMap) { + if (shadow[MEMORY$a] === dv) { + shadowMap.delete(shadow); + break; + } + } + } + } + + updateShadows() { + const { shadowMap } = this.context; + if (!shadowMap) { + return; + } + for (const [ shadow, object ] of shadowMap) { + shadow[COPIER$a](object); + } + } + + updateShadowTargets() { + const { shadowMap } = this.context; + if (!shadowMap) { + return; + } + for (const [ shadow, object ] of shadowMap) { + object[COPIER$a](shadow); + } + } + + releaseShadows() { + const { shadowMap } = this.context; + if (!shadowMap) { + return; + } + for (const [ shadow ] of shadowMap) { + const { address, len, align } = shadow[ATTRIBUTES]; + this.freeShadowMemory(address, len, align); + } + } + + acquirePointerTargets(args) { + const env = this; + const pointerMap = new Map(); + const callback = function({ isActive, isMutable }) { + const pointer = this[POINTER$a]; + if (pointerMap.get(pointer)) { + return; + } else { + pointerMap.set(pointer, true); + } + const writable = !pointer.constructor.const; + const currentTarget = pointer[SLOTS$a][0]; + let newTarget, location; + if (isActive(this)) { + const Target = pointer.constructor.child; + if (!currentTarget || isMutable(this)) { + // obtain address and length from memory + location = pointer[LOCATION_GETTER$a](); + if (!isInvalidAddress(location.address)) { + // get view of memory that pointer points to + const len = (Target[SIZE$a] !== undefined) ? location.length * Target[SIZE$a] : undefined; + const dv = env.findMemory(location.address, len); + // create the target + newTarget = Target.call(ENVIRONMENT$a, dv, { writable }); + } else { + newTarget = null; + } + } else { + newTarget = currentTarget; + } + } + // acquire objects pointed to by pointers in target + currentTarget?.[POINTER_VISITOR$a]?.(callback, { vivificate: true, isMutable: () => writable }); + if (newTarget !== currentTarget) { + newTarget?.[POINTER_VISITOR$a]?.(callback, { vivificate: true, isMutable: () => writable }); + pointer[SLOTS$a][0] = newTarget; + if (env.inFixedMemory(pointer)) { + pointer[FIXED_LOCATION$a] = location; + } + } + }; + args[POINTER_VISITOR$a](callback, { vivificate: true }); + } + + /* COMPTIME-ONLY */ + acquireDefaultPointers(structure) { + const { constructor, hasPointer, instance: { template } } = structure; + if (hasPointer && template && template[MEMORY$a]) { + // create a placeholder for retrieving default pointers + const placeholder = Object.create(constructor.prototype); + placeholder[MEMORY$a] = template[MEMORY$a]; + placeholder[SLOTS$a] = template[SLOTS$a]; + this.acquirePointerTargets(placeholder); + } + } + /* COMPTIME-ONLY-END */ +} + +class CallContext { + pointerProcessed = new Map(); + memoryList = []; + shadowMap = null; + /* WASM-ONLY */ + call = 0; + /* WASM-ONLY-END */ +} + +function findSortedIndex(array, value, cb) { + let low = 0; + let high = array.length; + if (high === 0) { + return 0; + } + while (low < high) { + const mid = Math.floor((low + high) / 2); + const value2 = cb(array[mid]); + if (value2 <= value) { + low = mid + 1; + } else { + high = mid; + } + } + return high; +} + +function findMemoryIndex(array, address) { + return findSortedIndex(array, address, m => m.address); +} + +function add(address, len) { + return address + ((typeof(address) === 'bigint') ? BigInt(len) : len); +} + +function isInvalidAddress(address) { + if (typeof(address) === 'bigint') { + return address === 0xaaaaaaaaaaaaaaaan; + } else { + return address === 0xaaaaaaaa; + } +} + +function isElectron() { + return typeof(process) === 'object' + && typeof(process?.versions) === 'object' + && !!process.versions?.electron; +} + +class WebAssemblyEnvironment extends Environment { + imports = { + getFactoryThunk: { argType: '', returnType: 'i' }, + allocateExternMemory: { argType: 'ii', returnType: 'i' }, + freeExternMemory: { argType: 'iii' }, + allocateShadowMemory: { argType: 'cii', returnType: 'v' }, + freeShadowMemory: { argType: 'ciii' }, + runThunk: { argType: 'iv', returnType: 'v' }, + isRuntimeSafetyActive: { argType: '', returnType: 'b' }, + }; + exports = { + allocateHostMemory: { argType: 'ii', returnType: 'v' }, + freeHostMemory: { argType: 'iii' }, + captureString: { argType: 'ii', returnType: 'v' }, + captureView: { argType: 'iib', returnType: 'v' }, + castView: { argType: 'vvb', returnType: 'v' }, + getSlotNumber: { argType: 'ii', returnType: 'i' }, + readSlot: { argType: 'vi', returnType: 'v' }, + writeSlot: { argType: 'viv' }, + getViewAddress: { argType: 'v', returnType: 'i' }, + beginDefinition: { returnType: 'v' }, + insertInteger: { argType: 'vsi', alias: 'insertProperty' }, + insertBoolean: { argType: 'vsb', alias: 'insertProperty' }, + insertString: { argType: 'vss', alias: 'insertProperty' }, + insertObject: { argType: 'vsv', alias: 'insertProperty' }, + beginStructure: { argType: 'v', returnType: 'v' }, + attachMember: { argType: 'vvb' }, + attachMethod: { argType: 'vvb' }, + createTemplate: { argType: 'v', returnType: 'v' }, + attachTemplate: { argType: 'vvb' }, + finalizeShape: { argType: 'v' }, + endStructure: { argType: 'v' }, + startCall: { argType: 'iv', returnType: 'i' }, + endCall: { argType: 'iv', returnType: 'i' }, + }; + nextValueIndex = 1; + valueTable = { 0: null }; + valueIndices = new Map; + memory = null; + // WASM is always little endian + littleEndian = true; + + allocateHostMemory(len, align) { + // allocate memory in both JavaScript and WASM space + const constructor = { [ALIGN$a]: align }; + const copier = getMemoryCopier$a(len); + const dv = this.allocateRelocMemory(len, align); + const shadowDV = this.allocateShadowMemory(len, align); + // create a shadow for the relocatable memory + const object = { constructor, [MEMORY$a]: dv, [COPIER$a]: copier }; + const shadow = { constructor, [MEMORY$a]: shadowDV, [COPIER$a]: copier }; + shadow[ATTRIBUTES] = { address: this.getViewAddress(shadowDV), len, align }; + this.addShadow(shadow, object, align); + return shadowDV; + } + + freeHostMemory(address, len, align) { + const dv = this.findMemory(address, len); + this.removeShadow(dv); + this.unregisterMemory(address); + this.freeShadowMemory(address, len, align); + } + + getBufferAddress(buffer) { + return 0; + } + + allocateFixedMemory(len, align) { + if (len === 0) { + return new DataView(this.memory.buffer, 0, 0); + } + const address = this.allocateExternMemory(len, align); + const dv = this.obtainFixedView(address, len); + dv[ALIGN$a] = align; + return dv; + } + + freeFixedMemory(address, len, align) { + if (len === 0) { + return; + } + this.freeExternMemory(address, len, align); + } + + obtainFixedView(address, len) { + const { memory } = this; + if (len === 0 && address === -1431655766) { // 0xAAAAAAAA + address = 0; + } + const dv = this.obtainView(memory.buffer, address, len); + dv[MEMORY$a] = { memory, address, len }; + return dv; + } + + releaseFixedView(dv) { + dv.buffer; + const address = dv.byteOffset; + const len = dv.byteLength; + // only allocated memory would have align attached + const align = dv[ALIGN$a]; + if (align !== undefined) { + this.freeFixedMemory(address, len, align); + } + } + + inFixedMemory(object) { + // reconnect any detached buffer before checking + if (!this.memory) { + return false; + } + restoreMemory$a.call(object); + return object[MEMORY$a].buffer === this.memory.buffer; + } + + copyBytes(dst, address, len) { + const { memory } = this; + const src = new DataView(memory.buffer, address, len); + const copy = getCopyFunction$a(len); + copy(dst, src); + } + + findSentinel(address, bytes) { + const { memory } = this; + const len = bytes.byteLength; + const end = memory.buffer.byteLength - len + 1; + for (let i = address; i < end; i += len) { + const dv = new DataView(memory.buffer, i, len); + let match = true; + for (let j = 0; j < len; j++) { + const a = dv.getUint8(j); + const b = bytes.getUint8(j); + if (a !== b) { + match = false; + break; + } + } + if (match) { + return (i - address) / len; + } + } + } + + captureString(address, len) { + const { buffer } = this.memory; + const ta = new Uint8Array(buffer, address, len); + return decodeText$a(ta); + } + + getTargetAddress(target, cluster) { + if (this.inFixedMemory(target)) { + return this.getViewAddress(target[MEMORY$a]); + } + if (target[MEMORY$a].byteLength === 0) { + // it's a null pointer/empty slice + return 0; + } + // relocatable buffers always need shadowing + return false; + } + + clearExchangeTable() { + if (this.nextValueIndex !== 1) { + this.nextValueIndex = 1; + this.valueTable = { 0: null }; + this.valueIndices = new Map(); + } + } + + getObjectIndex(object) { + if (object) { + let index = this.valueIndices.get(object); + if (index === undefined) { + index = this.nextValueIndex++; + this.valueIndices.set(object, index); + this.valueTable[index] = object; + } + return index; + } else { + return 0; + } + } + + fromWebAssembly(type, arg) { + switch (type) { + case 'v': + case 's': return this.valueTable[arg]; + case 'i': return arg; + case 'b': return !!arg; + } + } + + toWebAssembly(type, arg) { + switch (type) { + case 'v': + case 's': return this.getObjectIndex(arg); + case 'i': return arg; + case 'b': return arg ? 1 : 0; + } + } + + exportFunction(fn, argType = '', returnType = '') { + if (!fn) { + return () => {}; + } + return (...args) => { + args = args.map((arg, i) => this.fromWebAssembly(argType.charAt(i), arg)); + const retval = fn.apply(this, args); + return this.toWebAssembly(returnType, retval); + }; + } + + importFunction(fn, argType = '', returnType = '') { + let needCallContext = false; + if (argType.startsWith('c')) { + needCallContext = true; + argType = argType.slice(1); + } + return (...args) => { + args = args.map((arg, i) => this.toWebAssembly(argType.charAt(i), arg)); + if (needCallContext) { + args = [ this.context.call, ...args ]; + } + const retval = fn.apply(this, args); + return this.fromWebAssembly(returnType, retval); + }; + } + + exportFunctions() { + const imports = {}; + for (const [ name, { argType, returnType, alias } ] of Object.entries(this.exports)) { + const fn = this[alias ?? name]; + imports[`_${name}`] = this.exportFunction(fn, argType, returnType); + } + return imports; + } + + importFunctions(exports) { + for (const [ name, fn ] of Object.entries(exports)) { + const info = this.imports[name]; + if (info) { + const { argType, returnType } = info; + this[name] = this.importFunction(fn, argType, returnType); + } + } + } + + async instantiateWebAssembly(source) { + const res = await source; + const env = this.exportFunctions(); + const wasi = this.getWASI(); + const imports = { env, wasi_snapshot_preview1: wasi }; + if (res[Symbol.toStringTag] === 'Response') { + return WebAssembly.instantiateStreaming(res, imports); + } else { + return WebAssembly.instantiate(res, imports); + } + } + + loadModule(source) { + return this.initPromise = (async () => { + const { instance } = await this.instantiateWebAssembly(source); + const { memory, _initialize } = instance.exports; + this.importFunctions(instance.exports); + this.trackInstance(instance); + this.runtimeSafety = this.isRuntimeSafetyActive(); + this.memory = memory; + _initialize?.(); + })(); + } + + trackInstance(instance) { + // use WeakRef to detect whether web-assembly instance has been gc'ed + const ref = new WeakRef(instance); + Object.defineProperty(this, 'released', { get: () => !ref.deref(), enumerable: true }); + } + + linkVariables(writeBack) { + // linkage occurs when WASM compilation is complete and functions have been imported + // nothing needs to happen when WASM is not used + if (this.initPromise) { + this.initPromise = this.initPromise.then(() => super.linkVariables(writeBack)); + } + } + + /* COMPTIME-ONLY */ + beginDefinition() { + return {}; + } + + insertProperty(def, name, value) { + def[name] = value; + } + /* COMPTIME-ONLY-END */ + + getMemoryOffset(address) { + // WASM address space starts at 0 + return address; + } + + recreateAddress(reloc) { + return reloc; + } + + startCall(call, args) { + this.startContext(); + // call context, used by allocateShadowMemory and freeShadowMemory + this.context.call = call; + if (args[POINTER_VISITOR$a]) { + this.updatePointerAddresses(args); + } + // return address of shadow for argumnet struct + const address = this.getShadowAddress(args); + this.updateShadows(); + return address; + } + + endCall(call, args) { + this.updateShadowTargets(); + if (args[POINTER_VISITOR$a]) { + this.acquirePointerTargets(args); + } + this.releaseShadows(); + // restore the previous context if there's one + this.endContext(); + if (!this.context && this.flushConsole) { + this.flushConsole(); + } + } + + async runThunk(thunkId, args) { + // wait for compilation + await this.initPromise; + // invoke runThunk() from WASM code + return this.runThunk(thunkId, args); + } + + invokeThunk(thunkId, args) { + // wasm-exporter.zig will invoke startCall() with the context address and the args + // we can't do pointer fix up here since we need the context in order to allocate + // memory from the WebAssembly allocator; pointer target acquisition will happen in + // endCall() + const err = this.runThunk(thunkId, args); + // errors returned by exported Zig functions are normally written into the + // argument object and get thrown when we access its retval property (a zig error union) + // error strings returned by the thunk are due to problems in the thunking process + // (i.e. bugs in export.zig) + if (err) { + if (err[Symbol.toStringTag] === 'Promise') { + // getting a promise, WASM is not yet ready + // wait for fulfillment, then either return result or throw + return err.then((err) => { + if (err) { + throwZigError(err); + } + return args.retval; + }); + } else { + throwZigError(err); + } + } + return args.retval; + } + + getWASI() { + return { + proc_exit: (rval) => { + }, + fd_write: (fd, iovs_ptr, iovs_count, written_ptr) => { + if (fd === 1 || fd === 2) { + const dv = new DataView(this.memory.buffer); + let written = 0; + for (let i = 0, p = iovs_ptr; i < iovs_count; i++, p += 8) { + const buf_ptr = dv.getUint32(p, true); + const buf_len = dv.getUint32(p + 4, true); + const buf = new DataView(this.memory.buffer, buf_ptr, buf_len); + this.writeToConsole(buf); + written += buf_len; + } + dv.setUint32(written_ptr, written, true); + return 0; + } else { + return 1; + } + }, + random_get: (buf, buf_len) => { + const dv = new DataView(this.memory.buffer); + for (let i = 0; i < buf_len; i++) { + dv.setUint8(Math.floor(256 * Math.random())); + } + return 0; + }, + }; + } +} + +/* COMPTIME-ONLY */ + +// useAllMemberTypes(); +// useAllStructureTypes(); +// useAllExtendedTypes(); +/* COMPTIME-ONLY-END */ + +function createEnvironment(source) { + return new WebAssemblyEnvironment(); +} + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +function findSourceFile(modulePath, options) { + const { sourceFiles } = options; + return sourceFiles?.[modulePath]; +} + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +BigInt(Number.MAX_SAFE_INTEGER); +BigInt(Number.MIN_SAFE_INTEGER); + +process.cwd(); + +const MEMORY$9 = Symbol('memory'); +const SLOTS$9 = Symbol('slots'); +const PARENT$9 = Symbol('parent'); +const NAME$9 = Symbol('name'); +const CLASS$1 = Symbol('class'); +const TAG$9 = Symbol('tag'); +const PROPS$9 = Symbol('props'); +const GETTER$9 = Symbol('getter'); +const SETTER$9 = Symbol('setter'); +const ELEMENT_GETTER$9 = Symbol('elementGetter'); +const ELEMENT_SETTER$9 = Symbol('elementSetter'); +const LOCATION_GETTER$9 = Symbol('addressGetter'); +const LOCATION_SETTER$9 = Symbol('addressSetter'); +const TARGET_GETTER$9 = Symbol('targetGetter'); +const TARGET_SETTER$9 = Symbol('targetSetter'); +const FIXED_LOCATION$9 = Symbol('fixedLocation'); +const PROP_GETTERS$9 = Symbol('propGetters'); +const PROP_SETTERS$9 = Symbol('propSetters'); +const ALL_KEYS$9 = Symbol('allKeys'); +const LENGTH$9 = Symbol('length'); +const PROXY$9 = Symbol('proxy'); +const COMPAT$9 = Symbol('compat'); +const SIZE$9 = Symbol('size'); +const ALIGN$9 = Symbol('align'); +const ARRAY$9 = Symbol('array'); +const POINTER$9 = Symbol('pointer'); +const CONST$9 = Symbol('const'); +const CONST_PROTOTYPE$9 = Symbol('constProto'); +const COPIER$9 = Symbol('copier'); +const RESETTER$9 = Symbol('resetter'); +const NORMALIZER$9 = Symbol('normalizer'); +const VIVIFICATOR$9 = Symbol('vivificator'); +const POINTER_VISITOR$9 = Symbol('pointerVisitor'); +const ENVIRONMENT$9 = Symbol('environment'); +const MORE$9 = Symbol('more'); + +function getDestructor$9(env) { + return function() { + const dv = this[MEMORY$9]; + this[MEMORY$9] = null; + if (this[SLOTS$9]) { + this[SLOTS$9] = {}; + } + env.releaseFixedView(dv); + }; +} + +function getBitAlignFunction$9(bitPos, bitSize, toAligned) { + if (bitPos + bitSize <= 8) { + const mask = (2 ** bitSize) - 1; + if (toAligned) { + // from single byte + return function(dest, src, offset) { + const n = src.getUint8(offset); + const b = (n >> bitPos) & mask; + dest.setUint8(0, b); + }; + } else { + // to single byte + const destMask = 0xFF ^ (mask << bitPos); + return function(dest, src, offset) { + const n = src.getUint8(0); + const d = dest.getUint8(offset); + const b = (d & destMask) | ((n & mask) << bitPos); + dest.setUint8(offset, b); + }; + } + } else { + const leadBits = 8 - bitPos; + const leadMask = (2 ** leadBits) - 1; + if (toAligned) { + const trailBits = bitSize % 8; + const trailMask = (2 ** trailBits) - 1; + return function(dest, src, offset) { + let i = offset, j = 0; + let n = src.getUint8(i++), b; + let bitBuf = (n >> bitPos) & leadMask; + let bitCount = leadBits; + let remaining = bitSize; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + //bitCount += 8; + } + b = (remaining >= 8) ? bitBuf & 0xFF : bitBuf & trailMask; + dest.setUint8(j++, b); + bitBuf >>= 8; + //bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } else { + const trailBits = (bitSize - leadBits) % 8; + const trailMask = (2 ** trailBits) - 1; + const destMask1 = 0xFF ^ (leadMask << bitPos); + const destMask2 = 0xFF ^ trailMask; + return function(dest, src, offset) { + let i = 0, j = offset; + // preserve bits ahead of bitPos + let d = dest.getUint8(j), n, b; + let bitBuf = d & destMask1; + let bitCount = bitPos; + let remaining = bitSize + bitCount; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + bitCount += 8; + } + if (remaining >= 8) { + b = bitBuf & 0xFF; + } else { + // preserve bits at the destination sitting behind the trailing bits + d = dest.getUint8(j); + b = (d & destMask2) | (bitBuf & trailMask); + } + dest.setUint8(j++, b); + bitBuf >>= 8; + bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } + } +} + +function getMemoryCopier$9(size, multiple = false) { + const copy = getCopyFunction$9(size, multiple); + return function(target) { + /* WASM-ONLY */ + restoreMemory$9.call(this); + restoreMemory$9.call(target); + /* WASM-ONLY-END */ + const src = target[MEMORY$9]; + const dest = this[MEMORY$9]; + copy(dest, src); + }; +} + +function getCopyFunction$9(size, multiple = false) { + if (!multiple) { + const copier = copiers$9[size]; + if (copier) { + return copier; + } + } + if (!(size & 0x07)) return copy8x$9; + if (!(size & 0x03)) return copy4x$9; + if (!(size & 0x01)) return copy2x$9; + return copy1x$9; +} + +const copiers$9 = { + 1: copy1$9, + 2: copy2$9, + 4: copy4$9, + 8: copy8$9, + 16: copy16$9, + 32: copy32$9, +}; + +function copy1x$9(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i++) { + dest.setInt8(i, src.getInt8(i)); + } +} + +function copy2x$9(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 2) { + dest.setInt16(i, src.getInt16(i, true), true); + } +} + +function copy4x$9(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 4) { + dest.setInt32(i, src.getInt32(i, true), true); + } +} + +function copy8x$9(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 8) { + dest.setInt32(i, src.getInt32(i, true), true); + dest.setInt32(i + 4, src.getInt32(i + 4, true), true); + } +} + +function copy1$9(dest, src) { + dest.setInt8(0, src.getInt8(0)); +} + +function copy2$9(dest, src) { + dest.setInt16(0, src.getInt16(0, true), true); +} + +function copy4$9(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); +} + +function copy8$9(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); +} + +function copy16$9(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); +} + +function copy32$9(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); + dest.setInt32(16, src.getInt32(16, true), true); + dest.setInt32(20, src.getInt32(20, true), true); + dest.setInt32(24, src.getInt32(24, true), true); + dest.setInt32(28, src.getInt32(28, true), true); +} + +function getMemoryResetter$9(offset, size) { + const reset = getResetFunction$9(size); + return function() { + /* WASM-ONLY */ + restoreMemory$9.call(this); + /* WASM-ONLY-END */ + const dest = this[MEMORY$9]; + reset(dest, offset, size); + }; +} + +function getResetFunction$9(size) { + const resetter = resetters$9[size]; + if (resetter) { + return resetter; + } + if (!(size & 0x07)) return reset8x$9; + if (!(size & 0x03)) return reset4x$9; + if (!(size & 0x01)) return reset2x$9; + return reset1x$9; +} + +const resetters$9 = { + 1: reset1$9, + 2: reset2$9, + 4: reset4$9, + 8: reset8$9, + 16: reset16$9, + 32: reset32$9, +}; + +function reset1x$9(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i++) { + dest.setInt8(i, 0); + } +} + +function reset2x$9(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 2) { + dest.setInt16(i, 0, true); + } +} + +function reset4x$9(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 4) { + dest.setInt32(i, 0, true); + } +} + +function reset8x$9(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 8) { + dest.setInt32(i, 0, true); + dest.setInt32(i + 4, 0, true); + } +} + +function reset1$9(dest, offset) { + dest.setInt8(offset, 0); +} + +function reset2$9(dest, offset) { + dest.setInt16(offset, 0, true); +} + +function reset4$9(dest, offset) { + dest.setInt32(offset, 0, true); +} + +function reset8$9(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); +} + +function reset16$9(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); +} + +function reset32$9(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); + dest.setInt32(offset + 16, 0, true); + dest.setInt32(offset + 20, 0, true); + dest.setInt32(offset + 24, 0, true); + dest.setInt32(offset + 28, 0, true); +} + +function restoreMemory$9() { + const dv = this[MEMORY$9]; + const source = dv[MEMORY$9]; + if (!source || dv.buffer.byteLength !== 0) { + return false; + } + const { memory, address, len } = source; + const newDV = new DataView(memory.buffer, address, len); + newDV[MEMORY$9] = source; + this[MEMORY$9] = newDV; + return true; +} + +const decoders$9 = {}; +const encoders$9 = {}; + +function decodeText$9(arrays, encoding = 'utf-8') { + let decoder = decoders$9[encoding]; + if (!decoder) { + decoder = decoders$9[encoding] = new TextDecoder(encoding); + } + let array; + if (Array.isArray(arrays)) { + if (arrays.length === 1) { + array = arrays[0]; + } else { + let len = 0; + for (const a of arrays) { + len += a.length; + } + const { constructor } = arrays[0]; + array = new constructor(len); + let offset = 0; + for (const a of arrays) { + array.set(a, offset); + offset += a.length; + } + } + } else { + array = arrays; + } + return decoder.decode(array); +} + +function encodeText$9(text, encoding = 'utf-8') { + switch (encoding) { + case 'utf-16': { + const { length } = text; + const ta = new Uint16Array(length); + for (let i = 0; i < length; i++) { + ta[i] = text.charCodeAt(i); + } + return ta; + } + default: { + let encoder = encoders$9[encoding]; + if (!encoder) { + encoder = encoders$9[encoding] = new TextEncoder(); + } + return encoder.encode(text); + } + } +} + +function encodeBase64$9(dv) { + const ta = new Uint8Array(dv.buffer, dv.byteOffset, dv.byteLength); + const bstr = String.fromCharCode.apply(null, ta); + return btoa(bstr); +} + +function decodeBase64$9(str) { + const bstr = atob(str); + const ta = new Uint8Array(bstr.length); + for (let i = 0; i < ta.byteLength; i++) { + ta[i] = bstr.charCodeAt(i); + } + return new DataView(ta.buffer); +} + +function getValueOf$9() { + const map = new Map(); + const options = { error: 'throw' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$9]; + if (normalizer) { + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + map.set(value, result); + } + return result; + } else { + return value; + } + }; + return process(this); +} + +const INT_MAX$9 = BigInt(Number.MAX_SAFE_INTEGER); +const INT_MIN$9 = BigInt(Number.MIN_SAFE_INTEGER); + +function convertToJSON$9() { + const map = new Map(); + const options = { error: 'return' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$9]; + if (normalizer) { + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + if (typeof(result?.toJSON) === 'function') { + result = result.toJSON(); + } + map.set(value, result); + } + return result; + } else { + if (typeof(value) === 'bigint' && INT_MIN$9 <= value && value <= INT_MAX$9) { + return Number(value); + } + return value; + } + }; + return process(this); +} + +function normalizeValue$9(cb, options) { + const value = handleError$9(() => this.$, options); + return cb(value); +} + +function handleError$9(cb, options = {}) { + const { error = 'throw' } = options; + try { + return cb(); + } catch (err) { + if (error === 'return') { + return err; + } else { + throw err; + } + } +} + +function getDataViewDescriptor$9(structure, handlers = {}) { + return markAsSpecial$9({ + get() { + /* WASM-ONLY */ + restoreMemory$9.call(this); + /* WASM-ONLY-END */ + return this[MEMORY$9]; + }, + set(dv) { + checkDataView$9(dv); + setDataView$9.call(this, dv, structure, true, handlers); + }, + }); +} + +function getBase64Descriptor$9(structure, handlers = {}) { + return markAsSpecial$9({ + get() { + return encodeBase64$9(this.dataView); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$9('string', str); + } + const dv = decodeBase64$9(str); + setDataView$9.call(this, dv, structure, false, handlers); + } + }); +} + +function getStringDescriptor$9(structure, handlers = {}) { + const { sentinel, instance: { members }} = structure; + const { byteSize: charSize } = members[0]; + return markAsSpecial$9({ + get() { + const dv = this.dataView; + const TypedArray = (charSize === 1) ? Int8Array : Int16Array; + const ta = new TypedArray(dv.buffer, dv.byteOffset, this.length); + const s = decodeText$9(ta, `utf-${charSize * 8}`); + return (sentinel?.value === undefined) ? s : s.slice(0, -1); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$9('a string', str); + } + if (sentinel?.value !== undefined) { + if (str.charCodeAt(str.length - 1) !== sentinel.value) { + str = str + String.fromCharCode(sentinel.value); + } + } + const ta = encodeText$9(str, `utf-${charSize * 8}`); + const dv = new DataView(ta.buffer); + setDataView$9.call(this, dv, structure, false, handlers); + }, + }); +} + +function getTypedArrayDescriptor$9(structure, handlers = {}) { + const { typedArray } = structure; + return markAsSpecial$9({ + get() { + const dv = this.dataView; + const length = dv.byteLength / typedArray.BYTES_PER_ELEMENT; + return new typedArray(dv.buffer, dv.byteOffset, length); + }, + set(ta) { + if (!isTypedArray$9(ta, typedArray)) { + throwTypeMismatch$9(typedArray.name, ta); + } + const dv = new DataView(ta.buffer, ta.byteOffset, ta.byteLength); + setDataView$9.call(this, dv, structure, true, handlers); + }, + }); +} + +function markAsSpecial$9({ get, set }) { + get.special = set.special = true; + return { get, set }; +} + +function definePointer$9(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + isConst, + } = structure; + const { + runtimeSafety = true, + } = env; + const { structure: targetStructure } = member; + const { sentinel } = targetStructure; + const isTargetSlice = (targetStructure.type === StructureType$9.Slice); + const isTargetPointer = (targetStructure.type === StructureType$9.Pointer); + const hasLength = isTargetSlice && !sentinel; + const addressSize = (hasLength) ? byteSize / 2 : byteSize; + const { get: getAddress, set: setAddress } = getDescriptor$9({ + type: MemberType$9.Uint, + bitOffset: 0, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { byteSize: addressSize }, + }, env); + const { get: getLength, set: setLength } = (hasLength) ? getDescriptor$9({ + type: MemberType$9.Uint, + bitOffset: addressSize * 8, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { name: 'usize', byteSize: addressSize }, + }, env) : {}; + const updateTarget = function() { + const prevLocation = this[FIXED_LOCATION$9]; + if (prevLocation) { + const location = this[LOCATION_GETTER$9](); + if (location.address !== prevLocation.address || location.length !== prevLocation.length) { + const { constructor: Target } = targetStructure; + const dv = env.findMemory(location.address, location.length * Target[SIZE$9]); + const target = Target.call(ENVIRONMENT$9, dv, { writable: !isConst }); + this[SLOTS$9][0] = target; + this[FIXED_LOCATION$9] = location; + } + } + }; + const getTargetObject = function() { + updateTarget.call(this); + return this[SLOTS$9][0] ?? throwNullPointer$9(); + }; + const setTargetObject = function(arg) { + if (env.inFixedMemory(this)) { + // the pointer sits in fixed memory--apply the change immediately + if (env.inFixedMemory(arg)) { + const loc = { + address: env.getViewAddress(arg[MEMORY$9]), + length: (hasLength) ? arg.length : 1 + }; + addressSetter.call(this, loc); + this[FIXED_LOCATION$9] = loc; + } else { + throwFixedMemoryTargetRequired$9(); + } + } + this[SLOTS$9][0] = arg; + }; + const getTarget = isValueExpected$9(targetStructure) + ? function() { + const target = getTargetObject.call(this); + return target[GETTER$9](); + } + : getTargetObject; + const setTarget = function(value) { + updateTarget.call(this); + const object = this[SLOTS$9][0] ?? throwNullPointer$9(); + return object[SETTER$9](value); + }; + const alternateCaster = function(arg, options) { + const Target = targetStructure.constructor; + if ((this === ENVIRONMENT$9 || this === PARENT$9) || arg instanceof constructor) { + // casting from buffer to pointer is allowed only if request comes from the runtime + // casting from writable to read-only is also allowed + return false; + } else if (isPointerOf$9(arg, Target)) { + // const/non-const casting + return new constructor(Target(arg['*'], { writable: !isConst }), options); + } else if (isTargetSlice) { + // allow casting to slice through constructor of its pointer + return new constructor(Target(arg), options); + } else { + throwNoCastingToPointer$9(); + } + }; + const finalizer = function() { + const handlers = (isTargetPointer) ? {} : proxyHandlers$j; + const proxy = new Proxy(this, handlers); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$9, { value: proxy }); + return proxy; + }; + const initializer = function(arg) { + const Target = targetStructure.constructor; + if (isPointerOf$9(arg, Target)) { + // initialize with the other pointer'structure target + if (!isConst && arg.constructor.const) { + throwConstantConstraint$9(structure, arg); + } + arg = arg[SLOTS$9][0]; + } + if (arg instanceof Target) { + /* wasm-only */ + restoreMemory$9.call(arg); + /* wasm-only-end */ + if (isConst && !arg[CONST$9]) { + // create read-only version + arg = Target(arg, { writable: false }); + } else if (!isConst && arg[CONST$9]) { + throwReadOnlyTarget$9(structure); + } + } else if (isCompatible$9(arg, Target)) { + // autocast to target type + const dv = getDataView$9(targetStructure, arg, env); + arg = Target(dv, { writable: !isConst }); + } else if (arg !== undefined && !arg[MEMORY$9]) { + // autovivificate target object + const fixed = env.inFixedMemory(this); + const autoObj = new Target(arg, { writable: !isConst, fixed }); + if (runtimeSafety) { + // creation of a new slice using a typed array is probably + // not what the user wants; it's more likely that the intention + // is to point to the typed array but there's a mismatch (e.g. u32 vs i32) + if (targetStructure.typedArray && isBuffer$9(arg?.buffer)) { + warnImplicitArrayCreation$9(targetStructure, arg); + } + } + arg = autoObj; + } else if (arg !== undefined) { + throwInvalidPointerTarget$9(structure, arg); + } + this[TARGET_SETTER$9](arg); + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer, alternateCaster, finalizer }, env); + const addressSetter = function({ address, length }) { + setAddress.call(this, address); + setLength?.call(this, length); + }; + const addressGetter = function() { + const address = getAddress.call(this); + const length = (getLength) + ? getLength.call(this) + : (sentinel) + ? (address) ? env.findSentinel(address, sentinel.bytes) + 1 : 0 + : 1; + return { address, length }; + }; + const instanceDescriptors = { + '*': { get: getTarget, set: setTarget }, + '$': { get: getProxy$9, set: initializer }, + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [TARGET_GETTER$9]: { value: getTargetObject }, + [TARGET_SETTER$9]: { value: setTargetObject }, + [LOCATION_GETTER$9]: { value: addressGetter }, + [LOCATION_SETTER$9]: { value: addressSetter }, + [POINTER_VISITOR$9]: { value: visitPointer$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [VIVIFICATOR$9]: { value: throwNullPointer$9 }, + [NORMALIZER$9]: { value: normalizePointer$9 }, + [FIXED_LOCATION$9]: { value: undefined, writable: true }, + }; + const staticDescriptors = { + child: { get: () => targetStructure.constructor }, + const: { value: isConst }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizePointer$9(cb) { + let target; + try { + target = this['*']; + } catch (err) { + target = Symbol.for('inaccessible'); + } + return cb(target); +} + +function getProxy$9() { + return this[PROXY$9]; +} + +function copyPointer$9({ source }) { + const target = source[SLOTS$9][0]; + if (target) { + this[TARGET_SETTER$9](target); + } +} + +function resetPointer$9({ isActive }) { + if (this[SLOTS$9][0] && !isActive(this)) { + this[SLOTS$9][0] = undefined; + } +} + +function disablePointer$9() { + const disabledProp = { get: throwInaccessiblePointer$9, set: throwInaccessiblePointer$9 }; + const disabledFunc = { value: throwInaccessiblePointer$9 }; + defineProperties$9(this[POINTER$9], { + '*': disabledProp, + '$': disabledProp, + [GETTER$9]: disabledFunc, + [SETTER$9]: disabledFunc, + [TARGET_GETTER$9]: disabledFunc, + }); +} + +function visitPointer$9(fn, options = {}) { + const { + source, + isActive = always$9, + isMutable = always$9, + } = options; + fn.call(this, { source, isActive, isMutable }); +} + +function isPointerOf$9(arg, Target) { + return (arg?.constructor?.child === Target && arg['*']); +} + +const proxyHandlers$j = { + get(pointer, name) { + if (name === POINTER$9) { + return pointer; + } else if (name in pointer) { + return pointer[name]; + } else { + const target = pointer[TARGET_GETTER$9](); + return target[name]; + } + }, + set(pointer, name, value) { + if (name in pointer) { + pointer[name] = value; + } else { + const target = pointer[TARGET_GETTER$9](); + target[name] = value; + } + return true; + }, + deleteProperty(pointer, name) { + if (name in pointer) { + delete pointer[name]; + } else { + const target = pointer[TARGET_GETTER$9](); + delete target[name]; + } + return true; + }, + has(pointer, name) { + if (name in pointer) { + return true; + } else { + const target = pointer[TARGET_GETTER$9](); + return name in target; + } + }, +}; + +function always$9() { + return true; +} + +function never$9() { + return false; +} + +function defineStructShape$9(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const memberDescriptors = {}; + for (const member of members) { + const { get, set } = getDescriptor$9(member, env); + memberDescriptors[member.name] = { get, set, configurable: true, enumerable: true }; + if (member.isRequired && set) { + set.required = true; + } + } + const hasObject = !!members.find(m => m.type === MemberType$9.Object); + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + if (hasPointer) { + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } else if (arg && typeof(arg) === 'object') { + propApplier.call(this, arg); + } else if (arg !== undefined) { + throwInvalidInitializer$9(structure, 'object', arg); + } + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); + const instanceDescriptors = { + $: { get: getSelf$9, set: initializer }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getStructIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$j(structure, always$9) }, + [NORMALIZER$9]: { value: normalizeStruct$9 }, + [PROPS$9]: { value: members.map(m => m.name) }, + }; + const staticDescriptors = { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizeStruct$9(cb, options) { + const object = {}; + for (const [ name, value ] of getStructEntries$9.call(this, options)) { + object[name] = cb(value); + } + return object; +} + +function getStructEntries$9(options) { + return { + [Symbol.iterator]: getStructEntriesIterator$9.bind(this, options), + length: this[PROPS$9].length, + }; +} + +function getStructIterator$9(options) { + const entries = getStructEntries$9.call(this, options); + return entries[Symbol.iterator](); +} + +function getStructEntriesIterator$9(options) { + const self = this; + const props = this[PROPS$9]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + value = [ current, handleError$9(() => self[current], options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getChildVivificator$j(structure) { + const { instance: { members } } = structure; + const objectMembers = {}; + for (const member of members.filter(m => m.type === MemberType$9.Object)) { + objectMembers[member.slot] = member; + } + return function vivificateChild(slot, writable = true) { + const member = objectMembers[slot]; + const { bitOffset, byteSize, structure: { constructor } } = member; + const dv = this[MEMORY$9]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + (bitOffset >> 3); + let len = byteSize; + if (len === undefined) { + if (bitOffset & 7) { + throwNotOnByteBoundary$9(member); + } + len = member.bitSize >> 3; + } + const childDV = new DataView(dv.buffer, offset, len); + const object = this[SLOTS$9][slot] = constructor.call(PARENT$9, childDV, { writable }); + return object; + } +} + +function getPointerVisitor$j(structure, visitorOptions = {}) { + const { + isChildActive = always$9, + isChildMutable = always$9, + } = visitorOptions; + const { instance: { members } } = structure; + const pointerMembers = members.filter(m => m.structure.hasPointer); + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$9, + isMutable = always$9, + } = options; + const childOptions = { + ...options, + isActive: (object) => { + // make sure parent object is active, then check whether the child is active + return isActive(this) && isChildActive.call(this, object); + }, + isMutable: (object) => { + return isMutable(this) && isChildMutable.call(this, object); + }, + }; + for (const { slot } of pointerMembers) { + if (source) { + // when src is a the struct's template, most slots will likely be empty, + // since pointer fields aren't likely to have default values + const srcChild = source[SLOTS$9]?.[slot]; + if (!srcChild) { + continue; + } + childOptions.source = srcChild; + } + const child = this[SLOTS$9][slot] ?? (vivificate ? this[VIVIFICATOR$9](slot) : null); + if (child) { + child[POINTER_VISITOR$9](cb, childOptions); + } + } + }; +} + +function defineArgStruct$9(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const hasObject = !!members.find(m => m.type === MemberType$9.Object); + const constructor = structure.constructor = function(args) { + const dv = env.allocateMemory(byteSize, align); + this[MEMORY$9] = dv; + if (hasObject) { + this[SLOTS$9] = {}; + } + initializer.call(this, args); + }; + const argNames = members.slice(0, -1).map(m => m.name); + const argCount = argNames.length; + const initializer = function(args) { + if (args.length !== argCount) { + throwArgumentCountMismatch$9(structure, args.length); + } + for (const [ index, name ] of argNames.entries()) { + try { + this[name] = args[index]; + } catch (err) { + rethrowArgumentError$9(structure, index, err); + } + } + }; + const memberDescriptors = {}; + for (const member of members) { + memberDescriptors[member.name] = getDescriptor$9(member, env); + } + const isChildMutable = function(object) { + return (object === this.retval); + }; + defineProperties$9(constructor.prototype, { + ...memberDescriptors, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$j(structure, { isChildMutable }) }, + }); + defineProperties$9(constructor, { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }); + return constructor; +} + +function defineArray$9(structure, env) { + const { + length, + byteSize, + align, + instance: { members: [ member ] }, + hasPointer, + } = structure; + const { get, set } = getDescriptor$9(member, env); + const hasStringProp = canBeString$9(member); + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + if (hasPointer) { + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } else { + if (typeof(arg) === 'string' && hasStringProp) { + arg = { string: arg }; + } + if (arg?.[Symbol.iterator]) { + arg = transformIterable$9(arg); + if (arg.length !== length) { + throwArrayLengthMismatch$9(structure, this, arg); + } + let i = 0; + for (const value of arg) { + set.call(this, i++, value); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$9(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$9(structure, arg); + } + } + }; + const finalizer = createArrayProxy$9; + const constructor = structure.constructor = createConstructor$9(structure, { initializer, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); + const hasObject = member.type === MemberType$9.Object; + const instanceDescriptors = { + $: { get: getProxy$9, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + string: hasStringProp && getStringDescriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$9 }, + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [Symbol.iterator]: { value: getArrayIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$i(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$i() }, + [NORMALIZER$9]: { value: normalizeArray$9 }, + }; + const staticDescriptors = { + child: { get: () => member.structure.constructor }, + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function createArrayProxy$9() { + const proxy = new Proxy(this, proxyHandlers$i); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$9, { value: proxy }); + return proxy; +} + +function canBeString$9(member) { + return member.type === MemberType$9.Uint && [ 8, 16 ].includes(member.bitSize); +} + +function normalizeArray$9(cb, options) { + const array = []; + for (const [ index, value ] of getArrayEntries$9.call(this, options)) { + array.push(cb(value)); + } + return array; +} + +function getArrayIterator$9() { + const self = this[ARRAY$9] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self.get(current); + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getArrayEntriesIterator$9(options) { + const self = this[ARRAY$9] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, handleError$9(() => self.get(current), options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getArrayEntries$9(options) { + return { + [Symbol.iterator]: getArrayEntriesIterator$9.bind(this, options), + length: this.length, + }; +} + +function getChildVivificator$i(structure) { + const { instance: { members: [ member ]} } = structure; + const { byteSize, structure: elementStructure } = member; + return function getChild(index, writable = true) { + const { constructor } = elementStructure; + const dv = this[MEMORY$9]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + byteSize * index; + const childDV = new DataView(dv.buffer, offset, byteSize); + const object = this[SLOTS$9][index] = constructor.call(PARENT$9, childDV, { writable }); + return object; + }; +} + +function getPointerVisitor$i(structure) { + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$9, + isMutable = always$9, + } = options; + const childOptions = { + ...options, + isActive: () => isActive(this), + isMutable: () => isMutable(this), + }; + for (let i = 0, len = this.length; i < len; i++) { + // no need to check for empty slots, since that isn't possible + if (source) { + childOptions.source = source?.[SLOTS$9][i]; + } + const child = this[SLOTS$9][i] ?? (vivificate ? this[VIVIFICATOR$9](i) : null); + if (child) { + child[POINTER_VISITOR$9](cb, childOptions); + } + } + }; +} + +function transformIterable$9(arg) { + if (typeof(arg.length) === 'number') { + // it's an array of sort + return arg; + } + const iterator = arg[Symbol.iterator](); + const first = iterator.next(); + const length = first.value?.length; + if (typeof(length) === 'number' && Object.keys(first.value).join() === 'length') { + // return generator with length attached + return Object.assign((function*() { + let result; + while (!(result = iterator.next()).done) { + yield result.value; + } + })(), { length }); + } else { + const array = []; + let result = first; + while (!result.done) { + array.push(result.value); + result = iterator.next(); + } + return array; + } +} + +const proxyHandlers$i = { + get(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return array.get(index); + } else { + switch (name) { + case 'get': + if (!array[ELEMENT_GETTER$9]) { + array[ELEMENT_GETTER$9] = array.get.bind(array); + } + return array[ELEMENT_GETTER$9]; + case 'set': + if (!array[ELEMENT_SETTER$9]) { + array[ELEMENT_SETTER$9] = array.set.bind(array); + } + return array[ELEMENT_SETTER$9]; + case ARRAY$9: + return array; + default: + return array[name]; + } + } + }, + set(array, name, value) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + array.set(index, value); + } else { + switch (name) { + case 'get': + array[ELEMENT_GETTER$9] = value; + break; + case 'set': + array[ELEMENT_SETTER$9] = value; + break; + default: + array[name] = value; + } + } + return true; + }, + deleteProperty(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return false; + } else { + switch (name) { + case 'get': + delete array[ELEMENT_GETTER$9]; + break; + case 'set': + delete array[ELEMENT_SETTER$9]; + break; + default: + delete array[name]; + } + return true; + } + }, + has(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return (index >= 0 && index < array.length); + } else { + return array[name]; + } + }, + ownKeys(array) { + const keys = []; + for (let i = 0, len = array.length; i < len; i++) { + keys.push(`${i}`); + } + keys.push('length', PROXY$9); + return keys; + }, + getOwnPropertyDescriptor(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + if (index >= 0 && index < array.length) { + return { value: array.get(index), enumerable: true, writable: true, configurable: true }; + } + } else { + return Object.getOwnPropertyDescriptor(array, name); + } + }, +}; + +function defineEnumerationShape$9(structure, env) { + const { + byteSize, + align, + instance: { + members: [ member ], + }, + } = structure; + const { get, set } = getDescriptor$9(member, env); + const expected = [ 'string', 'number', 'tagged union' ]; + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$9(structure, expected, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'string' || typeof(arg) === 'number' || typeof(arg) === 'bigint') { + let item = constructor[arg]; + if (!item) { + if (constructor[MORE$9] && typeof(arg) !== 'string') { + // create the item on-the-fly when enum is non-exhaustive + item = new constructor(undefined); + debugger; + set.call(item, arg, 'number'); + appendEnumeration$1(constructor, `${arg}`, item); + } + } + return item; + } else if (arg instanceof constructor) { + return arg; + } else if (arg?.[TAG$9] instanceof constructor) { + // a tagged union, return the active tag + return arg[TAG$9]; + } else if (!getDataView$9(structure, arg, env)) { + throwInvalidInitializer$9(structure, expected, arg); + } else { + return false; + } + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); + const toPrimitive = function(hint) { + return (hint === 'string') ? this.$[NAME$9] : get.call(this, 'number'); + }; + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [Symbol.toPrimitive]: { value: toPrimitive }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: normalizeEnumerationItem$9 }, + }; + const staticDescriptors = { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} +function normalizeEnumerationItem$9(cb) { + return cb(this.$[NAME$9]); +} + +function appendEnumeration$1(enumeration, name, item) { + if (name !== undefined) { + // enum can have static variables + if (item instanceof enumeration) { + // attach name to item so tagged union code can quickly find it + defineProperties$9(item, { [NAME$9]: { value: name } }); + // call toPrimitive directly since enum can be bigint or number + const index = item[Symbol.toPrimitive](); + defineProperties$9(enumeration, { + [index]: { value: item }, + [name]: { value: item }, + }); + } + } else { + // non-exhaustive enum + defineProperties$9(enumeration, { [MORE$9]: { value: true } }); + } +} + +function defineErrorUnion$9(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const { get: getValue, set: setValue } = getDescriptor$9(members[0], env); + const { get: getError, set: setError } = getDescriptor$9(members[1], env); + const get = function() { + const errNum = getError.call(this, 'number'); + if (errNum) { + throw getError.call(this); + } else { + return getValue.call(this); + } + }; + const isValueVoid = members[0].type === MemberType$9.Void; + const TargetError = members[1].structure.constructor[CLASS$1]; + const isChildActive = function() { + return !getError.call(this, 'number'); + }; + const clearValue = function() { + this[RESETTER$9](); + this[POINTER_VISITOR$9]?.(resetPointer$9); + }; + const hasObject = !!members.find(m => m.type === MemberType$9.Object); + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + if (hasPointer) { + if (isChildActive.call(this)) { + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } + } else if (arg instanceof TargetError) { + setError.call(this, arg); + clearValue.call(this); + } else if (arg !== undefined || isValueVoid) { + try { + // call setValue() first, in case it throws + setValue.call(this, arg); + setError.call(this, 0, 'number'); + } catch (err) { + if (arg instanceof Error) { + // we give setValue a chance to see if the error is actually an acceptable value + // now is time to throw an error + throwNotInErrorSet$9(structure); + } else if (isErrorJSON$1(arg)) { + setError.call(this, arg); + clearValue.call(this); + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throw err; + } + } else { + throw err; + } + } + } + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); + const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; + const instanceDescriptors = { + '$': { get, set: initializer }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [RESETTER$9]: { value: getMemoryResetter$9(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$j(structure, { isChildActive }) }, + [NORMALIZER$9]: { value: normalizeValue$9 }, + }; + const staticDescriptors = { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function defineOpaque$9(structure, env) { + const { + byteSize, + align, + } = structure; + const initializer = function() { + throwCreatingOpaque$9(structure); + }; + const valueAccessor = function() { + throwAccessingOpaque$9(structure); + }; + const toPrimitive = function(hint) { + const { name } = structure; + return `[opaque ${name}]`; + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); + const instanceDescriptors = { + $: { get: valueAccessor, set: valueAccessor }, + dataView: getDataViewDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [Symbol.toPrimitive]: { value: toPrimitive }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: normalizeOpaque$9 }, + }; + const staticDescriptors = { + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} +function normalizeOpaque$9(cb) { + return {}; +} + +function defineOptional$9(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const { get: getValue, set: setValue } = getDescriptor$9(members[0], env); + const { get: getPresent, set: setPresent } = getDescriptor$9(members[1], env); + const hasPresentFlag = !(members[0].bitSize > 0 && members[0].bitOffset === members[1].bitOffset); + const get = function() { + const present = getPresent.call(this); + if (present) { + return getValue.call(this); + } else { + this[POINTER_VISITOR$9]?.(resetPointer$9); + return null; + } + }; + const isValueVoid = members[0].type === MemberType$9.Void; + const isChildActive = getPresent; + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + if (hasPointer) { + // don't bother copying pointers when it's empty + if (isChildActive.call(arg)) { + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } + } else if (arg === null) { + setPresent.call(this, false); + this[RESETTER$9]?.(); + // clear references so objects can be garbage-collected + this[POINTER_VISITOR$9]?.(resetPointer$9); + } else if (arg !== undefined || isValueVoid) { + // call setValue() first, in case it throws + setValue.call(this, arg); + if (hasPresentFlag || !env.inFixedMemory(this)) { + // since setValue() wouldn't write address into memory when the pointer is in + // relocatable memory, we need to use setPresent() in order to write something + // non-zero there so that we know the field is populated + setPresent.call(this, true); + } + } + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); + const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; + const hasObject = !!members.find(m => m.type === MemberType$9.Object); + const instanceDescriptors = { + $: { get, set: initializer }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + // no need to reset the value when it's a pointer, since setPresent() would null out memory used by the pointer + [RESETTER$9]: !hasPointer && { value: getMemoryResetter$9(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$j(structure, { isChildActive }) }, + [NORMALIZER$9]: { value: normalizeValue$9 }, + }; + const staticDescriptors = { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function definePrimitive$9(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { get, set } = getDescriptor$9(member, env); + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + } else { + if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + const type = getPrimitiveType$9(member); + throwInvalidInitializer$9(structure, type, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + } + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [Symbol.toPrimitive]: { value: get }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: normalizeValue$9 }, + }; + const staticDescriptors = { + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} +function getIntRange$9(member) { + const { type, bitSize } = member; + const signed = (type === MemberType$9.Int); + let magBits = (signed) ? bitSize - 1 : bitSize; + if (bitSize <= 32) { + const max = 2 ** magBits - 1; + const min = (signed) ? -(2 ** magBits) : 0; + return { min, max }; + } else { + magBits = BigInt(magBits); + const max = 2n ** magBits - 1n; + const min = (signed) ? -(2n ** magBits) : 0n; + return { min, max }; + } +} + +function getPrimitiveClass$9({ type, bitSize }) { + if (type === MemberType$9.Int || type === MemberType$9.Uint) { + if (bitSize <= 32) { + return Number; + } else { + return BigInt; + } + } else if (type === MemberType$9.Float) { + return Number; + } else if (type === MemberType$9.Bool) { + return Boolean; + } +} + +function getPrimitiveType$9(member) { + const Primitive = getPrimitiveClass$9(member); + if (Primitive) { + return typeof(Primitive(0)); + } +} + +function defineSlice$9(structure, env) { + const { + align, + instance: { + members: [ member ], + }, + hasPointer, + } = structure; + const { get, set } = getDescriptor$9(member, env); + const { byteSize: elementSize, structure: elementStructure } = member; + const sentinel = getSentinel$9(structure, env); + if (sentinel) { + // zero-terminated strings aren't expected to be commonly used + // so we're not putting this prop into the standard structure + structure.sentinel = sentinel; + } + const hasStringProp = canBeString$9(member); + const shapeDefiner = function(dv, length, fixed = false) { + if (!dv) { + dv = env.allocateMemory(length * elementSize, align, fixed); + } + this[MEMORY$9] = dv; + this[LENGTH$9] = length; + }; + const shapeChecker = function(arg, length) { + if (length !== this[LENGTH$9]) { + throwArrayLengthMismatch$9(structure, this, arg); + } + }; + // the initializer behave differently depending on whether it's called by the + // constructor or by a member setter (i.e. after object's shape has been established) + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg, fixed = false) { + if (arg instanceof constructor) { + if (!this[MEMORY$9]) { + shapeDefiner.call(this, null, arg.length, fixed); + } else { + shapeChecker.call(this, arg, arg.length); + } + this[COPIER$9](arg); + if (hasPointer) { + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } else if (typeof(arg) === 'string' && hasStringProp) { + initializer.call(this, { string: arg }, fixed); + } else if (arg?.[Symbol.iterator]) { + arg = transformIterable$9(arg); + if (!this[MEMORY$9]) { + shapeDefiner.call(this, null, arg.length, fixed); + } else { + shapeChecker.call(this, arg, arg.length); + } + let i = 0; + for (const value of arg) { + sentinel?.validateValue(value, i, arg.length); + set.call(this, i++, value); + } + } else if (typeof(arg) === 'number') { + if (!this[MEMORY$9] && arg >= 0 && isFinite(arg)) { + shapeDefiner.call(this, null, arg); + } else { + throwInvalidArrayInitializer$9(structure, arg, !this[MEMORY$9]); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$9(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$9(structure, arg); + } + }; + const finalizer = createArrayProxy$9; + const constructor = structure.constructor = createConstructor$9(structure, { initializer, shapeDefiner, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); + const hasObject = member.type === MemberType$9.Object; + const shapeHandlers = { shapeDefiner }; + const instanceDescriptors = { + $: { get: getProxy$9, set: initializer }, + length: { get: getLength$9 }, + dataView: getDataViewDescriptor$9(structure, shapeHandlers), + base64: getBase64Descriptor$9(structure, shapeHandlers), + string: hasStringProp && getStringDescriptor$9(structure, shapeHandlers), + typedArray: typedArray && getTypedArrayDescriptor$9(structure, shapeHandlers), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$9 }, + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [Symbol.iterator]: { value: getArrayIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(elementSize, true) }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$i(structure) }, + [POINTER_VISITOR$9]: hasPointer && { value: getPointerVisitor$i() }, + [NORMALIZER$9]: { value: normalizeArray$9 }, + }; + const staticDescriptors = { + child: { get: () => elementStructure.constructor }, + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: elementSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function getLength$9() { + return this[LENGTH$9]; +} + +function getSentinel$9(structure, env) { + const { + runtimeSafety = true, + } = env; + const { + byteSize, + instance: { members: [ member, sentinel ], template }, + } = structure; + if (!sentinel) { + return; + } + const { get: getSentinelValue } = getDescriptor$9(sentinel, env); + const value = getSentinelValue.call(template, 0); + const { get } = getDescriptor$9(member, env); + const validateValue = (runtimeSafety) ? function(v, i, l) { + if (v === value && i !== l - 1) { + throwMisplacedSentinel$9(structure, v, i, l); + } else if (v !== value && i === l - 1) { + throwMissingSentinel$9(structure, value, i); + } + } : function(v, i, l) { + if (v !== value && i === l - 1) { + throwMissingSentinel$9(structure, value, l); + } + }; + const validateData = (runtimeSafety) ? function(source, len) { + for (let i = 0; i < len; i++) { + const v = get.call(source, i); + if (v === value && i !== len - 1) { + throwMisplacedSentinel$9(structure, value, i, len); + } else if (v !== value && i === len - 1) { + throwMissingSentinel$9(structure, value, len); + } + } + } : function(source, len) { + if (len * byteSize === source[MEMORY$9].byteLength) { + const i = len - 1; + const v = get.call(source, i); + if (v !== value) { + throwMissingSentinel$9(structure, value, len); + } + } + }; + const bytes = template[MEMORY$9]; + return { value, bytes, validateValue, validateData }; +} + +function defineUnionShape$9(structure, env) { + const { + type, + byteSize, + align, + instance: { members, template }, + hasPointer, + } = structure; + const { runtimeSafety } = env; + const isTagged = (type === StructureType$9.TaggedUnion); + const exclusion = (isTagged || (type === StructureType$9.BareUnion && runtimeSafety)); + const memberDescriptors = {}; + const memberInitializers = {}; + const memberValueGetters = {}; + const valueMembers = (exclusion) ? members.slice(0, -1) : members; + const selectorMember = (exclusion) ? members[members.length - 1] : null; + const { get: getSelector, set: setSelector } = (exclusion) ? getDescriptor$9(selectorMember, env) : {}; + const getActiveField = (isTagged) + ? function() { + const item = getSelector.call(this); + return item[NAME$9]; + } + : function() { + const index = getSelector.call(this); + return valueMembers[index].name; + }; + const setActiveField = (isTagged) + ? function(name) { + const { constructor } = selectorMember.structure; + setSelector.call(this, constructor[name]); + } + : function(name) { + const index = valueMembers.findIndex(m => m.name === name); + setSelector.call(this, index); + }; + for (const member of valueMembers) { + const { name } = member; + const { get: getValue, set: setValue } = getDescriptor$9(member, env); + const get = (exclusion) + ? function() { + const currentName = getActiveField.call(this); + if (name !== currentName) { + if (isTagged) { + // tagged union allows inactive member to be queried + return null; + } else { + // whereas bare union does not, since the condition is not detectable + // when runtime safety is off + throwInactiveUnionProperty$9(structure, name, currentName); + } + } + this[POINTER_VISITOR$9]?.(resetPointer$9); + return getValue.call(this); + } + : getValue; + const set = (exclusion && setValue) + ? function(value) { + const currentName = getActiveField.call(this); + if (name !== currentName) { + throwInactiveUnionProperty$9(structure, name, currentName); + } + setValue.call(this, value); + } + : setValue; + const init = (exclusion && setValue) + ? function(value) { + setActiveField.call(this, name); + setValue.call(this, value); + this[POINTER_VISITOR$9]?.(resetPointer$9); + } + : setValue; + memberDescriptors[name] = { get, set, configurable: true, enumerable: true }; + memberInitializers[name] = init; + memberValueGetters[name] = getValue; + } + const hasDefaultMember = !!valueMembers.find(m => !m.isRequired); + const memberKeys = Object.keys(memberDescriptors); + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + /* WASM-ONLY-END */ + this[COPIER$9](arg); + if (hasPointer) { + this[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } else if (arg && typeof(arg) === 'object') { + let found = 0; + for (const key of memberKeys) { + if (key in arg) { + found++; + } + } + if (found > 1) { + throwMultipleUnionInitializers$9(structure); + } + if (propApplier.call(this, arg) === 0 && !hasDefaultMember) { + throwMissingUnionInitializer$9(structure, arg, exclusion); + } + } else if (arg !== undefined) { + throwInvalidInitializer$9(structure, 'object with a single property', arg); + } + }; + // non-tagged union as marked as not having pointers--if there're actually + // members with pointers, we need to disable them + const pointerMembers = members.filter(m => m.structure.hasPointer); + const hasInaccessiblePointer = !hasPointer && (pointerMembers.length > 0); + const modifier = (hasInaccessiblePointer && !env.comptime) + ? function() { + // make pointer access throw + this[POINTER_VISITOR$9](disablePointer$9, { vivificate: true }); + } + : undefined; + const constructor = structure.constructor = createConstructor$9(structure, { modifier, initializer }, env); + const fieldDescriptor = (isTagged) + ? { + // for tagged union, only the active field + get() { return [ getActiveField.call(this) ] } + } + : { + // for bare and extern union, all members are included + value: valueMembers.map(m => m.name) + }; + const isChildActive = (isTagged) + ? function(child) { + const name = getActiveField.call(this); + const active = memberValueGetters[name].call(this); + return child === active; + } + : never$9; + const hasAnyPointer = hasPointer || hasInaccessiblePointer; + const hasObject = !!members.find(m => m.type === MemberType$9.Object); + const instanceDescriptors = { + $: { get: getSelf$9, set: initializer, configurable: true }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getUnionIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [TAG$9]: isTagged && { get: getSelector, configurable: true }, + [VIVIFICATOR$9]: hasObject && { value: getChildVivificator$j(structure) }, + [POINTER_VISITOR$9]: hasAnyPointer && { value: getPointerVisitor$j(structure, { isChildActive }) }, + [PROP_GETTERS$9]: { value: memberValueGetters }, + [NORMALIZER$9]: { value: normalizeUnion$9 }, + [PROPS$9]: fieldDescriptor, + }; + const staticDescriptors = { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); + // replace regular setters with ones that change the active field + const setters = constructor.prototype[PROP_SETTERS$9]; + for (const [ name, init ] of Object.entries(memberInitializers)) { + if (init) { + setters[name] = init; + } + } +} +function normalizeUnion$9(cb, options) { + const object = {}; + for (const [ name, value ] of getUnionEntries$9.call(this, options)) { + object[name] = cb(value); + } + return object; +} + +function getUnionEntries$9(options) { + return { + [Symbol.iterator]: getUnionEntriesIterator$9.bind(this, options), + length: this[PROPS$9].length, + }; +} + +function getUnionIterator$9(options) { + const entries = getUnionEntries$9.call(this, options); + return entries[Symbol.iterator](); +} + +function getUnionEntriesIterator$9(options) { + const self = this; + const props = this[PROPS$9]; + const getters = this[PROP_GETTERS$9]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + // get value of prop with no check + value = [ current, handleError$9(() => getters[current].call(self), options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function defineVector$9(structure, env) { + const { + length, + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { bitSize: elementBitSize, structure: elementStructure } = member; + const elementDescriptors = {}; + for (let i = 0, bitOffset = 0; i < length; i++, bitOffset += elementBitSize) { + const { get, set } = getDescriptor$9({ ...member, bitOffset }, env); + elementDescriptors[i] = { get, set, configurable: true }; + } + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$9](arg); + } else if (arg?.[Symbol.iterator]) { + let argLen = arg.length; + if (typeof(argLen) !== 'number') { + arg = [ ...arg ]; + argLen = arg.length; + } + if (argLen !== length) { + throwArrayLengthMismatch$9(structure, this, arg); + } + let i = 0; + for (const value of arg) { + this[PROP_SETTERS$9][i++].call(this, value); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$9(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$9(structure, arg); + } + }; + const constructor = structure.constructor = createConstructor$9(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); + const instanceDescriptors = { + ...elementDescriptors, + $: { get: getSelf$9, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + entries: { value: getVectorEntries$9 }, + delete: { value: getDestructor$9(structure) }, + [Symbol.iterator]: { value: getVectorIterator$9 }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: normalizeVector$9 }, + }; + const staticDescriptors = { + child: { get: () => elementStructure.constructor }, + [COMPAT$9]: { value: getCompatibleTags$9(structure) }, + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizeVector$9(cb, options) { + const array = []; + for (const [ index, value ] of getVectorEntries$9.call(this, options)) { + array.push(cb(value)); + } + return array; +} + +function getVectorIterator$9() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self[current]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getVectorEntriesIterator$9() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, self[current] ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getVectorEntries$9() { + return { + [Symbol.iterator]: getVectorEntriesIterator$9.bind(this), + length: this.length, + }; +} + +const StructureType$9 = { + Primitive: 0, + Array: 1, + Struct: 2, + ExternStruct: 3, + PackedStruct: 4, + ArgStruct: 5, + ExternUnion: 6, + BareUnion: 7, + TaggedUnion: 8, + ErrorUnion: 9, + ErrorSet: 10, + Enumeration: 11, + Optional: 12, + Pointer: 13, + Slice: 14, + Vector: 15, + Opaque: 16, + Function: 17, +}; + +const factories$t = Array(Object.values(StructureType$9).length); + +function usePrimitive$9() { + factories$t[StructureType$9.Primitive] = definePrimitive$9; +} + +function useArray$9() { + factories$t[StructureType$9.Array] = defineArray$9; +} + +function useStruct$9() { + factories$t[StructureType$9.Struct] = defineStructShape$9; +} + +function usePackedStruct$9() { + factories$t[StructureType$9.PackedStruct] = defineStructShape$9; +} + +function useExternStruct$9() { + factories$t[StructureType$9.ExternStruct] = defineStructShape$9; +} + +function useArgStruct$9() { + factories$t[StructureType$9.ArgStruct] = defineArgStruct$9; +} + +function useExternUnion$9() { + factories$t[StructureType$9.ExternUnion] = defineUnionShape$9; +} + +function useBareUnion$9() { + factories$t[StructureType$9.BareUnion] = defineUnionShape$9; +} + +function useTaggedUnion$9() { + factories$t[StructureType$9.TaggedUnion] = defineUnionShape$9; +} + +function useErrorUnion$9() { + factories$t[StructureType$9.ErrorUnion] = defineErrorUnion$9; +} + +function useErrorSet$9() { + factories$t[StructureType$9.ErrorSet] = defineErrorSet$9; + useErrorSetTransform$1(); +} + +function useEnumeration$9() { + factories$t[StructureType$9.Enumeration] = defineEnumerationShape$9; + useEnumerationTransform$1(); +} + +function useOptional$9() { + factories$t[StructureType$9.Optional] = defineOptional$9; +} + +function usePointer$9() { + factories$t[StructureType$9.Pointer] = definePointer$9; + useUint$9(); +} + +function useSlice$9() { + factories$t[StructureType$9.Slice] = defineSlice$9; +} + +function useVector$9() { + factories$t[StructureType$9.Vector] = defineVector$9; +} + +function useOpaque$9() { + factories$t[StructureType$9.Opaque] = defineOpaque$9; +} + +function defineProperties$9(object, descriptors) { + for (const [ name, descriptor ] of Object.entries(descriptors)) { + if (descriptor) { + const { + set, + get, + value, + enumerable, + configurable = true, + writable = true, + } = descriptor; + Object.defineProperty(object, name, (get) + ? { get, set, configurable, enumerable } + : { value, configurable, enumerable, writable } + ); + } + } + for (const symbol of Object.getOwnPropertySymbols(descriptors)) { + const descriptor = descriptors[symbol]; + if (descriptor) { + Object.defineProperty(object, symbol, descriptor); + } + } +} + +function attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors) { + // create prototype for read-only objects + const prototypeRO = {}; + Object.setPrototypeOf(prototypeRO, constructor.prototype); + const instanceDescriptorsRO = {}; + const propSetters = {}; + for (const [ name, descriptor ] of Object.entries(instanceDescriptors)) { + if (descriptor?.set) { + instanceDescriptorsRO[name] = { ...descriptor, set: throwReadOnly$9 }; + // save the setters so we can initialize read-only objects + if (name !== '$') { + propSetters[name] = descriptor.set; + } + } else if (name === 'set') { + instanceDescriptorsRO[name] = { value: throwReadOnly$9, configurable: true, writable: true }; + } + } + const vivificate = instanceDescriptors[VIVIFICATOR$9]?.value; + const vivificateDescriptor = { + // vivificate child objects as read-only too + value: function(slot) { + return vivificate.call(this, slot, false); + } + }; + const { get, set } = instanceDescriptors.$; + defineProperties$9(constructor.prototype, { + [CONST$9]: { value: false }, + [ALL_KEYS$9]: { value: Object.keys(propSetters) }, + [SETTER$9]: { value: set }, + [GETTER$9]: { value: get }, + [PROP_SETTERS$9]: { value: propSetters }, + ...instanceDescriptors, + }); + defineProperties$9(constructor, { + [CONST_PROTOTYPE$9]: { value: prototypeRO }, + ...staticDescriptors, + }); + defineProperties$9(prototypeRO, { + constructor: { value: constructor, configurable: true }, + [CONST$9]: { value: true }, + [SETTER$9]: { value: throwReadOnly$9 }, + [VIVIFICATOR$9]: vivificate && vivificateDescriptor, + ...instanceDescriptorsRO, + }); + return constructor; +} + +function createConstructor$9(structure, handlers, env) { + const { + byteSize, + align, + instance: { members, template }, + hasPointer, + } = structure; + const { + modifier, + initializer, + finalizer, + alternateCaster, + shapeDefiner, + } = handlers; + const hasSlots = needSlots$9(members); + // comptime fields are stored in the instance template's slots + let comptimeFieldSlots; + if (template?.[SLOTS$9]) { + const comptimeMembers = members.filter(m => isReadOnly$9(m.type)); + if (comptimeMembers.length > 0) { + comptimeFieldSlots = comptimeMembers.map(m => m.slot); + } + } + const cache = new ObjectCache$9(); + const constructor = function(arg, options = {}) { + const { + writable = true, + fixed = false, + } = options; + const creating = this instanceof constructor; + let self, dv; + if (creating) { + if (arguments.length === 0) { + throwNoInitializer$9(structure); + } + self = this; + if (hasSlots) { + self[SLOTS$9] = {}; + } + if (shapeDefiner) { + // provided by defineSlice(); the slice is different from other structures as it does not have + // a fixed size; memory is allocated by the slice initializer based on the argument given + initializer.call(self, arg, fixed); + dv = self[MEMORY$9]; + } else { + self[MEMORY$9] = dv = env.allocateMemory(byteSize, align, fixed); + } + } else { + if (alternateCaster) { + // casting from number, string, etc. + self = alternateCaster.call(this, arg, options); + if (self !== false) { + return self; + } + } + // look for buffer + dv = requireDataView$9(structure, arg, env); + if (self = cache.find(dv, writable)) { + return self; + } + self = Object.create(writable ? constructor.prototype : constructor[CONST_PROTOTYPE$9]); + if (shapeDefiner) { + setDataView$9.call(self, dv, structure, false, { shapeDefiner }); + } else { + self[MEMORY$9] = dv; + } + if (hasSlots) { + self[SLOTS$9] = {}; + if (hasPointer && arg instanceof constructor) { + // copy pointer from other object + self[POINTER_VISITOR$9](copyPointer$9, { vivificate: true, source: arg }); + } + } + } + if (comptimeFieldSlots) { + for (const slot of comptimeFieldSlots) { + self[SLOTS$9][slot] = template[SLOTS$9][slot]; + } + } + if (modifier) { + modifier.call(self); + } + if (creating) { + // initialize object unless it's been done already + if (!shapeDefiner) { + initializer.call(self, arg); + } + if (!writable) { + // create object with read-only prototype + self = Object.assign(Object.create(constructor[CONST_PROTOTYPE$9]), self); + } + } + if (finalizer) { + self = finalizer.call(self); + } + return cache.save(dv, writable, self); + }; + return constructor; +} + +function createPropertyApplier$9(structure) { + const { instance: { template } } = structure; + return function(arg) { + const argKeys = Object.keys(arg); + const propSetters = this[PROP_SETTERS$9]; + const allKeys = this[ALL_KEYS$9]; + // don't accept unknown props + for (const key of argKeys) { + if (!(key in propSetters)) { + throwNoProperty$9(structure, key); + } + } + // checking each name so that we would see inenumerable initializers as well + let normalCount = 0; + let normalFound = 0; + let normalMissing = 0; + let specialFound = 0; + for (const key of allKeys) { + const set = propSetters[key]; + if (set.special) { + if (key in arg) { + specialFound++; + } + } else { + normalCount++; + if (key in arg) { + normalFound++; + } else if (set.required) { + normalMissing++; + } + } + } + if (normalMissing !== 0 && specialFound === 0) { + const missing = allKeys.filter(k => propSetters[k].required && !(k in arg)); + throwMissingInitializers$9(structure, missing); + } + if (specialFound + normalFound > argKeys.length) { + // some props aren't enumerable + for (const key of allKeys) { + if (key in arg) { + if (!argKeys.includes(key)) { + argKeys.push(key); + } + } + } + } + // apply default values unless all properties are initialized + if (normalFound < normalCount && specialFound === 0) { + if (template) { + if (template[MEMORY$9]) { + this[COPIER$9](template); + } + this[POINTER_VISITOR$9]?.(copyPointer$9, { vivificate: true, source: template }); + } + } + for (const key of argKeys) { + const set = propSetters[key]; + set.call(this, arg[key]); + } + return argKeys.length; + }; +} + +function needSlots$9(members) { + for (const { type } of members) { + switch (type) { + case MemberType$9.Object: + case MemberType$9.Comptime: + case MemberType$9.Type: + case MemberType$9.Literal: + return true; + } + } + return false; +} + +function getSelf$9() { + return this; +} + +function useAllStructureTypes$9() { + usePrimitive$9(); + useArray$9(); + useStruct$9(); + useExternStruct$9(); + usePackedStruct$9(); + useArgStruct$9(); + useExternUnion$9(); + useBareUnion$9(); + useTaggedUnion$9(); + useErrorUnion$9(); + useErrorSet$9(); + useEnumeration$9(); + useOptional$9(); + usePointer$9(); + useSlice$9(); + useVector$9(); + useOpaque$9(); +} + +let ObjectCache$9 = class ObjectCache { + [0] = null; + [1] = null; + + find(dv, writable) { + const key = (writable) ? 0 : 1; + const map = this[key]; + return map?.get(dv); + } + + save(dv, writable, object) { + const key = (writable) ? 0 : 1; + let map = this[key]; + if (!map) { + map = this[key] = new WeakMap(); + } + map.set(dv, object); + return object; + } +}; + +let currentGlobalSet$1; +let currentErrorClass$1; + +function defineErrorSet$9(structure, env) { + const { + name, + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + if (!currentErrorClass$1) { + currentErrorClass$1 = class ZigError extends ZigErrorBase$1 {}; + currentGlobalSet$1 = defineErrorSet$9({ ...structure, name: 'anyerror' }, env); + } + if (currentGlobalSet$1 && name === 'anyerror') { + structure.constructor = currentGlobalSet$1; + structure.typedArray = getTypedArrayClass$9(member); + return currentGlobalSet$1; + } + const errorClass = currentErrorClass$1; + const { get, set } = getDescriptor$9(member, env); + const expected = [ 'string', 'number' ]; + const propApplier = createPropertyApplier$9(structure); + const initializer = function(arg) { + if (arg instanceof constructor[CLASS$1]) { + set.call(this, arg); + } else if (arg && typeof(arg) === 'object' && !isErrorJSON$1(arg)) { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$9(structure, expected, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'number' || typeof(arg) === 'string') { + return constructor[arg]; + } else if (arg instanceof constructor[CLASS$1]) { + return constructor[Number(arg)]; + } else if (isErrorJSON$1(arg)) { + return constructor[`Error: ${arg.error}`]; + } else if (!getDataView$9(structure, arg, env)) { + throwInvalidInitializer$9(structure, expected, arg); + } else { + return false; + } + }; + // items are inserted when static members get attached in static.js + const constructor = structure.constructor = createConstructor$9(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass$9(member); + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$9(structure), + base64: getBase64Descriptor$9(structure), + typedArray: typedArray && getTypedArrayDescriptor$9(structure), + valueOf: { value: getValueOf$9 }, + toJSON: { value: convertToJSON$9 }, + delete: { value: getDestructor$9(env) }, + [COPIER$9]: { value: getMemoryCopier$9(byteSize) }, + [NORMALIZER$9]: { value: get }, + }; + const staticDescriptors = { + [ALIGN$9]: { value: align }, + [SIZE$9]: { value: byteSize }, + [CLASS$1]: { value: errorClass }, + // the PROPS array is normally set in static.js; it needs to be set here for anyerror + // so we can add names to it as error sets are defined + [PROPS$9]: (name === 'anyerror') ? { value: [] } : undefined, + }; + return attachDescriptors$9(constructor, instanceDescriptors, staticDescriptors); +} + +function isErrorJSON$1(arg) { + return typeof(arg) === 'object' && typeof(arg.error) === 'string' && Object.keys(arg).length === 1 ; +} + +let ZigErrorBase$1 = class ZigErrorBase extends Error { + constructor(name, number) { + super(deanimalizeErrorName$1(name)); + this.number = number; + } + + [Symbol.toPrimitive](hint) { + if (hint === 'string') { + return Error.prototype.toString.call(this, hint); + } else { + return this.number; + } + } + + toJSON() { + return { error: this.message }; + } +}; + +function throwNoInitializer$9(structure) { + const { name } = structure; + throw new TypeError(`An initializer must be provided to the constructor of ${name}, even when the intended value is undefined`); +} + +function throwBufferSizeMismatch$9(structure, dv, target = null) { + const { name, type, byteSize } = structure; + const actual = dv.byteLength; + const s = (byteSize !== 1) ? 's' : ''; + if (type === StructureType$9.Slice && !target) { + throw new TypeError(`${name} has elements that are ${byteSize} byte${s} in length, received ${actual}`); + } else { + const total = (type === StructureType$9.Slice) ? target.length * byteSize : byteSize; + throw new TypeError(`${name} has ${total} byte${s}, received ${actual}`); + } +} + +function throwBufferExpected$9(structure) { + const { type, byteSize, typedArray } = structure; + const s = (byteSize !== 1) ? 's' : ''; + const acceptable = [ 'ArrayBuffer', 'DataView' ].map(addArticle$9); + if (typedArray) { + acceptable.push(addArticle$9(typedArray.name)); + } + if (type === StructureType$9.Slice) { + throw new TypeError(`Expecting ${formatList$9(acceptable)} that can accommodate items ${byteSize} byte${s} in length`); + } else { + throw new TypeError(`Expecting ${formatList$9(acceptable)} that is ${byteSize} byte${s} in length`); + } +} + +function throwEnumExpected$9(structure, arg) { + const { name } = structure; + if (typeof(arg) === 'number' || typeof(arg) === 'bigint') { + throw new TypeError(`Value given does not correspond to an item of enum ${name}: ${arg}`); + } else { + throw new TypeError(`Enum item of the type ${name} expected, received ${arg}`); + } +} + +function throwErrorExpected$9(structure, arg) { + const { name } = structure; + const type = typeof(arg); + if (type === 'string' || type === 'number' || isErrorJSON$1(arg)) { + if (isErrorJSON$1(arg)) { + arg = `{ error: ${JSON.stringify(arg.error)} }`; + } + throw new TypeError(`Error ${type} does not corresponds to any error in error set ${name}: ${arg}`); + } else { + throw new TypeError(`Error of the type ${name} expected, received ${arg}`); + } +} + +function throwNotInErrorSet$9(structure) { + const { name } = structure; + throw new TypeError(`Error given is not a part of error set ${name}`); +} + +function throwMultipleUnionInitializers$9(structure) { + const { name } = structure; + throw new TypeError(`Only one property of ${name} can be given a value`); +} + +function throwInactiveUnionProperty$9(structure, name, currentName) { + throw new TypeError(`Accessing property ${name} when ${currentName} is active`); +} + +function throwMissingUnionInitializer$9(structure, arg, exclusion) { + const { name, instance: { members } } = structure; + const missing = members.slice(0, exclusion ? -1 : undefined).map(m => m.name); + throw new TypeError(`${name} needs an initializer for one of its union properties: ${missing.join(', ')}`); +} + +function throwInvalidInitializer$9(structure, expected, arg) { + const { name } = structure; + const acceptable = []; + if (Array.isArray(expected)) { + for (const type of expected) { + acceptable.push(addArticle$9(type)); + } + } else { + acceptable.push(addArticle$9(expected)); + } + const received = getDescription$9(arg); + throw new TypeError(`${name} expects ${formatList$9(acceptable)} as argument, received ${received}`); +} + +function throwInvalidArrayInitializer$9(structure, arg, shapeless = false) { + const { instance: { members: [ member ] }, type, typedArray } = structure; + const acceptable = []; + const primitive = getPrimitiveType$9(member); + if (primitive) { + let object; + switch (member.structure?.type) { + case StructureType$9.Enumeration: object = 'enum item'; break; + case StructureType$9.ErrorSet: object = 'error'; break; + default: object = primitive; + } + acceptable.push(`array of ${object}s`); + } else { + acceptable.push(`array of objects`); + } + if (typedArray) { + acceptable.push(typedArray.name); + } + if (type === StructureType$9.Slice && shapeless) { + acceptable.push(`length`); + } + throwInvalidInitializer$9(structure, acceptable.join(' or '), arg); +} + +function throwArrayLengthMismatch$9(structure, target, arg) { + const { name, length, instance: { members: [ member ] } } = structure; + const { structure: { constructor: elementConstructor} } = member; + const { length: argLength, constructor: argConstructor } = arg; + // get length from object whech it's a slice + const actualLength = target?.length ?? length; + const s = (actualLength !== 1) ? 's' : ''; + let received; + if (argConstructor === elementConstructor) { + received = `only a single one`; + } else if (argConstructor.child === elementConstructor) { + received = `a slice/array that has ${argLength}`; + } else { + received = `${argLength} initializer${argLength > 1 ? 's' : ''}`; + } + throw new TypeError(`${name} has ${actualLength} element${s}, received ${received}`); +} + +function throwMissingInitializers$9(structure, missing) { + const { name } = structure; + throw new TypeError(`Missing initializers for ${name}: ${missing.join(', ')}`); +} + +function throwNoProperty$9(structure, propName) { + const { name, instance: { members } } = structure; + const member = members.find(m => m.name === propName); + if (member) { + throw new TypeError(`Comptime value cannot be changed: ${propName}`); + } else { + throw new TypeError(`${name} does not have a property with that name: ${propName}`); + } +} + +function throwArgumentCountMismatch$9(structure, actual) { + const { name, instance: { members } } = structure; + const argCount = members.length - 1; + const s = (argCount !== 1) ? 's' : ''; + throw new Error(`${name} expects ${argCount} argument${s}, received ${actual}`); +} + +function rethrowArgumentError$9(structure, index, err) { + const { name, instance: { members } } = structure; + // Zig currently does not provide the argument name + const argName = `args[${index}]`; + const argCount = members.length - 1; + const prefix = (index !== 0) ? '..., ' : ''; + const suffix = (index !== argCount - 1) ? ', ...' : ''; + const argLabel = prefix + argName + suffix; + const newError = new err.constructor(`${name}(${argLabel}): ${err.message}`); + newError.stack = err.stack; + throw newError; +} + +function throwNoCastingToPointer$9(structure) { + throw new TypeError(`Non-slice pointers can only be created with the help of the new operator`); +} + +function throwConstantConstraint$9(structure, pointer) { + const { name: target } = structure; + const { constructor: { name } } = pointer; + throw new TypeError(`Conversion of ${name} to ${target} requires an explicit cast`); +} + +function throwMisplacedSentinel$9(structure, value, index, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}, found at ${index}`); +} + +function throwMissingSentinel$9(structure, value, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}`); +} + +function throwTypeMismatch$9(expected, arg) { + const received = getDescription$9(arg); + throw new TypeError(`Expected ${addArticle$9(expected)}, received ${received}`) +} + +function throwInaccessiblePointer$9() { + throw new TypeError(`Pointers within an untagged union are not accessible`); +} + +function throwNullPointer$9() { + throw new TypeError(`Null pointer`); +} + +function throwInvalidPointerTarget$9(structure, arg) { + const { name } = structure; + let target; + if (arg != null) { + const type = typeof(arg); + const noun = (type === 'object' && arg.constructor !== Object) ? `${arg.constructor.name} object`: type; + const a = article$9(noun); + target = `${a} ${noun}`; + } else { + target = arg + ''; + } + throw new TypeError(`${name} cannot point to ${target}`) +} + +function throwFixedMemoryTargetRequired$9(structure, arg) { + throw new TypeError(`Pointers in fixed memory cannot point to garbage-collected object`); +} + + +function throwOverflow$9(member, value) { + const typeName = getTypeName$9(member); + throw new TypeError(`${typeName} cannot represent the value given: ${value}`); +} + +function throwOutOfBound$9(member, index) { + const { name } = member; + throw new RangeError(`Index exceeds the size of ${name ?? 'array'}: ${index}`); +} + +function rethrowRangeError$9(member, index, err) { + if (err instanceof RangeError) { + throwOutOfBound$9(member, index); + } else { + throw err; + } +} + +function throwNotUndefined$9(member) { + const { name } = member; + throw new RangeError(`Property ${name} can only be undefined`); +} + +function throwNotOnByteBoundary$9(member) { + const { name, structure: { name: { struct }} } = member; + throw new TypeError(`Unable to create ${struct} as it is not situated on a byte boundary: ${name}`); +} + +function throwReadOnly$9() { + throw new TypeError(`Unable to modify read-only object`); +} + +function throwReadOnlyTarget$9(structure) { + const { name } = structure; + throw new TypeError(`${name} cannot point to a read-only object`); +} + +function throwAccessingOpaque$9(structure) { + const { name } = structure; + throw new TypeError(`Unable to access opaque structure ${name}`); +} + +function throwCreatingOpaque$9(structure) { + const { name } = structure; + throw new TypeError(`Unable to create instance of ${name}, as it is opaque`); +} + +function warnImplicitArrayCreation$9(structure, arg) { + const created = addArticle$9(structure.typedArray.name); + const source = addArticle$9(arg.constructor.name); + console.warn(`Implicitly creating ${created} from ${source}`); +} + +function deanimalizeErrorName$1(name) { + // deal with snake_case first + let s = name.replace(/_/g, ' '); + // then camelCase, using a try block in case Unicode regex fails + try { + s = s.replace(/(\p{Uppercase}+)(\p{Lowercase}*)/gu, (m0, m1, m2) => { + if (m1.length === 1) { + return ` ${m1.toLocaleLowerCase()}${m2}`; + } else { + if (m2) { + const acronym = m1.substring(0, m1.length - 1); + const letter = m1.charAt(m1.length - 1).toLocaleLowerCase(); + return ` ${acronym} ${letter}${m2}`; + } else { + return ` ${m1}`; + } + } + }).trimStart(); + /* c8 ignore next 2 */ + } catch (err) { + } + return s.charAt(0).toLocaleUpperCase() + s.substring(1); +} + +function getDescription$9(arg) { + const type = typeof(arg); + let s; + if (type === 'object') { + s = (arg) ? Object.prototype.toString.call(arg) : 'null'; + } else { + s = type; + } + return addArticle$9(s); +} + +function addArticle$9(noun) { + return `${article$9(noun)} ${noun}`; +} + +function article$9(noun) { + return /^\W*[aeiou]/i.test(noun) ? 'an' : 'a'; +} + +function formatList$9(list, conj = 'or') { + const sep = ` ${conj} `; + if (list.length > 2) { + return list.slice(0, -1).join(', ') + sep + list[list.length - 1]; + } else { + return list.join(sep); + } +} + +function getBoolAccessor$9(access, member) { + return cacheMethod$9(access, member, () => { + if (isByteAligned$9(member)) { + const { byteSize } = member; + const typeName = getTypeName$9({ type: MemberType$9.Int, bitSize: byteSize * 8 }); + if (access === 'get') { + const get = DataView.prototype[`get${typeName}`]; + return function(offset, littleEndian) { + return !!get.call(this, offset, littleEndian); + }; + } else { + const set = DataView.prototype[`set${typeName}`]; + const T = (byteSize > 4) ? 1n : 1; + const F = (byteSize > 4) ? 0n : 0; + return function(offset, value, littleEndian) { + set.call(this, offset, value ? T : F, littleEndian); + }; + } + } else { + return getExtendedTypeAccessor$9(access, member); + } + }); +} + +function getNumericAccessor$9(access, member) { + return cacheMethod$9(access, member, (name) => { + if (DataView.prototype[name]) { + return DataView.prototype[name]; + } else { + return getExtendedTypeAccessor$9(access, member); + } + }); +} + +const factories$s = {}; + +function useExtendedBool$9() { + factories$s[MemberType$9.Bool] = getExtendedBoolAccessor$9; +} + +function useExtendedInt$9() { + factories$s[MemberType$9.Int] = getExtendedIntAccessor$9; +} + +function useExtendedUint$9() { + factories$s[MemberType$9.Uint] = getExtendedUintAccessor$9; +} + +function useExtendedFloat$9() { + factories$s[MemberType$9.Float] = getExtendedFloatAccessor$9; +} + +function getExtendedTypeAccessor$9(access, member) { + const f = factories$s[member.type]; + return f(access, member); +} + +function getExtendedBoolAccessor$9(access, member) { + const { bitOffset } = member; + const bitPos = bitOffset & 0x07; + const mask = 1 << bitPos; + const get = DataView.prototype.getInt8; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + return !!(n & mask); + }; + } else { + const set = DataView.prototype.setInt8; + return function(offset, value) { + const n = get.call(this, offset); + const b = (value) ? n | mask : n & ~mask; + set.call(this, offset, b); + }; + } +} + +function getExtendedIntAccessor$9(access, member) { + if (isByteAligned$9(member)) { + return getAlignedIntAccessor$9(access, member) + } else { + return getUnalignedIntAccessor$9(access, member); + } +} + +function getExtendedUintAccessor$9(access, member) { + if (isByteAligned$9(member)) { + return getAlignedUintAccessor$9(access, member) + } else { + return getUnalignedUintAccessor$9(access, member); + } +} + +function getExtendedFloatAccessor$9(access, member) { + if (isByteAligned$9(member)) { + return getAlignedFloatAccessor$9(access, member) + } else { + return getUnalignedFloatAccessor$9(access, member); + } +} + +function getDataView$9(structure, arg, env) { + const { type, byteSize, typedArray } = structure; + let dv; + // not using instanceof just in case we're getting objects created in other contexts + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView') { + dv = arg; + } else if (tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + dv = env.obtainView(arg, 0, arg.byteLength); + } else if (typedArray && tag === typedArray.name || (tag === 'Uint8ClampedArray' && typedArray === Uint8Array)) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else if (tag === 'Uint8Array' && typeof(Buffer) === 'function' && arg instanceof Buffer) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else { + const memory = arg?.[MEMORY$9]; + if (memory) { + const { constructor, instance: { members: [ member ] } } = structure; + if (arg instanceof constructor) { + return memory; + } else if (type === StructureType$9.Array || type === StructureType$9.Slice || type === StructureType$9.Vector) { + const { byteSize: elementSize, structure: { constructor: Child } } = member; + const number = findElements$9(arg, Child); + if (number !== undefined) { + if (type === StructureType$9.Slice || number * elementSize === byteSize) { + return memory; + } else { + throwArrayLengthMismatch$9(structure, null, arg); + } + } + } + } + } + if (dv && byteSize !== undefined) { + checkDataViewSize$9(dv, structure); + } + return dv; +} + +function checkDataView$9(dv) { + if (dv?.[Symbol.toStringTag] !== 'DataView') { + throwTypeMismatch$9('a DataView', dv); + } + return dv; +} + +function checkDataViewSize$9(dv, structure) { + const { byteSize, type } = structure; + const multiple = type === StructureType$9.Slice; + if (multiple ? dv.byteLength % byteSize !== 0 : dv.byteLength !== byteSize) { + throwBufferSizeMismatch$9(structure, dv); + } +} + +function setDataView$9(dv, structure, copy, handlers) { + const { byteSize, type, sentinel } = structure; + const multiple = type === StructureType$9.Slice; + if (!this[MEMORY$9]) { + const { shapeDefiner } = handlers; + checkDataViewSize$9(dv, structure); + const len = dv.byteLength / byteSize; + const source = { [MEMORY$9]: dv }; + sentinel?.validateData(source, len); + shapeDefiner.call(this, copy ? null : dv, len); + if (copy) { + this[COPIER$9](source); + } + } else { + const byteLength = multiple ? byteSize * this.length : byteSize; + if (dv.byteLength !== byteLength) { + throwBufferSizeMismatch$9(structure, dv, this); + } + const source = { [MEMORY$9]: dv }; + sentinel?.validateData(source, this.length); + this[COPIER$9](source); + } +} + +function findElements$9(arg, Child) { + // casting to a array/slice + const { constructor: Arg } = arg; + if (Arg === Child) { + // matching object + return 1; + } else if (Arg.child === Child) { + // matching slice/array + return arg.length; + } +} + +function requireDataView$9(structure, arg, env) { + const dv = getDataView$9(structure, arg, env); + if (!dv) { + throwBufferExpected$9(structure); + } + return dv; +} + +function getTypedArrayClass$9(member) { + const { type: memberType, byteSize } = member; + if (memberType === MemberType$9.Int) { + switch (byteSize) { + case 1: return Int8Array; + case 2: return Int16Array; + case 4: return Int32Array; + case 8: return BigInt64Array; + } + } else if (memberType === MemberType$9.Uint) { + switch (byteSize) { + case 1: return Uint8Array; + case 2: return Uint16Array; + case 4: return Uint32Array; + case 8: return BigUint64Array; + } + } else if (memberType === MemberType$9.Float) { + switch (byteSize) { + case 4: return Float32Array; + case 8: return Float64Array; + } + } else if (memberType === MemberType$9.Object) { + return member.structure.typedArray; + } + return null; +} + +function isTypedArray$9(arg, TypedArray) { + const tag = arg?.[Symbol.toStringTag]; + return (!!TypedArray && tag === TypedArray.name); +} + +function isCompatible$9(arg, constructor) { + const tags = constructor[COMPAT$9]; + if (tags) { + const tag = arg?.[Symbol.toStringTag]; + if (tags.includes(tag)) { + return true; + } + } + if (constructor.child) { + if (findElements$9(arg, constructor.child) !== undefined) { + return true; + } + } + return false; +} + +function getCompatibleTags$9(structure) { + const { typedArray } = structure; + const tags = []; + if (typedArray) { + tags.push(typedArray.name); + tags.push('DataView'); + if (typedArray === Uint8Array || typedArray === Int8Array) { + tags.push('Uint8ClampedArray'); + tags.push('ArrayBuffer'); + tags.push('SharedArrayBuffer'); + } + } + return tags; +} + +function isBuffer$9(arg, typedArray) { + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView' || tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + return true; + } else if (typedArray && tag === typedArray.name) { + return true; + } else { + return false; + } +} + +function getTypeName$9(member) { + const { type, bitSize, byteSize } = member; + if (type === MemberType$9.Int) { + return `${bitSize <= 32 ? '' : 'Big' }Int${bitSize}`; + } else if (type === MemberType$9.Uint) { + return `${bitSize <= 32 ? '' : 'Big' }Uint${bitSize}`; + } else if (type === MemberType$9.Float) { + return `Float${bitSize}`; + } else if (type === MemberType$9.Bool) { + const boolSize = (byteSize !== undefined) ? byteSize * 8 : 1; + return `Bool${boolSize}`; + } else if (type === MemberType$9.Void) { + return `Null`; + } +} + +function getBigIntDescriptor$9(bitSize) { + const getWord = DataView.prototype.getBigUint64; + const setWord = DataView.prototype.setBigUint64; + const wordCount = Math.ceil(bitSize / 64); + return { + get: function(offset, littleEndian) { + let n = 0n; + if (littleEndian) { + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; + } + } else { + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; + } + } + return n; + }, + set: function(offset, value, littleEndian) { + let n = value; + const mask = 0xFFFFFFFFFFFFFFFFn; + if (littleEndian) { + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } + } else { + n <<= BigInt(wordCount * 64 - bitSize); + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } + } + return n; + }, + }; +} + +function getAlignedIntAccessor$9(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$9({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const signMask = (bitSize <= 32) ? 2 ** (bitSize - 1) : 2n ** BigInt(bitSize - 1); + const valueMask = (bitSize <= 32) ? signMask - 1 : signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$9(bitSize); + const signMask = 2n ** BigInt(bitSize - 1); + const valueMask = signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } + } +} + +function getAlignedUintAccessor$9(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$9({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const valueMask = (bitSize <= 32) ? (2 ** bitSize) - 1 : (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$9(bitSize); + const valueMask = (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } + } +} + +function getUnalignedIntAccessor$9(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + // sub-8-bit numbers have real use cases + const signMask = 2 ** (bitSize - 1); + const valueMask = signMask - 1; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return (s & valueMask) - (s & signMask); + }; + } else { + const outsideMask = 0xFF ^ ((valueMask | signMask) << bitPos); + return function(offset, value) { + let b = get.call(this, offset); + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + b = (b & outsideMask) | (n << bitPos); + set.call(this, offset, b); + }; + } + } + return getUnalignedNumericAccessor$9(access, member); +} + +function getUnalignedUintAccessor$9(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + const valueMask = (2 ** bitSize - 1); + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return s & valueMask; + }; + } else { + const outsideMask = 0xFF ^ (valueMask << bitPos); + return function(offset, value) { + const n = get.call(this, offset); + const b = (n & outsideMask) | ((value & valueMask) << bitPos); + set.call(this, offset, b); + }; + } + } + return getUnalignedNumericAccessor$9(access, member); +} + +function getAlignedFloatAccessor$9(access, member) { + const { bitSize, byteSize } = member; + if (bitSize === 16) { + const buf = new DataView(new ArrayBuffer(4)); + const set = DataView.prototype.setUint16; + const get = DataView.prototype.getUint16; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >>> 15; + const exp = (n & 0x7C00) >> 10; + const frac = n & 0x03FF; + if (exp === 0) { + return (sign) ? -0 : 0; + } else if (exp === 0x1F) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } + } + const n32 = (sign << 31) | ((exp - 15 + 127) << 23) | (frac << 13); + buf.setUint32(0, n32, littleEndian); + return buf.getFloat32(0, littleEndian); + } + } else { + return function(offset, value, littleEndian) { + buf.setFloat32(0, value, littleEndian); + const n = buf.getUint32(0, littleEndian); + const sign = n >>> 31; + const exp = (n & 0x7F800000) >> 23; + const frac = n & 0x007FFFFF; + const exp16 = (exp - 127 + 15); + let n16; + if (exp === 0) { + n16 = sign << 15; + } else if (exp === 0xFF) { + n16 = sign << 15 | 0x1F << 10 | (frac ? 1 : 0); + } else if (exp16 >= 31) { + n16 = sign << 15 | 0x1F << 10; + } else { + n16 = sign << 15 | exp16 << 10 | (frac >> 13); + } + set.call(this, offset, n16, littleEndian); + } + } + } else if (bitSize === 80) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + return w1 | w2 << 32n | w3 << 64n; + }; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 79n; + const exp = (n & 0x7FFF0000000000000000n) >> 64n; + const frac = n & 0x00007FFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } + } + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; + } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 11n) + BigInt((frac & (2n**11n - 1n)) >= 2n**10n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); + } + } else { + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n80; + if (exp === 0n) { + n80 = sign << 79n | (frac << 11n); + } else if (exp === 0x07FFn) { + n80 = sign << 79n | 0x7FFFn << 64n | (frac ? 0x00002000000000000000n : 0n) | 0x00008000000000000000n; + // ^ bit 61 ^ bit 63 + } else { + n80 = sign << 79n | (exp - 1023n + 16383n) << 64n | (frac << 11n) | 0x00008000000000000000n; + } + set.call(this, offset, n80, littleEndian); + } + } + } else if (bitSize === 128) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + const w4 = BigInt(this.getUint32(offset + (littleEndian ? 12 : byteSize - 16), littleEndian)); + return w1 | w2 << 32n | w3 << 64n | w4 << 96n; + }; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + const w4 = (value >> 96n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + this.setUint32(offset + (littleEndian ? 12 : byteSize - 16), Number(w4), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 127n; + const exp = (n & 0x7FFF0000000000000000000000000000n) >> 112n; + const frac = n & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } + } + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; + } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 60n) + BigInt((frac & (2n**60n - 1n)) >= 2n**59n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); + } + } else { + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n128; + if (exp === 0n) { + n128 = sign << 127n | (frac << 60n); + } else if (exp === 0x07FFn) { + n128 = sign << 127n | 0x7FFFn << 112n | (frac ? 1n : 0n); + } else { + n128 = sign << 127n | (exp - 1023n + 16383n) << 112n | (frac << 60n); + } + set.call(this, offset, n128, littleEndian); + } + } + } +} + +function getUnalignedFloatAccessor$9(access, member) { + return getUnalignedNumericAccessor$9(access, member); +} + +function getUnalignedNumericAccessor$9(access, member) { + // pathological usage scenario--handle it anyway by copying the bitSize into a + // temporary buffer, bit-aligning the data + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + const byteSize = [ 1, 2, 4, 8 ].find(b => b * 8 >= bitSize) ?? Math.ceil(bitSize / 64) * 64; + const buf = new DataView(new ArrayBuffer(byteSize)); + if (access === 'get') { + const getAligned = getNumericAccessor$9('get', { ...member, byteSize }); + const copyBits = getBitAlignFunction$9(bitPos, bitSize, true); + return function(offset, littleEndian) { + copyBits(buf, this, offset); + return getAligned.call(buf, 0, littleEndian); + }; + } else { + const setAligned = getNumericAccessor$9('set', { ...member, byteSize }); + const applyBits = getBitAlignFunction$9(bitPos, bitSize, false); + return function(offset, value, littleEndian) { + setAligned.call(buf, 0, value, littleEndian); + applyBits(this, buf, offset); + }; + } +} + +const methodCache$9 = {}; + +function cacheMethod$9(access, member, cb) { + const { type, bitOffset, bitSize, structure } = member; + const bitPos = bitOffset & 0x07; + const typeName = getTypeName$9(member); + const suffix = isByteAligned$9(member) ? `` : `Bit${bitPos}`; + const isInt = type === MemberType$9.Int || type === MemberType$9.Uint; + let name = `${access}${typeName}${suffix}`; + let isSize = false, originalName = name; + if (isInt && bitSize === 64) { + const zigTypeName = structure?.name; + if (zigTypeName === 'usize' || zigTypeName === 'isize') { + name += 'Size'; + isSize = true; + } + } + let fn = methodCache$9[name]; + if (!fn) { + if (isInt && access === 'set') { + // add auto-conversion between number and bigint + const Primitive = getPrimitiveClass$9(member); + const set = cb(originalName); + fn = function(offset, value, littleEndian) { + set.call(this, offset, Primitive(value), littleEndian); + }; + } else if (isSize && access === 'get') { + // use number instead of bigint where possible + const get = cb(originalName); + const min = BigInt(Number.MIN_SAFE_INTEGER); + const max = BigInt(Number.MAX_SAFE_INTEGER); + fn = function(offset, littleEndian) { + const value = get.call(this, offset, littleEndian); + if (min <= value && value <= max) { + return Number(value); + } else { + return value; + } + }; + } else { + fn = cb(name); + } + if (fn && fn.name !== name) { + Object.defineProperty(fn, 'name', { value: name, configurable: true, writable: false }); + } + methodCache$9[name] = fn; + } + return fn; +} + +function useAllExtendedTypes$9() { + useExtendedBool$9(); + useExtendedInt$9(); + useExtendedUint$9(); + useExtendedFloat$9(); +} + +const MemberType$9 = { + Void: 0, + Bool: 1, + Int: 2, + Uint: 3, + Float: 4, + Object: 5, + Type: 6, + Comptime: 7, + Static: 8, + Literal: 9, + Null: 10, + Undefined: 11, +}; + +function isReadOnly$9(type) { + switch (type) { + case MemberType$9.Type: + case MemberType$9.Comptime: + case MemberType$9.Literal: + return true; + default: + return false; + } +} + +const factories$r = {}; + +function useVoid$9() { + factories$r[MemberType$9.Void] = getVoidDescriptor$9; +} + +function useBool$9() { + factories$r[MemberType$9.Bool] = getBoolDescriptor$9; +} + +function useInt$9() { + factories$r[MemberType$9.Int] = getIntDescriptor$9; +} + +function useUint$9() { + factories$r[MemberType$9.Uint] = getUintDescriptor$9; +} + +function useFloat$9() { + factories$r[MemberType$9.Float] = getFloatDescriptor$9; +} + +function useObject$9() { + factories$r[MemberType$9.Object] = getObjectDescriptor$9; +} + +function useType$9() { + factories$r[MemberType$9.Type] = getTypeDescriptor$9; +} + +function useComptime$9() { + factories$r[MemberType$9.Comptime] = getComptimeDescriptor$9; +} + +function useStatic$9() { + factories$r[MemberType$9.Static] = getStaticDescriptor$9; +} + +function useLiteral$9() { + factories$r[MemberType$9.Literal] = getLiteralDescriptor$9; +} + +function useNull$9() { + factories$r[MemberType$9.Null] = getNullDescriptor$9; +} + +function useUndefined$9() { + factories$r[MemberType$9.Undefined] = getUndefinedDescriptor$9; +} + +const transformers$1 = {}; + +function useEnumerationTransform$1() { + transformers$1[StructureType$9.Enumeration] = transformEnumerationDescriptor$1; +} + +function useErrorSetTransform$1() { + transformers$1[StructureType$9.ErrorSet] = transformErrorSetDescriptor$1; +} + +function isByteAligned$9({ bitOffset, bitSize, byteSize }) { + return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; +} + +function getDescriptor$9(member, env) { + const f = factories$r[member.type]; + return f(member, env); +} + +function transformDescriptor$1(descriptor, member) { + const { structure } = member; + const t = transformers$1[structure?.type]; + return (t) ? t(descriptor, structure) : descriptor; +} + +function getVoidDescriptor$9(member, env) { + const { runtimeSafety } = env; + return { + get: function() { + return undefined; + }, + set: (runtimeSafety) + ? function(value) { + if (value !== undefined) { + throwNotUndefined$9(member); + } + } + : function() {}, + } +} + +function getNullDescriptor$9(member, env) { + return { + get: function() { + return null; + }, + } +} + +function getUndefinedDescriptor$9(member, env) { + return { + get: function() { + return undefined; + }, + } +} + +function getBoolDescriptor$9(member, env) { + return getDescriptorUsing$9(member, env, getBoolAccessor$9) +} + +function getIntDescriptor$9(member, env) { + const getDataViewAccessor = addRuntimeCheck$9(env, getNumericAccessor$9); + const descriptor = getDescriptorUsing$9(member, env, getDataViewAccessor); + return transformDescriptor$1(descriptor, member); +} + +function getUintDescriptor$9(member, env) { + const getDataViewAccessor = addRuntimeCheck$9(env, getNumericAccessor$9); + const descriptor = getDescriptorUsing$9(member, env, getDataViewAccessor); + return transformDescriptor$1(descriptor, member); +} + +function addRuntimeCheck$9(env, getDataViewAccessor) { + return function (access, member) { + const { + runtimeSafety = true, + } = env; + const accessor = getDataViewAccessor(access, member); + if (runtimeSafety && access === 'set') { + const { min, max } = getIntRange$9(member); + return function(offset, value, littleEndian) { + if (value < min || value > max) { + throwOverflow$9(member, value); + } + accessor.call(this, offset, value, littleEndian); + }; + } + return accessor; + }; +} + +function getFloatDescriptor$9(member, env) { + return getDescriptorUsing$9(member, env, getNumericAccessor$9) +} + +function transformEnumerationDescriptor$1(int, structure) { + const findEnum = function(value) { + const { constructor } = structure; + // the enumeration constructor returns the object for the int value + const item = constructor(value); + if (!item) { + throwEnumExpected$9(structure, value); + } + return item + }; + return { + get: (int.get.length === 0) + ? function getEnum(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } + return findEnum(value); + } + : function getEnumElement(index) { + const value = int.get.call(this, index); + return findEnum(value); + }, + set: (int.set.length === 1) + ? function setEnum(value, hint) { + if (hint !== 'number') { + const item = findEnum(value); + // call Symbol.toPrimitive directly as enum can be bigint or number + value = item[Symbol.toPrimitive](); + } + int.set.call(this, value); + } + : function setEnumElement(index, value) { + const item = findEnum(value); + int.set.call(this, index, item[Symbol.toPrimitive]()); + }, + }; +} + +function transformErrorSetDescriptor$1(int, structure) { + const findError = function(value) { + const { constructor } = structure; + const item = constructor(value); + if (!item) { + if (value instanceof Error) { + throwNotInErrorSet$9(structure); + } else { + throwErrorExpected$9(structure, value); + } + } + return item + }; + return { + get: (int.get.length === 0) + ? function getError(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } + return findError(value); + } + : function getErrorElement(index) { + const value = int.get.call(this, index); + return findError(value); + }, + set: (int.set.length === 1) + ? function setError(value, hint) { + if (hint !== 'number') { + const item = findError(value); + value = Number(item); + } + int.set.call(this, value); + } + : function setError(index, value) { + const item = findError(value); + value = Number(item); + int.set.call(this, index, value); + }, + }; +} + +function isValueExpected$9(structure) { + switch (structure.type) { + case StructureType$9.Primitive: + case StructureType$9.ErrorUnion: + case StructureType$9.Optional: + case StructureType$9.Enumeration: + case StructureType$9.ErrorSet: + return true; + default: + return false; + } +} + +function getValue$9(slot) { + const object = this[SLOTS$9][slot] ?? this[VIVIFICATOR$9](slot); + return object[GETTER$9](); +} + +function getObject$9(slot) { + const object = this[SLOTS$9][slot] ?? this[VIVIFICATOR$9](slot); + return object; +} + +function setValue$9(slot, value) { + const object = this[SLOTS$9][slot] ?? this[VIVIFICATOR$9](slot); + object[SETTER$9](value); +} + +function bindSlot$9(slot, { get, set }) { + if (slot !== undefined) { + return { + get: function() { + return get.call(this, slot); + }, + set: (set) + ? function(arg) { + return set.call(this, slot, arg); + } + : undefined, + }; + } else { + // array accessors + return { get, set }; + } +} + +function getObjectDescriptor$9(member, env) { + const { structure, slot } = member; + return bindSlot$9(slot, { + get: isValueExpected$9(structure) ? getValue$9 : getObject$9, + set: setValue$9, + }); +} + +function getType$9(slot) { + // unsupported types will have undefined structure + const structure = this[SLOTS$9][slot]; + return structure?.constructor; +} + +function getTypeDescriptor$9(member, env) { + const { slot } = member; + return bindSlot$9(slot, { get: getType$9 }); +} + +function getComptimeDescriptor$9(member, env) { + const { slot, structure } = member; + return bindSlot$9(slot, { + get: isValueExpected$9(structure) ? getValue$9 : getObject$9, + }); +} + +function getStaticDescriptor$9(member, env) { + const { slot, structure } = member; + return bindSlot$9(slot, { + get: isValueExpected$9(structure) ? getValue$9 : getObject$9, + set: setValue$9, + }); +} + +function getLiteral$9(slot) { + const object = this[SLOTS$9][slot]; + return object.string; +} + +function getLiteralDescriptor$9(member, env) { + const { slot } = member; + return bindSlot$9(slot, { get: getLiteral$9 }); +} + +function getDescriptorUsing$9(member, env, getDataViewAccessor) { + const { + littleEndian = true, + } = env; + const { bitOffset, byteSize } = member; + const getter = getDataViewAccessor('get', member); + const setter = getDataViewAccessor('set', member); + if (bitOffset !== undefined) { + const offset = bitOffset >> 3; + return { + get: function getValue() { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return getter.call(this[MEMORY$9], offset, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$9.call(this)) { + return getter.call(this[MEMORY$9], offset, littleEndian); + } else { + throw err; + } + } + /* WASM-ONLY-END*/ + }, + set: function setValue(value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return setter.call(this[MEMORY$9], offset, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$9.call(this)) { + return setter.call(this[MEMORY$9], offset, value, littleEndian); + } else { + throw err; + } + } + /* WASM-ONLY-END*/ + } + } + } else { + return { + get: function getElement(index) { + try { + return getter.call(this[MEMORY$9], index * byteSize, littleEndian); + } catch (err) { + /* WASM-ONLY */ + if (err instanceof TypeError && restoreMemory$9.call(this)) { + return getter.call(this[MEMORY$9], index * byteSize, littleEndian); + } else { + /* WASM-ONLY-END */ + rethrowRangeError$9(member, index, err); + /* WASM-ONLY */ + } + /* WASM-ONLY-END */ + } + }, + set: function setElement(index, value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END */ + return setter.call(this[MEMORY$9], index * byteSize, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$9.call(this)) { + return setter.call(this[MEMORY$9], index * byteSize, value, littleEndian); + } else { + rethrowRangeError$9(member, index, err); + } + } + /* WASM-ONLY-END */ + }, + } + } +} + +function useAllMemberTypes$9() { + useVoid$9(); + useNull$9(); + useUndefined$9(); + useBool$9(); + useInt$9(); + useUint$9(); + useFloat$9(); + useObject$9(); + useType$9(); + useComptime$9(); + useStatic$9(); + useLiteral$9(); +} + +process.cwd(); + +useAllMemberTypes$9(); +useAllStructureTypes$9(); +useAllExtendedTypes$9(); + +const MEMORY$8 = Symbol('memory'); +const SLOTS$8 = Symbol('slots'); +const PARENT$8 = Symbol('parent'); +const NAME$8 = Symbol('name'); +const CLASS = Symbol('class'); +const TAG$8 = Symbol('tag'); +const PROPS$8 = Symbol('props'); +const GETTER$8 = Symbol('getter'); +const SETTER$8 = Symbol('setter'); +const ELEMENT_GETTER$8 = Symbol('elementGetter'); +const ELEMENT_SETTER$8 = Symbol('elementSetter'); +const LOCATION_GETTER$8 = Symbol('addressGetter'); +const LOCATION_SETTER$8 = Symbol('addressSetter'); +const TARGET_GETTER$8 = Symbol('targetGetter'); +const TARGET_SETTER$8 = Symbol('targetSetter'); +const FIXED_LOCATION$8 = Symbol('fixedLocation'); +const PROP_GETTERS$8 = Symbol('propGetters'); +const PROP_SETTERS$8 = Symbol('propSetters'); +const ALL_KEYS$8 = Symbol('allKeys'); +const LENGTH$8 = Symbol('length'); +const PROXY$8 = Symbol('proxy'); +const COMPAT$8 = Symbol('compat'); +const SIZE$8 = Symbol('size'); +const ALIGN$8 = Symbol('align'); +const ARRAY$8 = Symbol('array'); +const POINTER$8 = Symbol('pointer'); +const CONST$8 = Symbol('const'); +const CONST_PROTOTYPE$8 = Symbol('constProto'); +const COPIER$8 = Symbol('copier'); +const RESETTER$8 = Symbol('resetter'); +const NORMALIZER$8 = Symbol('normalizer'); +const VIVIFICATOR$8 = Symbol('vivificator'); +const POINTER_VISITOR$8 = Symbol('pointerVisitor'); +const ENVIRONMENT$8 = Symbol('environment'); +const MORE$8 = Symbol('more'); + +function getDestructor$8(env) { + return function() { + const dv = this[MEMORY$8]; + this[MEMORY$8] = null; + if (this[SLOTS$8]) { + this[SLOTS$8] = {}; + } + env.releaseFixedView(dv); + }; +} + +function getBitAlignFunction$8(bitPos, bitSize, toAligned) { + if (bitPos + bitSize <= 8) { + const mask = (2 ** bitSize) - 1; + if (toAligned) { + // from single byte + return function(dest, src, offset) { + const n = src.getUint8(offset); + const b = (n >> bitPos) & mask; + dest.setUint8(0, b); + }; + } else { + // to single byte + const destMask = 0xFF ^ (mask << bitPos); + return function(dest, src, offset) { + const n = src.getUint8(0); + const d = dest.getUint8(offset); + const b = (d & destMask) | ((n & mask) << bitPos); + dest.setUint8(offset, b); + }; + } + } else { + const leadBits = 8 - bitPos; + const leadMask = (2 ** leadBits) - 1; + if (toAligned) { + const trailBits = bitSize % 8; + const trailMask = (2 ** trailBits) - 1; + return function(dest, src, offset) { + let i = offset, j = 0; + let n = src.getUint8(i++), b; + let bitBuf = (n >> bitPos) & leadMask; + let bitCount = leadBits; + let remaining = bitSize; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + //bitCount += 8; + } + b = (remaining >= 8) ? bitBuf & 0xFF : bitBuf & trailMask; + dest.setUint8(j++, b); + bitBuf >>= 8; + //bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } else { + const trailBits = (bitSize - leadBits) % 8; + const trailMask = (2 ** trailBits) - 1; + const destMask1 = 0xFF ^ (leadMask << bitPos); + const destMask2 = 0xFF ^ trailMask; + return function(dest, src, offset) { + let i = 0, j = offset; + // preserve bits ahead of bitPos + let d = dest.getUint8(j), n, b; + let bitBuf = d & destMask1; + let bitCount = bitPos; + let remaining = bitSize + bitCount; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + bitCount += 8; + } + if (remaining >= 8) { + b = bitBuf & 0xFF; + } else { + // preserve bits at the destination sitting behind the trailing bits + d = dest.getUint8(j); + b = (d & destMask2) | (bitBuf & trailMask); + } + dest.setUint8(j++, b); + bitBuf >>= 8; + bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } + } +} + +function getMemoryCopier$8(size, multiple = false) { + const copy = getCopyFunction$8(size, multiple); + return function(target) { + /* WASM-ONLY */ + restoreMemory$8.call(this); + restoreMemory$8.call(target); + /* WASM-ONLY-END */ + const src = target[MEMORY$8]; + const dest = this[MEMORY$8]; + copy(dest, src); + }; +} + +function getCopyFunction$8(size, multiple = false) { + if (!multiple) { + const copier = copiers$8[size]; + if (copier) { + return copier; + } + } + if (!(size & 0x07)) return copy8x$8; + if (!(size & 0x03)) return copy4x$8; + if (!(size & 0x01)) return copy2x$8; + return copy1x$8; +} + +const copiers$8 = { + 1: copy1$8, + 2: copy2$8, + 4: copy4$8, + 8: copy8$8, + 16: copy16$8, + 32: copy32$8, +}; + +function copy1x$8(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i++) { + dest.setInt8(i, src.getInt8(i)); + } +} + +function copy2x$8(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 2) { + dest.setInt16(i, src.getInt16(i, true), true); + } +} + +function copy4x$8(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 4) { + dest.setInt32(i, src.getInt32(i, true), true); + } +} + +function copy8x$8(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 8) { + dest.setInt32(i, src.getInt32(i, true), true); + dest.setInt32(i + 4, src.getInt32(i + 4, true), true); + } +} + +function copy1$8(dest, src) { + dest.setInt8(0, src.getInt8(0)); +} + +function copy2$8(dest, src) { + dest.setInt16(0, src.getInt16(0, true), true); +} + +function copy4$8(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); +} + +function copy8$8(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); +} + +function copy16$8(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); +} + +function copy32$8(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); + dest.setInt32(16, src.getInt32(16, true), true); + dest.setInt32(20, src.getInt32(20, true), true); + dest.setInt32(24, src.getInt32(24, true), true); + dest.setInt32(28, src.getInt32(28, true), true); +} + +function getMemoryResetter$8(offset, size) { + const reset = getResetFunction$8(size); + return function() { + /* WASM-ONLY */ + restoreMemory$8.call(this); + /* WASM-ONLY-END */ + const dest = this[MEMORY$8]; + reset(dest, offset, size); + }; +} + +function getResetFunction$8(size) { + const resetter = resetters$8[size]; + if (resetter) { + return resetter; + } + if (!(size & 0x07)) return reset8x$8; + if (!(size & 0x03)) return reset4x$8; + if (!(size & 0x01)) return reset2x$8; + return reset1x$8; +} + +const resetters$8 = { + 1: reset1$8, + 2: reset2$8, + 4: reset4$8, + 8: reset8$8, + 16: reset16$8, + 32: reset32$8, +}; + +function reset1x$8(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i++) { + dest.setInt8(i, 0); + } +} + +function reset2x$8(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 2) { + dest.setInt16(i, 0, true); + } +} + +function reset4x$8(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 4) { + dest.setInt32(i, 0, true); + } +} + +function reset8x$8(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 8) { + dest.setInt32(i, 0, true); + dest.setInt32(i + 4, 0, true); + } +} + +function reset1$8(dest, offset) { + dest.setInt8(offset, 0); +} + +function reset2$8(dest, offset) { + dest.setInt16(offset, 0, true); +} + +function reset4$8(dest, offset) { + dest.setInt32(offset, 0, true); +} + +function reset8$8(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); +} + +function reset16$8(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); +} + +function reset32$8(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); + dest.setInt32(offset + 16, 0, true); + dest.setInt32(offset + 20, 0, true); + dest.setInt32(offset + 24, 0, true); + dest.setInt32(offset + 28, 0, true); +} + +function restoreMemory$8() { + const dv = this[MEMORY$8]; + const source = dv[MEMORY$8]; + if (!source || dv.buffer.byteLength !== 0) { + return false; + } + const { memory, address, len } = source; + const newDV = new DataView(memory.buffer, address, len); + newDV[MEMORY$8] = source; + this[MEMORY$8] = newDV; + return true; +} + +const decoders$8 = {}; +const encoders$8 = {}; + +function decodeText$8(arrays, encoding = 'utf-8') { + let decoder = decoders$8[encoding]; + if (!decoder) { + decoder = decoders$8[encoding] = new TextDecoder(encoding); + } + let array; + if (Array.isArray(arrays)) { + if (arrays.length === 1) { + array = arrays[0]; + } else { + let len = 0; + for (const a of arrays) { + len += a.length; + } + const { constructor } = arrays[0]; + array = new constructor(len); + let offset = 0; + for (const a of arrays) { + array.set(a, offset); + offset += a.length; + } + } + } else { + array = arrays; + } + return decoder.decode(array); +} + +function encodeText$8(text, encoding = 'utf-8') { + switch (encoding) { + case 'utf-16': { + const { length } = text; + const ta = new Uint16Array(length); + for (let i = 0; i < length; i++) { + ta[i] = text.charCodeAt(i); + } + return ta; + } + default: { + let encoder = encoders$8[encoding]; + if (!encoder) { + encoder = encoders$8[encoding] = new TextEncoder(); + } + return encoder.encode(text); + } + } +} + +function encodeBase64$8(dv) { + const ta = new Uint8Array(dv.buffer, dv.byteOffset, dv.byteLength); + const bstr = String.fromCharCode.apply(null, ta); + return btoa(bstr); +} + +function decodeBase64$8(str) { + const bstr = atob(str); + const ta = new Uint8Array(bstr.length); + for (let i = 0; i < ta.byteLength; i++) { + ta[i] = bstr.charCodeAt(i); + } + return new DataView(ta.buffer); +} + +function getValueOf$8() { + const map = new Map(); + const options = { error: 'throw' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$8]; + if (normalizer) { + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + map.set(value, result); + } + return result; + } else { + return value; + } + }; + return process(this); +} + +const INT_MAX$8 = BigInt(Number.MAX_SAFE_INTEGER); +const INT_MIN$8 = BigInt(Number.MIN_SAFE_INTEGER); + +function convertToJSON$8() { + const map = new Map(); + const options = { error: 'return' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$8]; + if (normalizer) { + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + if (typeof(result?.toJSON) === 'function') { + result = result.toJSON(); + } + map.set(value, result); + } + return result; + } else { + if (typeof(value) === 'bigint' && INT_MIN$8 <= value && value <= INT_MAX$8) { + return Number(value); + } + return value; + } + }; + return process(this); +} + +function normalizeValue$8(cb, options) { + const value = handleError$8(() => this.$, options); + return cb(value); +} + +function handleError$8(cb, options = {}) { + const { error = 'throw' } = options; + try { + return cb(); + } catch (err) { + if (error === 'return') { + return err; + } else { + throw err; + } + } +} + +function getDataViewDescriptor$8(structure, handlers = {}) { + return markAsSpecial$8({ + get() { + /* WASM-ONLY */ + restoreMemory$8.call(this); + /* WASM-ONLY-END */ + return this[MEMORY$8]; + }, + set(dv) { + checkDataView$8(dv); + setDataView$8.call(this, dv, structure, true, handlers); + }, + }); +} + +function getBase64Descriptor$8(structure, handlers = {}) { + return markAsSpecial$8({ + get() { + return encodeBase64$8(this.dataView); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$8('string', str); + } + const dv = decodeBase64$8(str); + setDataView$8.call(this, dv, structure, false, handlers); + } + }); +} + +function getStringDescriptor$8(structure, handlers = {}) { + const { sentinel, instance: { members }} = structure; + const { byteSize: charSize } = members[0]; + return markAsSpecial$8({ + get() { + const dv = this.dataView; + const TypedArray = (charSize === 1) ? Int8Array : Int16Array; + const ta = new TypedArray(dv.buffer, dv.byteOffset, this.length); + const s = decodeText$8(ta, `utf-${charSize * 8}`); + return (sentinel?.value === undefined) ? s : s.slice(0, -1); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$8('a string', str); + } + if (sentinel?.value !== undefined) { + if (str.charCodeAt(str.length - 1) !== sentinel.value) { + str = str + String.fromCharCode(sentinel.value); + } + } + const ta = encodeText$8(str, `utf-${charSize * 8}`); + const dv = new DataView(ta.buffer); + setDataView$8.call(this, dv, structure, false, handlers); + }, + }); +} + +function getTypedArrayDescriptor$8(structure, handlers = {}) { + const { typedArray } = structure; + return markAsSpecial$8({ + get() { + const dv = this.dataView; + const length = dv.byteLength / typedArray.BYTES_PER_ELEMENT; + return new typedArray(dv.buffer, dv.byteOffset, length); + }, + set(ta) { + if (!isTypedArray$8(ta, typedArray)) { + throwTypeMismatch$8(typedArray.name, ta); + } + const dv = new DataView(ta.buffer, ta.byteOffset, ta.byteLength); + setDataView$8.call(this, dv, structure, true, handlers); + }, + }); +} + +function markAsSpecial$8({ get, set }) { + get.special = set.special = true; + return { get, set }; +} + +function definePointer$8(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + isConst, + } = structure; + const { + runtimeSafety = true, + } = env; + const { structure: targetStructure } = member; + const { sentinel } = targetStructure; + const isTargetSlice = (targetStructure.type === StructureType$8.Slice); + const isTargetPointer = (targetStructure.type === StructureType$8.Pointer); + const hasLength = isTargetSlice && !sentinel; + const addressSize = (hasLength) ? byteSize / 2 : byteSize; + const { get: getAddress, set: setAddress } = getDescriptor$8({ + type: MemberType$8.Uint, + bitOffset: 0, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { byteSize: addressSize }, + }, env); + const { get: getLength, set: setLength } = (hasLength) ? getDescriptor$8({ + type: MemberType$8.Uint, + bitOffset: addressSize * 8, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { name: 'usize', byteSize: addressSize }, + }, env) : {}; + const updateTarget = function() { + const prevLocation = this[FIXED_LOCATION$8]; + if (prevLocation) { + const location = this[LOCATION_GETTER$8](); + if (location.address !== prevLocation.address || location.length !== prevLocation.length) { + const { constructor: Target } = targetStructure; + const dv = env.findMemory(location.address, location.length * Target[SIZE$8]); + const target = Target.call(ENVIRONMENT$8, dv, { writable: !isConst }); + this[SLOTS$8][0] = target; + this[FIXED_LOCATION$8] = location; + } + } + }; + const getTargetObject = function() { + updateTarget.call(this); + return this[SLOTS$8][0] ?? throwNullPointer$8(); + }; + const setTargetObject = function(arg) { + if (env.inFixedMemory(this)) { + // the pointer sits in fixed memory--apply the change immediately + if (env.inFixedMemory(arg)) { + const loc = { + address: env.getViewAddress(arg[MEMORY$8]), + length: (hasLength) ? arg.length : 1 + }; + addressSetter.call(this, loc); + this[FIXED_LOCATION$8] = loc; + } else { + throwFixedMemoryTargetRequired$8(); + } + } + this[SLOTS$8][0] = arg; + }; + const getTarget = isValueExpected$8(targetStructure) + ? function() { + const target = getTargetObject.call(this); + return target[GETTER$8](); + } + : getTargetObject; + const setTarget = function(value) { + updateTarget.call(this); + const object = this[SLOTS$8][0] ?? throwNullPointer$8(); + return object[SETTER$8](value); + }; + const alternateCaster = function(arg, options) { + const Target = targetStructure.constructor; + if ((this === ENVIRONMENT$8 || this === PARENT$8) || arg instanceof constructor) { + // casting from buffer to pointer is allowed only if request comes from the runtime + // casting from writable to read-only is also allowed + return false; + } else if (isPointerOf$8(arg, Target)) { + // const/non-const casting + return new constructor(Target(arg['*'], { writable: !isConst }), options); + } else if (isTargetSlice) { + // allow casting to slice through constructor of its pointer + return new constructor(Target(arg), options); + } else { + throwNoCastingToPointer$8(); + } + }; + const finalizer = function() { + const handlers = (isTargetPointer) ? {} : proxyHandlers$h; + const proxy = new Proxy(this, handlers); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$8, { value: proxy }); + return proxy; + }; + const initializer = function(arg) { + const Target = targetStructure.constructor; + if (isPointerOf$8(arg, Target)) { + // initialize with the other pointer'structure target + if (!isConst && arg.constructor.const) { + throwConstantConstraint$8(structure, arg); + } + arg = arg[SLOTS$8][0]; + } + if (arg instanceof Target) { + /* wasm-only */ + restoreMemory$8.call(arg); + /* wasm-only-end */ + if (isConst && !arg[CONST$8]) { + // create read-only version + arg = Target(arg, { writable: false }); + } else if (!isConst && arg[CONST$8]) { + throwReadOnlyTarget$8(structure); + } + } else if (isCompatible$8(arg, Target)) { + // autocast to target type + const dv = getDataView$8(targetStructure, arg, env); + arg = Target(dv, { writable: !isConst }); + } else if (arg !== undefined && !arg[MEMORY$8]) { + // autovivificate target object + const fixed = env.inFixedMemory(this); + const autoObj = new Target(arg, { writable: !isConst, fixed }); + if (runtimeSafety) { + // creation of a new slice using a typed array is probably + // not what the user wants; it's more likely that the intention + // is to point to the typed array but there's a mismatch (e.g. u32 vs i32) + if (targetStructure.typedArray && isBuffer$8(arg?.buffer)) { + warnImplicitArrayCreation$8(targetStructure, arg); + } + } + arg = autoObj; + } else if (arg !== undefined) { + throwInvalidPointerTarget$8(structure, arg); + } + this[TARGET_SETTER$8](arg); + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer, alternateCaster, finalizer }, env); + const addressSetter = function({ address, length }) { + setAddress.call(this, address); + setLength?.call(this, length); + }; + const addressGetter = function() { + const address = getAddress.call(this); + const length = (getLength) + ? getLength.call(this) + : (sentinel) + ? (address) ? env.findSentinel(address, sentinel.bytes) + 1 : 0 + : 1; + return { address, length }; + }; + const instanceDescriptors = { + '*': { get: getTarget, set: setTarget }, + '$': { get: getProxy$8, set: initializer }, + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [TARGET_GETTER$8]: { value: getTargetObject }, + [TARGET_SETTER$8]: { value: setTargetObject }, + [LOCATION_GETTER$8]: { value: addressGetter }, + [LOCATION_SETTER$8]: { value: addressSetter }, + [POINTER_VISITOR$8]: { value: visitPointer$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [VIVIFICATOR$8]: { value: throwNullPointer$8 }, + [NORMALIZER$8]: { value: normalizePointer$8 }, + [FIXED_LOCATION$8]: { value: undefined, writable: true }, + }; + const staticDescriptors = { + child: { get: () => targetStructure.constructor }, + const: { value: isConst }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizePointer$8(cb) { + let target; + try { + target = this['*']; + } catch (err) { + target = Symbol.for('inaccessible'); + } + return cb(target); +} + +function getProxy$8() { + return this[PROXY$8]; +} + +function copyPointer$8({ source }) { + const target = source[SLOTS$8][0]; + if (target) { + this[TARGET_SETTER$8](target); + } +} + +function resetPointer$8({ isActive }) { + if (this[SLOTS$8][0] && !isActive(this)) { + this[SLOTS$8][0] = undefined; + } +} + +function disablePointer$8() { + const disabledProp = { get: throwInaccessiblePointer$8, set: throwInaccessiblePointer$8 }; + const disabledFunc = { value: throwInaccessiblePointer$8 }; + defineProperties$8(this[POINTER$8], { + '*': disabledProp, + '$': disabledProp, + [GETTER$8]: disabledFunc, + [SETTER$8]: disabledFunc, + [TARGET_GETTER$8]: disabledFunc, + }); +} + +function visitPointer$8(fn, options = {}) { + const { + source, + isActive = always$8, + isMutable = always$8, + } = options; + fn.call(this, { source, isActive, isMutable }); +} + +function isPointerOf$8(arg, Target) { + return (arg?.constructor?.child === Target && arg['*']); +} + +const proxyHandlers$h = { + get(pointer, name) { + if (name === POINTER$8) { + return pointer; + } else if (name in pointer) { + return pointer[name]; + } else { + const target = pointer[TARGET_GETTER$8](); + return target[name]; + } + }, + set(pointer, name, value) { + if (name in pointer) { + pointer[name] = value; + } else { + const target = pointer[TARGET_GETTER$8](); + target[name] = value; + } + return true; + }, + deleteProperty(pointer, name) { + if (name in pointer) { + delete pointer[name]; + } else { + const target = pointer[TARGET_GETTER$8](); + delete target[name]; + } + return true; + }, + has(pointer, name) { + if (name in pointer) { + return true; + } else { + const target = pointer[TARGET_GETTER$8](); + return name in target; + } + }, +}; + +function always$8() { + return true; +} + +function never$8() { + return false; +} + +function defineStructShape$8(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const memberDescriptors = {}; + for (const member of members) { + const { get, set } = getDescriptor$8(member, env); + memberDescriptors[member.name] = { get, set, configurable: true, enumerable: true }; + if (member.isRequired && set) { + set.required = true; + } + } + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); + if (hasPointer) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } else if (arg && typeof(arg) === 'object') { + propApplier.call(this, arg); + } else if (arg !== undefined) { + throwInvalidInitializer$8(structure, 'object', arg); + } + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const instanceDescriptors = { + $: { get: getSelf$8, set: initializer }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getStructIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, always$8) }, + [NORMALIZER$8]: { value: normalizeStruct$8 }, + [PROPS$8]: { value: members.map(m => m.name) }, + }; + const staticDescriptors = { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizeStruct$8(cb, options) { + const object = {}; + for (const [ name, value ] of getStructEntries$8.call(this, options)) { + object[name] = cb(value); + } + return object; +} + +function getStructEntries$8(options) { + return { + [Symbol.iterator]: getStructEntriesIterator$8.bind(this, options), + length: this[PROPS$8].length, + }; +} + +function getStructIterator$8(options) { + const entries = getStructEntries$8.call(this, options); + return entries[Symbol.iterator](); +} + +function getStructEntriesIterator$8(options) { + const self = this; + const props = this[PROPS$8]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + value = [ current, handleError$8(() => self[current], options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getChildVivificator$h(structure) { + const { instance: { members } } = structure; + const objectMembers = {}; + for (const member of members.filter(m => m.type === MemberType$8.Object)) { + objectMembers[member.slot] = member; + } + return function vivificateChild(slot, writable = true) { + const member = objectMembers[slot]; + const { bitOffset, byteSize, structure: { constructor } } = member; + const dv = this[MEMORY$8]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + (bitOffset >> 3); + let len = byteSize; + if (len === undefined) { + if (bitOffset & 7) { + throwNotOnByteBoundary$8(member); + } + len = member.bitSize >> 3; + } + const childDV = new DataView(dv.buffer, offset, len); + const object = this[SLOTS$8][slot] = constructor.call(PARENT$8, childDV, { writable }); + return object; + } +} + +function getPointerVisitor$h(structure, visitorOptions = {}) { + const { + isChildActive = always$8, + isChildMutable = always$8, + } = visitorOptions; + const { instance: { members } } = structure; + const pointerMembers = members.filter(m => m.structure.hasPointer); + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$8, + isMutable = always$8, + } = options; + const childOptions = { + ...options, + isActive: (object) => { + // make sure parent object is active, then check whether the child is active + return isActive(this) && isChildActive.call(this, object); + }, + isMutable: (object) => { + return isMutable(this) && isChildMutable.call(this, object); + }, + }; + for (const { slot } of pointerMembers) { + if (source) { + // when src is a the struct's template, most slots will likely be empty, + // since pointer fields aren't likely to have default values + const srcChild = source[SLOTS$8]?.[slot]; + if (!srcChild) { + continue; + } + childOptions.source = srcChild; + } + const child = this[SLOTS$8][slot] ?? (vivificate ? this[VIVIFICATOR$8](slot) : null); + if (child) { + child[POINTER_VISITOR$8](cb, childOptions); + } + } + }; +} + +function defineArgStruct$8(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const constructor = structure.constructor = function(args) { + const dv = env.allocateMemory(byteSize, align); + this[MEMORY$8] = dv; + if (hasObject) { + this[SLOTS$8] = {}; + } + initializer.call(this, args); + }; + const argNames = members.slice(0, -1).map(m => m.name); + const argCount = argNames.length; + const initializer = function(args) { + if (args.length !== argCount) { + throwArgumentCountMismatch$8(structure, args.length); + } + for (const [ index, name ] of argNames.entries()) { + try { + this[name] = args[index]; + } catch (err) { + rethrowArgumentError$8(structure, index, err); + } + } + }; + const memberDescriptors = {}; + for (const member of members) { + memberDescriptors[member.name] = getDescriptor$8(member, env); + } + const isChildMutable = function(object) { + return (object === this.retval); + }; + defineProperties$8(constructor.prototype, { + ...memberDescriptors, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, { isChildMutable }) }, + }); + defineProperties$8(constructor, { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }); + return constructor; +} + +function defineArray$8(structure, env) { + const { + length, + byteSize, + align, + instance: { members: [ member ] }, + hasPointer, + } = structure; + const { get, set } = getDescriptor$8(member, env); + const hasStringProp = canBeString$8(member); + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); + if (hasPointer) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } else { + if (typeof(arg) === 'string' && hasStringProp) { + arg = { string: arg }; + } + if (arg?.[Symbol.iterator]) { + arg = transformIterable$8(arg); + if (arg.length !== length) { + throwArrayLengthMismatch$8(structure, this, arg); + } + let i = 0; + for (const value of arg) { + set.call(this, i++, value); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$8(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$8(structure, arg); + } + } + }; + const finalizer = createArrayProxy$8; + const constructor = structure.constructor = createConstructor$8(structure, { initializer, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); + const hasObject = member.type === MemberType$8.Object; + const instanceDescriptors = { + $: { get: getProxy$8, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + string: hasStringProp && getStringDescriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$8 }, + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [Symbol.iterator]: { value: getArrayIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$g(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$g() }, + [NORMALIZER$8]: { value: normalizeArray$8 }, + }; + const staticDescriptors = { + child: { get: () => member.structure.constructor }, + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} + +function createArrayProxy$8() { + const proxy = new Proxy(this, proxyHandlers$g); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$8, { value: proxy }); + return proxy; +} + +function canBeString$8(member) { + return member.type === MemberType$8.Uint && [ 8, 16 ].includes(member.bitSize); +} + +function normalizeArray$8(cb, options) { + const array = []; + for (const [ index, value ] of getArrayEntries$8.call(this, options)) { + array.push(cb(value)); + } + return array; +} + +function getArrayIterator$8() { + const self = this[ARRAY$8] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self.get(current); + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getArrayEntriesIterator$8(options) { + const self = this[ARRAY$8] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, handleError$8(() => self.get(current), options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getArrayEntries$8(options) { + return { + [Symbol.iterator]: getArrayEntriesIterator$8.bind(this, options), + length: this.length, + }; +} + +function getChildVivificator$g(structure) { + const { instance: { members: [ member ]} } = structure; + const { byteSize, structure: elementStructure } = member; + return function getChild(index, writable = true) { + const { constructor } = elementStructure; + const dv = this[MEMORY$8]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + byteSize * index; + const childDV = new DataView(dv.buffer, offset, byteSize); + const object = this[SLOTS$8][index] = constructor.call(PARENT$8, childDV, { writable }); + return object; + }; +} + +function getPointerVisitor$g(structure) { + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$8, + isMutable = always$8, + } = options; + const childOptions = { + ...options, + isActive: () => isActive(this), + isMutable: () => isMutable(this), + }; + for (let i = 0, len = this.length; i < len; i++) { + // no need to check for empty slots, since that isn't possible + if (source) { + childOptions.source = source?.[SLOTS$8][i]; + } + const child = this[SLOTS$8][i] ?? (vivificate ? this[VIVIFICATOR$8](i) : null); + if (child) { + child[POINTER_VISITOR$8](cb, childOptions); + } + } + }; +} + +function transformIterable$8(arg) { + if (typeof(arg.length) === 'number') { + // it's an array of sort + return arg; + } + const iterator = arg[Symbol.iterator](); + const first = iterator.next(); + const length = first.value?.length; + if (typeof(length) === 'number' && Object.keys(first.value).join() === 'length') { + // return generator with length attached + return Object.assign((function*() { + let result; + while (!(result = iterator.next()).done) { + yield result.value; + } + })(), { length }); + } else { + const array = []; + let result = first; + while (!result.done) { + array.push(result.value); + result = iterator.next(); + } + return array; + } +} + +const proxyHandlers$g = { + get(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return array.get(index); + } else { + switch (name) { + case 'get': + if (!array[ELEMENT_GETTER$8]) { + array[ELEMENT_GETTER$8] = array.get.bind(array); + } + return array[ELEMENT_GETTER$8]; + case 'set': + if (!array[ELEMENT_SETTER$8]) { + array[ELEMENT_SETTER$8] = array.set.bind(array); + } + return array[ELEMENT_SETTER$8]; + case ARRAY$8: + return array; + default: + return array[name]; + } + } + }, + set(array, name, value) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + array.set(index, value); + } else { + switch (name) { + case 'get': + array[ELEMENT_GETTER$8] = value; + break; + case 'set': + array[ELEMENT_SETTER$8] = value; + break; + default: + array[name] = value; + } + } + return true; + }, + deleteProperty(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return false; + } else { + switch (name) { + case 'get': + delete array[ELEMENT_GETTER$8]; + break; + case 'set': + delete array[ELEMENT_SETTER$8]; + break; + default: + delete array[name]; + } + return true; + } + }, + has(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return (index >= 0 && index < array.length); + } else { + return array[name]; + } + }, + ownKeys(array) { + const keys = []; + for (let i = 0, len = array.length; i < len; i++) { + keys.push(`${i}`); + } + keys.push('length', PROXY$8); + return keys; + }, + getOwnPropertyDescriptor(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + if (index >= 0 && index < array.length) { + return { value: array.get(index), enumerable: true, writable: true, configurable: true }; + } + } else { + return Object.getOwnPropertyDescriptor(array, name); + } + }, +}; + +function defineEnumerationShape$8(structure, env) { + const { + byteSize, + align, + instance: { + members: [ member ], + }, + } = structure; + const { get, set } = getDescriptor$8(member, env); + const expected = [ 'string', 'number', 'tagged union' ]; + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$8(structure, expected, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'string' || typeof(arg) === 'number' || typeof(arg) === 'bigint') { + let item = constructor[arg]; + if (!item) { + if (constructor[MORE$8] && typeof(arg) !== 'string') { + // create the item on-the-fly when enum is non-exhaustive + item = new constructor(undefined); + debugger; + set.call(item, arg, 'number'); + appendEnumeration(constructor, `${arg}`, item); } } return item; - } else if (arg?.[TAG$7] instanceof constructor) { + } else if (arg instanceof constructor) { + return arg; + } else if (arg?.[TAG$8] instanceof constructor) { // a tagged union, return the active tag - return arg[TAG$7]; - } else if (!getDataView$7(structure, arg, env)) { - throwInvalidInitializer$7(structure, expected, arg); + return arg[TAG$8]; + } else if (!getDataView$8(structure, arg, env)) { + throwInvalidInitializer$8(structure, expected, arg); } else { return false; } }; - const constructor = structure.constructor = createConstructor$7(structure, { initializer, alternateCaster }, env); - const typedArray = structure.typedArray = getTypedArrayClass$7(member); + const constructor = structure.constructor = createConstructor$8(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); const toPrimitive = function(hint) { - return (hint === 'string') ? this.$[NAME$7] : getIndex.call(this); + return (hint === 'string') ? this.$[NAME$8] : get.call(this, 'number'); }; const instanceDescriptors = { $: { get, set }, - dataView: getDataViewDescriptor$7(structure), - base64: getBase64Descriptor$7(structure), - typedArray: typedArray && getTypedArrayDescriptor$7(structure), - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, [Symbol.toPrimitive]: { value: toPrimitive }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [NORMALIZER$7]: { value: normalizeEnumerationItem$7 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: normalizeEnumerationItem$8 }, }; const staticDescriptors = { - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, - [ITEMS$7]: { value: {} }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } -function normalizeEnumerationItem$7(cb) { - return cb(this.$[NAME$7]); +function normalizeEnumerationItem$8(cb) { + return cb(this.$[NAME$8]); } -function defineErrorSet$7(structure, env) { +function appendEnumeration(enumeration, name, item) { + if (name !== undefined) { + // enum can have static variables + if (item instanceof enumeration) { + // attach name to item so tagged union code can quickly find it + defineProperties$8(item, { [NAME$8]: { value: name } }); + // call toPrimitive directly since enum can be bigint or number + const index = item[Symbol.toPrimitive](); + defineProperties$8(enumeration, { + [index]: { value: item }, + [name]: { value: item }, + }); + } + } else { + // non-exhaustive enum + defineProperties$8(enumeration, { [MORE$8]: { value: true } }); + } +} + +function defineErrorUnion$8(structure, env) { const { byteSize, align, - instance: { members: [ member ] }, + instance: { members }, + hasPointer, } = structure; - const { get: getIndex } = getDescriptor$7(member, env); - // get the error descriptor instead of the int/uint descriptor - const { get, set } = getDescriptor$7({ ...member, type: MemberType$7.Error, structure }, env); - const expected = [ 'string', 'number' ]; - const propApplier = createPropertyApplier$7(structure); + const { get: getValue, set: setValue } = getDescriptor$8(members[0], env); + const { get: getError, set: setError } = getDescriptor$8(members[1], env); + const get = function() { + const errNum = getError.call(this, 'number'); + if (errNum) { + throw getError.call(this); + } else { + return getValue.call(this); + } + }; + const isValueVoid = members[0].type === MemberType$8.Void; + const TargetError = members[1].structure.constructor[CLASS]; + const isChildActive = function() { + return !getError.call(this, 'number'); + }; + const clearValue = function() { + this[RESETTER$8](); + this[POINTER_VISITOR$8]?.(resetPointer$8); + }; + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const propApplier = createPropertyApplier$8(structure); const initializer = function(arg) { - if (arg && typeof(arg) === 'object') { + if (arg instanceof constructor) { + this[COPIER$8](arg); + if (hasPointer) { + if (isChildActive.call(this)) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } + } else if (arg instanceof TargetError) { + setError.call(this, arg); + clearValue.call(this); + } else if (arg !== undefined || isValueVoid) { try { - if (propApplier.call(this, arg) === 0) { - throwInvalidInitializer$7(structure, expected, arg); - } + // call setValue() first, in case it throws + setValue.call(this, arg); + setError.call(this, 0, 'number'); } catch (err) { - const { error } = arg; - if (typeof(error) === 'string') { - set.call(this, error); + if (arg instanceof Error) { + // we give setValue a chance to see if the error is actually an acceptable value + // now is time to throw an error + throwNotInErrorSet$8(structure); + } else if (isErrorJSON(arg)) { + setError.call(this, arg); + clearValue.call(this); + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throw err; + } } else { throw err; } } - } else if (arg !== undefined) { - set.call(this, arg); } + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; + const instanceDescriptors = { + '$': { get, set: initializer }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [RESETTER$8]: { value: getMemoryResetter$8(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, { isChildActive }) }, + [NORMALIZER$8]: { value: normalizeValue$8 }, }; - const alternateCaster = function(arg) { - if (typeof(arg) === 'number' || typeof(arg) === 'string') { - return constructor[ITEMS$7][arg]; - } else if (!getDataView$7(structure, arg, env)) { - throwInvalidInitializer$7(structure, expected, arg); + const staticDescriptors = { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} + +function defineOpaque$8(structure, env) { + const { + byteSize, + align, + } = structure; + const initializer = function() { + throwCreatingOpaque$8(structure); + }; + const valueAccessor = function() { + throwAccessingOpaque$8(structure); + }; + const toPrimitive = function(hint) { + const { name } = structure; + return `[opaque ${name}]`; + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const instanceDescriptors = { + $: { get: valueAccessor, set: valueAccessor }, + dataView: getDataViewDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [Symbol.toPrimitive]: { value: toPrimitive }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: normalizeOpaque$8 }, + }; + const staticDescriptors = { + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} +function normalizeOpaque$8(cb) { + return {}; +} + +function defineOptional$8(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const { get: getValue, set: setValue } = getDescriptor$8(members[0], env); + const { get: getPresent, set: setPresent } = getDescriptor$8(members[1], env); + const hasPresentFlag = !(members[0].bitSize > 0 && members[0].bitOffset === members[1].bitOffset); + const get = function() { + const present = getPresent.call(this); + if (present) { + return getValue.call(this); } else { - return false; + this[POINTER_VISITOR$8]?.(resetPointer$8); + return null; } }; - const constructor = structure.constructor = createConstructor$7(structure, { initializer, alternateCaster }, env); - Object.setPrototypeOf(constructor.prototype, globalErrorSet$7.prototype); - const typedArray = structure.typedArray = getTypedArrayClass$7(member); - const getMessage = function() { return this.$.message; }; - const toStringTag = function() { return 'Error' }; - const toPrimitive = function(hint) { - if (hint === 'string') { - return Error.prototype.toString.call(this, hint); + const isValueVoid = members[0].type === MemberType$8.Void; + const isChildActive = getPresent; + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); + if (hasPointer) { + // don't bother copying pointers when it's empty + if (isChildActive.call(arg)) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } + } else if (arg === null) { + setPresent.call(this, false); + this[RESETTER$8]?.(); + // clear references so objects can be garbage-collected + this[POINTER_VISITOR$8]?.(resetPointer$8); + } else if (arg !== undefined || isValueVoid) { + // call setValue() first, in case it throws + setValue.call(this, arg); + if (hasPresentFlag || !env.inFixedMemory(this)) { + // since setValue() wouldn't write address into memory when the pointer is in + // relocatable memory, we need to use setPresent() in order to write something + // non-zero there so that we know the field is populated + setPresent.call(this, true); + } + } + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const instanceDescriptors = { + $: { get, set: initializer }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + // no need to reset the value when it's a pointer, since setPresent() would null out memory used by the pointer + [RESETTER$8]: !hasPointer && { value: getMemoryResetter$8(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$h(structure, { isChildActive }) }, + [NORMALIZER$8]: { value: normalizeValue$8 }, + }; + const staticDescriptors = { + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} + +function definePrimitive$8(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { get, set } = getDescriptor$8(member, env); + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$8](arg); } else { - return getIndex.call(this); + if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + const type = getPrimitiveType$8(member); + throwInvalidInitializer$8(structure, type, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + } + }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [Symbol.toPrimitive]: { value: get }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: normalizeValue$8 }, + }; + const staticDescriptors = { + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + }; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} +function getIntRange$8(member) { + const { type, bitSize } = member; + const signed = (type === MemberType$8.Int); + let magBits = (signed) ? bitSize - 1 : bitSize; + if (bitSize <= 32) { + const max = 2 ** magBits - 1; + const min = (signed) ? -(2 ** magBits) : 0; + return { min, max }; + } else { + magBits = BigInt(magBits); + const max = 2n ** magBits - 1n; + const min = (signed) ? -(2n ** magBits) : 0n; + return { min, max }; + } +} + +function getPrimitiveClass$8({ type, bitSize }) { + if (type === MemberType$8.Int || type === MemberType$8.Uint) { + if (bitSize <= 32) { + return Number; + } else { + return BigInt; + } + } else if (type === MemberType$8.Float) { + return Number; + } else if (type === MemberType$8.Bool) { + return Boolean; + } +} + +function getPrimitiveType$8(member) { + const Primitive = getPrimitiveClass$8(member); + if (Primitive) { + return typeof(Primitive(0)); + } +} + +function defineSlice$8(structure, env) { + const { + align, + instance: { + members: [ member ], + }, + hasPointer, + } = structure; + const { get, set } = getDescriptor$8(member, env); + const { byteSize: elementSize, structure: elementStructure } = member; + const sentinel = getSentinel$8(structure, env); + if (sentinel) { + // zero-terminated strings aren't expected to be commonly used + // so we're not putting this prop into the standard structure + structure.sentinel = sentinel; + } + const hasStringProp = canBeString$8(member); + const shapeDefiner = function(dv, length, fixed = false) { + if (!dv) { + dv = env.allocateMemory(length * elementSize, align, fixed); + } + this[MEMORY$8] = dv; + this[LENGTH$8] = length; + }; + const shapeChecker = function(arg, length) { + if (length !== this[LENGTH$8]) { + throwArrayLengthMismatch$8(structure, this, arg); + } + }; + // the initializer behave differently depending on whether it's called by the + // constructor or by a member setter (i.e. after object's shape has been established) + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg, fixed = false) { + if (arg instanceof constructor) { + if (!this[MEMORY$8]) { + shapeDefiner.call(this, null, arg.length, fixed); + } else { + shapeChecker.call(this, arg, arg.length); + } + this[COPIER$8](arg); + if (hasPointer) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } else if (typeof(arg) === 'string' && hasStringProp) { + initializer.call(this, { string: arg }, fixed); + } else if (arg?.[Symbol.iterator]) { + arg = transformIterable$8(arg); + if (!this[MEMORY$8]) { + shapeDefiner.call(this, null, arg.length, fixed); + } else { + shapeChecker.call(this, arg, arg.length); + } + let i = 0; + for (const value of arg) { + sentinel?.validateValue(value, i, arg.length); + set.call(this, i++, value); + } + } else if (typeof(arg) === 'number') { + if (!this[MEMORY$8] && arg >= 0 && isFinite(arg)) { + shapeDefiner.call(this, null, arg); + } else { + throwInvalidArrayInitializer$8(structure, arg, !this[MEMORY$8]); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$8(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$8(structure, arg); } }; + const finalizer = createArrayProxy$8; + const constructor = structure.constructor = createConstructor$8(structure, { initializer, shapeDefiner, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); + const hasObject = member.type === MemberType$8.Object; + const shapeHandlers = { shapeDefiner }; const instanceDescriptors = { - $: { get, set }, - message: { get: getMessage }, - dataView: getDataViewDescriptor$7(structure), - base64: getBase64Descriptor$7(structure), - typedArray: typedArray && getTypedArrayDescriptor$7(structure), - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - // ensure that libraries that rely on the string tag for type detection will - // correctly identify the object as an error - [Symbol.toStringTag]: { get: toStringTag }, - [Symbol.toPrimitive]: { value: toPrimitive }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [NORMALIZER$7]: { value: get }, + $: { get: getProxy$8, set: initializer }, + length: { get: getLength$8 }, + dataView: getDataViewDescriptor$8(structure, shapeHandlers), + base64: getBase64Descriptor$8(structure, shapeHandlers), + string: hasStringProp && getStringDescriptor$8(structure, shapeHandlers), + typedArray: typedArray && getTypedArrayDescriptor$8(structure, shapeHandlers), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$8 }, + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [Symbol.iterator]: { value: getArrayIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(elementSize, true) }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$g(structure) }, + [POINTER_VISITOR$8]: hasPointer && { value: getPointerVisitor$g() }, + [NORMALIZER$8]: { value: normalizeArray$8 }, }; const staticDescriptors = { - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, - [ITEMS$7]: { value: {} }, + child: { get: () => elementStructure.constructor }, + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: elementSize }, }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); -} -let globalErrorSet$7; - -function createGlobalErrorSet() { - globalErrorSet$7 = function() {}; - Object.setPrototypeOf(globalErrorSet$7.prototype, Error.prototype); + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); } -function getGlobalErrorSet$7() { - return globalErrorSet$7; +function getLength$8() { + return this[LENGTH$8]; } -function defineErrorUnion$7(structure, env) { +function getSentinel$8(structure, env) { + const { + runtimeSafety = true, + } = env; const { byteSize, - align, - instance: { members }, - hasPointer, + instance: { members: [ member, sentinel ], template }, } = structure; - const { get: getValue, set: setValue } = getDescriptor$7(members[0], env); - const { get: getError, set: setError } = getDescriptor$7(members[1], env); - const get = function() { - const error = getError.call(this, true); - if (error) { - throw error; - } else { - return getValue.call(this); + if (!sentinel) { + return; + } + const { get: getSentinelValue } = getDescriptor$8(sentinel, env); + const value = getSentinelValue.call(template, 0); + const { get } = getDescriptor$8(member, env); + const validateValue = (runtimeSafety) ? function(v, i, l) { + if (v === value && i !== l - 1) { + throwMisplacedSentinel$8(structure, v, i, l); + } else if (v !== value && i === l - 1) { + throwMissingSentinel$8(structure, value, i); + } + } : function(v, i, l) { + if (v !== value && i === l - 1) { + throwMissingSentinel$8(structure, value, l); } }; - const isValueVoid = members[0].type === MemberType$7.Void; - const acceptAny = members[1].structure.name === 'anyerror'; - const TargetError = (acceptAny) ? getGlobalErrorSet$7() : members[1].structure.constructor; - const isChildActive = function() { - return !getError.call(this, true); - }; - const clearValue = function() { - this[RESETTER$7](); - this[POINTER_VISITOR$7]?.(resetPointer$7); - }; - const hasObject = !!members.find(m => m.type === MemberType$7.Object); - const propApplier = createPropertyApplier$7(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$7](arg); - if (hasPointer) { - if (isChildActive.call(this)) { - this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); - } + const validateData = (runtimeSafety) ? function(source, len) { + for (let i = 0; i < len; i++) { + const v = get.call(source, i); + if (v === value && i !== len - 1) { + throwMisplacedSentinel$8(structure, value, i, len); + } else if (v !== value && i === len - 1) { + throwMissingSentinel$8(structure, value, len); } - } else if (arg instanceof TargetError) { - setError.call(this, arg); - clearValue.call(this); - } else if (arg !== undefined || isValueVoid) { - try { - // call setValue() first, in case it throws - setValue.call(this, arg); - setError.call(this, 0, true); - } catch (err) { - if (arg instanceof Error) { - // we give setValue a chance to see if the error is actually an acceptable value - // now is time to throw an error - throwNotInErrorSet$7(structure); - } else if (arg && typeof(arg) === 'object') { - try { - if (propApplier.call(this, arg) === 0) { - throw err; - } - } catch (err) { - const { error } = arg; - if (typeof(error) === 'string') { - setError.call(this, error); - clearValue.call(this); - } else { - throw err; - } - } - } else { - throw err; - } + } + } : function(source, len) { + if (len * byteSize === source[MEMORY$8].byteLength) { + const i = len - 1; + const v = get.call(source, i); + if (v !== value) { + throwMissingSentinel$8(structure, value, len); } } - }; - const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); - const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; - const instanceDescriptors = { - '$': { get, set: initializer }, - dataView: getDataViewDescriptor$7(structure), - base64: getBase64Descriptor$7(structure), - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [RESETTER$7]: { value: getMemoryResetter$7(valueBitOffset / 8, valueByteSize) }, - [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, - [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$f(structure, { isChildActive }) }, - [NORMALIZER$7]: { value: normalizeValue$7 }, - }; - const staticDescriptors = { - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); + const bytes = template[MEMORY$8]; + return { value, bytes, validateValue, validateData }; } -function defineOpaque$7(structure, env) { +function defineUnionShape$8(structure, env) { const { + type, byteSize, align, + instance: { members, template }, + hasPointer, } = structure; - const initializer = function() { - throwCreatingOpaque$7(structure); - }; - const valueAccessor = function() { - throwAccessingOpaque$7(structure); - }; - const toPrimitive = function(hint) { - const { name } = structure; - return `[opaque ${name}]`; - }; - const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); - const instanceDescriptors = { - $: { get: valueAccessor, set: valueAccessor }, - dataView: getDataViewDescriptor$7(structure), - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - [Symbol.toPrimitive]: { value: toPrimitive }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [NORMALIZER$7]: { value: normalizeOpaque$7 }, + const { runtimeSafety } = env; + const isTagged = (type === StructureType$8.TaggedUnion); + const exclusion = (isTagged || (type === StructureType$8.BareUnion && runtimeSafety)); + const memberDescriptors = {}; + const memberInitializers = {}; + const memberValueGetters = {}; + const valueMembers = (exclusion) ? members.slice(0, -1) : members; + const selectorMember = (exclusion) ? members[members.length - 1] : null; + const { get: getSelector, set: setSelector } = (exclusion) ? getDescriptor$8(selectorMember, env) : {}; + const getActiveField = (isTagged) + ? function() { + const item = getSelector.call(this); + return item[NAME$8]; + } + : function() { + const index = getSelector.call(this); + return valueMembers[index].name; + }; + const setActiveField = (isTagged) + ? function(name) { + const { constructor } = selectorMember.structure; + setSelector.call(this, constructor[name]); + } + : function(name) { + const index = valueMembers.findIndex(m => m.name === name); + setSelector.call(this, index); + }; + for (const member of valueMembers) { + const { name } = member; + const { get: getValue, set: setValue } = getDescriptor$8(member, env); + const get = (exclusion) + ? function() { + const currentName = getActiveField.call(this); + if (name !== currentName) { + if (isTagged) { + // tagged union allows inactive member to be queried + return null; + } else { + // whereas bare union does not, since the condition is not detectable + // when runtime safety is off + throwInactiveUnionProperty$8(structure, name, currentName); + } + } + this[POINTER_VISITOR$8]?.(resetPointer$8); + return getValue.call(this); + } + : getValue; + const set = (exclusion && setValue) + ? function(value) { + const currentName = getActiveField.call(this); + if (name !== currentName) { + throwInactiveUnionProperty$8(structure, name, currentName); + } + setValue.call(this, value); + } + : setValue; + const init = (exclusion && setValue) + ? function(value) { + setActiveField.call(this, name); + setValue.call(this, value); + this[POINTER_VISITOR$8]?.(resetPointer$8); + } + : setValue; + memberDescriptors[name] = { get, set, configurable: true, enumerable: true }; + memberInitializers[name] = init; + memberValueGetters[name] = getValue; + } + const hasDefaultMember = !!valueMembers.find(m => !m.isRequired); + const memberKeys = Object.keys(memberDescriptors); + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + /* WASM-ONLY-END */ + this[COPIER$8](arg); + if (hasPointer) { + this[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } else if (arg && typeof(arg) === 'object') { + let found = 0; + for (const key of memberKeys) { + if (key in arg) { + found++; + } + } + if (found > 1) { + throwMultipleUnionInitializers$8(structure); + } + if (propApplier.call(this, arg) === 0 && !hasDefaultMember) { + throwMissingUnionInitializer$8(structure, arg, exclusion); + } + } else if (arg !== undefined) { + throwInvalidInitializer$8(structure, 'object with a single property', arg); + } }; + // non-tagged union as marked as not having pointers--if there're actually + // members with pointers, we need to disable them + const pointerMembers = members.filter(m => m.structure.hasPointer); + const hasInaccessiblePointer = !hasPointer && (pointerMembers.length > 0); + const modifier = (hasInaccessiblePointer && !env.comptime) + ? function() { + // make pointer access throw + this[POINTER_VISITOR$8](disablePointer$8, { vivificate: true }); + } + : undefined; + const constructor = structure.constructor = createConstructor$8(structure, { modifier, initializer }, env); + const fieldDescriptor = (isTagged) + ? { + // for tagged union, only the active field + get() { return [ getActiveField.call(this) ] } + } + : { + // for bare and extern union, all members are included + value: valueMembers.map(m => m.name) + }; + const isChildActive = (isTagged) + ? function(child) { + const name = getActiveField.call(this); + const active = memberValueGetters[name].call(this); + return child === active; + } + : never$8; + const hasAnyPointer = hasPointer || hasInaccessiblePointer; + const hasObject = !!members.find(m => m.type === MemberType$8.Object); + const instanceDescriptors = { + $: { get: getSelf$8, set: initializer, configurable: true }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getUnionIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [TAG$8]: isTagged && { get: getSelector, configurable: true }, + [VIVIFICATOR$8]: hasObject && { value: getChildVivificator$h(structure) }, + [POINTER_VISITOR$8]: hasAnyPointer && { value: getPointerVisitor$h(structure, { isChildActive }) }, + [PROP_GETTERS$8]: { value: memberValueGetters }, + [NORMALIZER$8]: { value: normalizeUnion$8 }, + [PROPS$8]: fieldDescriptor, + }; const staticDescriptors = { - [COMPAT$7]: { value: getCompatibleTags$7(structure) }, - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); + attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); + // replace regular setters with ones that change the active field + const setters = constructor.prototype[PROP_SETTERS$8]; + for (const [ name, init ] of Object.entries(memberInitializers)) { + if (init) { + setters[name] = init; + } + } } -function normalizeOpaque$7(cb) { - return {}; +function normalizeUnion$8(cb, options) { + const object = {}; + for (const [ name, value ] of getUnionEntries$8.call(this, options)) { + object[name] = cb(value); + } + return object; } -function defineOptional$7(structure, env) { - const { - byteSize, - align, - instance: { members }, - hasPointer, - } = structure; - const { get: getValue, set: setValue } = getDescriptor$7(members[0], env); - const { get: getPresent, set: setPresent } = getDescriptor$7(members[1], env); - const hasPresentFlag = !(members[0].bitSize > 0 && members[0].bitOffset === members[1].bitOffset); - const get = function() { - const present = getPresent.call(this); - if (present) { - return getValue.call(this); - } else { - this[POINTER_VISITOR$7]?.(resetPointer$7); - return null; - } +function getUnionEntries$8(options) { + return { + [Symbol.iterator]: getUnionEntriesIterator$8.bind(this, options), + length: this[PROPS$8].length, }; - const isValueVoid = members[0].type === MemberType$7.Void; - const isChildActive = getPresent; - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$7](arg); - if (hasPointer) { - // don't bother copying pointers when it's empty - if (isChildActive.call(arg)) { - this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); - } - } - } else if (arg === null) { - setPresent.call(this, false); - this[RESETTER$7]?.(); - // clear references so objects can be garbage-collected - this[POINTER_VISITOR$7]?.(resetPointer$7); - } else if (arg !== undefined || isValueVoid) { - // call setValue() first, in case it throws - setValue.call(this, arg); - if (hasPresentFlag || !env.inFixedMemory(this)) { - // since setValue() wouldn't write address into memory when the pointer is in - // relocatable memory, we need to use setPresent() in order to write something - // non-zero there so that we know the field is populated - setPresent.call(this, true); +} + +function getUnionIterator$8(options) { + const entries = getUnionEntries$8.call(this, options); + return entries[Symbol.iterator](); +} + +function getUnionEntriesIterator$8(options) { + const self = this; + const props = this[PROPS$8]; + const getters = this[PROP_GETTERS$8]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + // get value of prop with no check + value = [ current, handleError$8(() => getters[current].call(self), options) ]; + done = false; + } else { + done = true; } - } - }; - const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); - const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; - const hasObject = !!members.find(m => m.type === MemberType$7.Object); - const instanceDescriptors = { - $: { get, set: initializer }, - dataView: getDataViewDescriptor$7(structure), - base64: getBase64Descriptor$7(structure), - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - // no need to reset the value when it's a pointer, since setPresent() would null out memory used by the pointer - [RESETTER$7]: !hasPointer && { value: getMemoryResetter$7(valueBitOffset / 8, valueByteSize) }, - [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, - [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$f(structure, { isChildActive }) }, - [NORMALIZER$7]: { value: normalizeValue$7 }, - }; - const staticDescriptors = { - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, + return { value, done }; + }, }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); } -function defineSlice$7(structure, env) { +function defineVector$8(structure, env) { const { + length, + byteSize, align, - instance: { - members: [ member ], - }, - hasPointer, + instance: { members: [ member ] }, } = structure; - const { get, set } = getDescriptor$7(member, env); - const { byteSize: elementSize, structure: elementStructure } = member; - const sentinel = getSentinel$7(structure, env); - if (sentinel) { - // zero-terminated strings aren't expected to be commonly used - // so we're not putting this prop into the standard structure - structure.sentinel = sentinel; + const { bitSize: elementBitSize, structure: elementStructure } = member; + const elementDescriptors = {}; + for (let i = 0, bitOffset = 0; i < length; i++, bitOffset += elementBitSize) { + const { get, set } = getDescriptor$8({ ...member, bitOffset }, env); + elementDescriptors[i] = { get, set, configurable: true }; } - const hasStringProp = canBeString$7(member); - const shapeDefiner = function(dv, length, fixed = false) { - if (!dv) { - dv = env.allocateMemory(length * elementSize, align, fixed); - } - this[MEMORY$7] = dv; - this[LENGTH$7] = length; - }; - const shapeChecker = function(arg, length) { - if (length !== this[LENGTH$7]) { - throwArrayLengthMismatch$7(structure, this, arg); - } - }; - // the initializer behave differently depending on whether it's called by the - // constructor or by a member setter (i.e. after object's shape has been established) - const propApplier = createPropertyApplier$7(structure); - const initializer = function(arg, fixed = false) { + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { if (arg instanceof constructor) { - if (!this[MEMORY$7]) { - shapeDefiner.call(this, null, arg.length, fixed); - } else { - shapeChecker.call(this, arg, arg.length); - } - this[COPIER$7](arg); - if (hasPointer) { - this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); - } - } else if (typeof(arg) === 'string' && hasStringProp) { - initializer.call(this, { string: arg }, fixed); + this[COPIER$8](arg); } else if (arg?.[Symbol.iterator]) { - arg = transformIterable$7(arg); - if (!this[MEMORY$7]) { - shapeDefiner.call(this, null, arg.length, fixed); - } else { - shapeChecker.call(this, arg, arg.length); + let argLen = arg.length; + if (typeof(argLen) !== 'number') { + arg = [ ...arg ]; + argLen = arg.length; + } + if (argLen !== length) { + throwArrayLengthMismatch$8(structure, this, arg); } let i = 0; for (const value of arg) { - sentinel?.validateValue(value, i, arg.length); - set.call(this, i++, value); - } - } else if (typeof(arg) === 'number') { - if (!this[MEMORY$7] && arg >= 0 && isFinite(arg)) { - shapeDefiner.call(this, null, arg); - } else { - throwInvalidArrayInitializer$7(structure, arg, !this[MEMORY$7]); + this[PROP_SETTERS$8][i++].call(this, value); } } else if (arg && typeof(arg) === 'object') { if (propApplier.call(this, arg) === 0) { - throwInvalidArrayInitializer$7(structure, arg); + throwInvalidArrayInitializer$8(structure, arg); } } else if (arg !== undefined) { - throwInvalidArrayInitializer$7(structure, arg); + throwInvalidArrayInitializer$8(structure, arg); } }; - const finalizer = createArrayProxy$7; - const constructor = structure.constructor = createConstructor$7(structure, { initializer, shapeDefiner, finalizer }, env); - const typedArray = structure.typedArray = getTypedArrayClass$7(member); - const hasObject = member.type === MemberType$7.Object; - const shapeHandlers = { shapeDefiner }; + const constructor = structure.constructor = createConstructor$8(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); const instanceDescriptors = { - $: { get: getProxy$7, set: initializer }, - length: { get: getLength$7 }, - dataView: getDataViewDescriptor$7(structure, shapeHandlers), - base64: getBase64Descriptor$7(structure, shapeHandlers), - string: hasStringProp && getStringDescriptor$7(structure, shapeHandlers), - typedArray: typedArray && getTypedArrayDescriptor$7(structure, shapeHandlers), - get: { value: get }, - set: { value: set }, - entries: { value: getArrayEntries$7 }, - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - [Symbol.iterator]: { value: getArrayIterator$7 }, - [COPIER$7]: { value: getMemoryCopier$7(elementSize, true) }, - [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$e(structure) }, - [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$e() }, - [NORMALIZER$7]: { value: normalizeArray$7 }, + ...elementDescriptors, + $: { get: getSelf$8, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + entries: { value: getVectorEntries$8 }, + delete: { value: getDestructor$8(structure) }, + [Symbol.iterator]: { value: getVectorIterator$8 }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: normalizeVector$8 }, }; const staticDescriptors = { child: { get: () => elementStructure.constructor }, - [COMPAT$7]: { value: getCompatibleTags$7(structure) }, - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: elementSize }, + [COMPAT$8]: { value: getCompatibleTags$8(structure) }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizeVector$8(cb, options) { + const array = []; + for (const [ index, value ] of getVectorEntries$8.call(this, options)) { + array.push(cb(value)); + } + return array; +} + +function getVectorIterator$8() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self[current]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getVectorEntriesIterator$8() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, self[current] ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getVectorEntries$8() { + return { + [Symbol.iterator]: getVectorEntriesIterator$8.bind(this), + length: this.length, + }; +} + +const StructureType$8 = { + Primitive: 0, + Array: 1, + Struct: 2, + ExternStruct: 3, + PackedStruct: 4, + ArgStruct: 5, + ExternUnion: 6, + BareUnion: 7, + TaggedUnion: 8, + ErrorUnion: 9, + ErrorSet: 10, + Enumeration: 11, + Optional: 12, + Pointer: 13, + Slice: 14, + Vector: 15, + Opaque: 16, + Function: 17, +}; + +const factories$q = Array(Object.values(StructureType$8).length); + +function usePrimitive$8() { + factories$q[StructureType$8.Primitive] = definePrimitive$8; } -function getLength$7() { - return this[LENGTH$7]; +function useArray$8() { + factories$q[StructureType$8.Array] = defineArray$8; } -function getSentinel$7(structure, env) { - const { - runtimeSafety = true, - } = env; - const { - byteSize, - instance: { members: [ member, sentinel ], template }, - } = structure; - if (!sentinel) { - return; - } - const { get: getSentinelValue } = getDescriptor$7(sentinel, env); - const value = getSentinelValue.call(template, 0); - const { get } = getDescriptor$7(member, env); - const validateValue = (runtimeSafety) ? function(v, i, l) { - if (v === value && i !== l - 1) { - throwMisplacedSentinel$7(structure, v, i, l); - } else if (v !== value && i === l - 1) { - throwMissingSentinel$7(structure, value, i); +function useStruct$8() { + factories$q[StructureType$8.Struct] = defineStructShape$8; +} + +function usePackedStruct$8() { + factories$q[StructureType$8.PackedStruct] = defineStructShape$8; +} + +function useExternStruct$8() { + factories$q[StructureType$8.ExternStruct] = defineStructShape$8; +} + +function useArgStruct$8() { + factories$q[StructureType$8.ArgStruct] = defineArgStruct$8; +} + +function useExternUnion$8() { + factories$q[StructureType$8.ExternUnion] = defineUnionShape$8; +} + +function useBareUnion$8() { + factories$q[StructureType$8.BareUnion] = defineUnionShape$8; +} + +function useTaggedUnion$8() { + factories$q[StructureType$8.TaggedUnion] = defineUnionShape$8; +} + +function useErrorUnion$8() { + factories$q[StructureType$8.ErrorUnion] = defineErrorUnion$8; +} + +function useErrorSet$8() { + factories$q[StructureType$8.ErrorSet] = defineErrorSet$8; + useErrorSetTransform(); +} + +function useEnumeration$8() { + factories$q[StructureType$8.Enumeration] = defineEnumerationShape$8; + useEnumerationTransform(); +} + +function useOptional$8() { + factories$q[StructureType$8.Optional] = defineOptional$8; +} + +function usePointer$8() { + factories$q[StructureType$8.Pointer] = definePointer$8; + useUint$8(); +} + +function useSlice$8() { + factories$q[StructureType$8.Slice] = defineSlice$8; +} + +function useVector$8() { + factories$q[StructureType$8.Vector] = defineVector$8; +} + +function useOpaque$8() { + factories$q[StructureType$8.Opaque] = defineOpaque$8; +} + +function defineProperties$8(object, descriptors) { + for (const [ name, descriptor ] of Object.entries(descriptors)) { + if (descriptor) { + const { + set, + get, + value, + enumerable, + configurable = true, + writable = true, + } = descriptor; + Object.defineProperty(object, name, (get) + ? { get, set, configurable, enumerable } + : { value, configurable, enumerable, writable } + ); } - } : function(v, i, l) { - if (v !== value && i === l - 1) { - throwMissingSentinel$7(structure, value, l); + } + for (const symbol of Object.getOwnPropertySymbols(descriptors)) { + const descriptor = descriptors[symbol]; + if (descriptor) { + Object.defineProperty(object, symbol, descriptor); } - }; - const validateData = (runtimeSafety) ? function(source, len) { - for (let i = 0; i < len; i++) { - const v = get.call(source, i); - if (v === value && i !== len - 1) { - throwMisplacedSentinel$7(structure, value, i, len); - } else if (v !== value && i === len - 1) { - throwMissingSentinel$7(structure, value, len); + } +} + +function attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors) { + // create prototype for read-only objects + const prototypeRO = {}; + Object.setPrototypeOf(prototypeRO, constructor.prototype); + const instanceDescriptorsRO = {}; + const propSetters = {}; + for (const [ name, descriptor ] of Object.entries(instanceDescriptors)) { + if (descriptor?.set) { + instanceDescriptorsRO[name] = { ...descriptor, set: throwReadOnly$8 }; + // save the setters so we can initialize read-only objects + if (name !== '$') { + propSetters[name] = descriptor.set; } + } else if (name === 'set') { + instanceDescriptorsRO[name] = { value: throwReadOnly$8, configurable: true, writable: true }; } - } : function(source, len) { - if (len * byteSize === source[MEMORY$7].byteLength) { - const i = len - 1; - const v = get.call(source, i); - if (v !== value) { - throwMissingSentinel$7(structure, value, len); - } + } + const vivificate = instanceDescriptors[VIVIFICATOR$8]?.value; + const vivificateDescriptor = { + // vivificate child objects as read-only too + value: function(slot) { + return vivificate.call(this, slot, false); } }; - const bytes = template[MEMORY$7]; - return { value, bytes, validateValue, validateData }; + const { get, set } = instanceDescriptors.$; + defineProperties$8(constructor.prototype, { + [CONST$8]: { value: false }, + [ALL_KEYS$8]: { value: Object.keys(propSetters) }, + [SETTER$8]: { value: set }, + [GETTER$8]: { value: get }, + [PROP_SETTERS$8]: { value: propSetters }, + ...instanceDescriptors, + }); + defineProperties$8(constructor, { + [CONST_PROTOTYPE$8]: { value: prototypeRO }, + ...staticDescriptors, + }); + defineProperties$8(prototypeRO, { + constructor: { value: constructor, configurable: true }, + [CONST$8]: { value: true }, + [SETTER$8]: { value: throwReadOnly$8 }, + [VIVIFICATOR$8]: vivificate && vivificateDescriptor, + ...instanceDescriptorsRO, + }); + return constructor; } -function defineUnionShape$7(structure, env) { +function createConstructor$8(structure, handlers, env) { const { - type, byteSize, align, instance: { members, template }, hasPointer, } = structure; - const { runtimeSafety } = env; - const isTagged = (type === StructureType$7.TaggedUnion); - const exclusion = (isTagged || (type === StructureType$7.BareUnion && runtimeSafety)); - const memberDescriptors = {}; - const memberInitializers = {}; - const memberValueGetters = {}; - const valueMembers = (exclusion) ? members.slice(0, -1) : members; - const selectorMember = (exclusion) ? members[members.length - 1] : null; - const { get: getSelector, set: setSelector } = (exclusion) ? getDescriptor$7(selectorMember, env) : {}; - const getActiveField = (isTagged) - ? function() { - const item = getSelector.call(this); - return item[NAME$7]; - } - : function() { - const index = getSelector.call(this); - return valueMembers[index].name; - }; - const setActiveField = (isTagged) - ? function(name) { - const { constructor } = selectorMember.structure; - setSelector.call(this, constructor[name]); - } - : function(name) { - const index = valueMembers.findIndex(m => m.name === name); - setSelector.call(this, index); - }; - for (const member of valueMembers) { - const { name } = member; - const { get: getValue, set: setValue } = getDescriptor$7(member, env); - const get = (exclusion) - ? function() { - const currentName = getActiveField.call(this); - if (name !== currentName) { - if (isTagged) { - // tagged union allows inactive member to be queried - return null; - } else { - // whereas bare union does not, since the condition is not detectable - // when runtime safety is off - throwInactiveUnionProperty$7(structure, name, currentName); - } - } - this[POINTER_VISITOR$7]?.(resetPointer$7); - return getValue.call(this); + const { + modifier, + initializer, + finalizer, + alternateCaster, + shapeDefiner, + } = handlers; + const hasSlots = needSlots$8(members); + // comptime fields are stored in the instance template's slots + let comptimeFieldSlots; + if (template?.[SLOTS$8]) { + const comptimeMembers = members.filter(m => isReadOnly$8(m.type)); + if (comptimeMembers.length > 0) { + comptimeFieldSlots = comptimeMembers.map(m => m.slot); + } + } + const cache = new ObjectCache$8(); + const constructor = function(arg, options = {}) { + const { + writable = true, + fixed = false, + } = options; + const creating = this instanceof constructor; + let self, dv; + if (creating) { + if (arguments.length === 0) { + throwNoInitializer$8(structure); } - : getValue; - const set = (exclusion && setValue) - ? function(value) { - const currentName = getActiveField.call(this); - if (name !== currentName) { - throwInactiveUnionProperty$7(structure, name, currentName); + self = this; + if (hasSlots) { + self[SLOTS$8] = {}; + } + if (shapeDefiner) { + // provided by defineSlice(); the slice is different from other structures as it does not have + // a fixed size; memory is allocated by the slice initializer based on the argument given + initializer.call(self, arg, fixed); + dv = self[MEMORY$8]; + } else { + self[MEMORY$8] = dv = env.allocateMemory(byteSize, align, fixed); + } + } else { + if (alternateCaster) { + // casting from number, string, etc. + self = alternateCaster.call(this, arg, options); + if (self !== false) { + return self; } - setValue.call(this, value); } - : setValue; - const init = (exclusion && setValue) - ? function(value) { - setActiveField.call(this, name); - setValue.call(this, value); - this[POINTER_VISITOR$7]?.(resetPointer$7); + // look for buffer + dv = requireDataView$8(structure, arg, env); + if (self = cache.find(dv, writable)) { + return self; + } + self = Object.create(writable ? constructor.prototype : constructor[CONST_PROTOTYPE$8]); + if (shapeDefiner) { + setDataView$8.call(self, dv, structure, false, { shapeDefiner }); + } else { + self[MEMORY$8] = dv; + } + if (hasSlots) { + self[SLOTS$8] = {}; + if (hasPointer && arg instanceof constructor) { + // copy pointer from other object + self[POINTER_VISITOR$8](copyPointer$8, { vivificate: true, source: arg }); + } + } + } + if (comptimeFieldSlots) { + for (const slot of comptimeFieldSlots) { + self[SLOTS$8][slot] = template[SLOTS$8][slot]; + } + } + if (modifier) { + modifier.call(self); + } + if (creating) { + // initialize object unless it's been done already + if (!shapeDefiner) { + initializer.call(self, arg); } - : setValue; - memberDescriptors[name] = { get, set, configurable: true, enumerable: true }; - memberInitializers[name] = init; - memberValueGetters[name] = getValue; - } - const hasDefaultMember = !!valueMembers.find(m => !m.isRequired); - const memberKeys = Object.keys(memberDescriptors); - const propApplier = createPropertyApplier$7(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - /* WASM-ONLY-END */ - this[COPIER$7](arg); - if (hasPointer) { - this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); + if (!writable) { + // create object with read-only prototype + self = Object.assign(Object.create(constructor[CONST_PROTOTYPE$8]), self); + } + } + if (finalizer) { + self = finalizer.call(self); + } + return cache.save(dv, writable, self); + }; + return constructor; +} + +function createPropertyApplier$8(structure) { + const { instance: { template } } = structure; + return function(arg) { + const argKeys = Object.keys(arg); + const propSetters = this[PROP_SETTERS$8]; + const allKeys = this[ALL_KEYS$8]; + // don't accept unknown props + for (const key of argKeys) { + if (!(key in propSetters)) { + throwNoProperty$8(structure, key); } - } else if (arg && typeof(arg) === 'object') { - let found = 0; - for (const key of memberKeys) { + } + // checking each name so that we would see inenumerable initializers as well + let normalCount = 0; + let normalFound = 0; + let normalMissing = 0; + let specialFound = 0; + for (const key of allKeys) { + const set = propSetters[key]; + if (set.special) { if (key in arg) { - found++; + specialFound++; + } + } else { + normalCount++; + if (key in arg) { + normalFound++; + } else if (set.required) { + normalMissing++; } } - if (found > 1) { - throwMultipleUnionInitializers$7(structure); + } + if (normalMissing !== 0 && specialFound === 0) { + const missing = allKeys.filter(k => propSetters[k].required && !(k in arg)); + throwMissingInitializers$8(structure, missing); + } + if (specialFound + normalFound > argKeys.length) { + // some props aren't enumerable + for (const key of allKeys) { + if (key in arg) { + if (!argKeys.includes(key)) { + argKeys.push(key); + } + } } - if (propApplier.call(this, arg) === 0 && !hasDefaultMember) { - throwMissingUnionInitializer$7(structure, arg, exclusion); + } + // apply default values unless all properties are initialized + if (normalFound < normalCount && specialFound === 0) { + if (template) { + if (template[MEMORY$8]) { + this[COPIER$8](template); + } + this[POINTER_VISITOR$8]?.(copyPointer$8, { vivificate: true, source: template }); } - } else if (arg !== undefined) { - throwInvalidInitializer$7(structure, 'object with a single property', arg); } + for (const key of argKeys) { + const set = propSetters[key]; + set.call(this, arg[key]); + } + return argKeys.length; }; - // non-tagged union as marked as not having pointers--if there're actually - // members with pointers, we need to disable them - const pointerMembers = members.filter(m => m.structure.hasPointer); - const hasInaccessiblePointer = !hasPointer && (pointerMembers.length > 0); - const modifier = (hasInaccessiblePointer && !env.comptime) - ? function() { - // make pointer access throw - this[POINTER_VISITOR$7](disablePointer$7, { vivificate: true }); +} + +function needSlots$8(members) { + for (const { type } of members) { + switch (type) { + case MemberType$8.Object: + case MemberType$8.Comptime: + case MemberType$8.Type: + case MemberType$8.Literal: + return true; } - : undefined; - const constructor = structure.constructor = createConstructor$7(structure, { modifier, initializer }, env); - const fieldDescriptor = (isTagged) - ? { - // for tagged union, only the active field - get() { return [ getActiveField.call(this) ] } + } + return false; +} + +function getSelf$8() { + return this; +} + +function useAllStructureTypes$8() { + usePrimitive$8(); + useArray$8(); + useStruct$8(); + useExternStruct$8(); + usePackedStruct$8(); + useArgStruct$8(); + useExternUnion$8(); + useBareUnion$8(); + useTaggedUnion$8(); + useErrorUnion$8(); + useErrorSet$8(); + useEnumeration$8(); + useOptional$8(); + usePointer$8(); + useSlice$8(); + useVector$8(); + useOpaque$8(); +} + +let ObjectCache$8 = class ObjectCache { + [0] = null; + [1] = null; + + find(dv, writable) { + const key = (writable) ? 0 : 1; + const map = this[key]; + return map?.get(dv); + } + + save(dv, writable, object) { + const key = (writable) ? 0 : 1; + let map = this[key]; + if (!map) { + map = this[key] = new WeakMap(); } - : { - // for bare and extern union, all members are included - value: valueMembers.map(m => m.name) - }; - const isChildActive = (isTagged) - ? function(child) { - const name = getActiveField.call(this); - const active = memberValueGetters[name].call(this); - return child === active; + map.set(dv, object); + return object; + } +}; + +let currentGlobalSet; +let currentErrorClass; + +function defineErrorSet$8(structure, env) { + const { + name, + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + if (!currentErrorClass) { + currentErrorClass = class ZigError extends ZigErrorBase {}; + currentGlobalSet = defineErrorSet$8({ ...structure, name: 'anyerror' }, env); + } + if (currentGlobalSet && name === 'anyerror') { + structure.constructor = currentGlobalSet; + structure.typedArray = getTypedArrayClass$8(member); + return currentGlobalSet; + } + const errorClass = currentErrorClass; + const { get, set } = getDescriptor$8(member, env); + const expected = [ 'string', 'number' ]; + const propApplier = createPropertyApplier$8(structure); + const initializer = function(arg) { + if (arg instanceof constructor[CLASS]) { + set.call(this, arg); + } else if (arg && typeof(arg) === 'object' && !isErrorJSON(arg)) { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$8(structure, expected, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); } - : never$7; - const hasAnyPointer = hasPointer || hasInaccessiblePointer; - const hasObject = !!members.find(m => m.type === MemberType$7.Object); + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'number' || typeof(arg) === 'string') { + return constructor[arg]; + } else if (arg instanceof constructor[CLASS]) { + return constructor[Number(arg)]; + } else if (isErrorJSON(arg)) { + return constructor[`Error: ${arg.error}`]; + } else if (!getDataView$8(structure, arg, env)) { + throwInvalidInitializer$8(structure, expected, arg); + } else { + return false; + } + }; + // items are inserted when static members get attached in static.js + const constructor = structure.constructor = createConstructor$8(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass$8(member); const instanceDescriptors = { - $: { get: getSelf$7, set: initializer, configurable: true }, - dataView: getDataViewDescriptor$7(structure), - base64: getBase64Descriptor$7(structure), - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - ...memberDescriptors, - [Symbol.iterator]: { value: getUnionIterator$7 }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [TAG$7]: isTagged && { get: getSelector, configurable: true }, - [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, - [POINTER_VISITOR$7]: hasAnyPointer && { value: getPointerVisitor$f(structure, { isChildActive }) }, - [PROP_GETTERS$7]: { value: memberValueGetters }, - [NORMALIZER$7]: { value: normalizeUnion$7 }, - [PROPS$7]: fieldDescriptor, - }; + $: { get, set }, + dataView: getDataViewDescriptor$8(structure), + base64: getBase64Descriptor$8(structure), + typedArray: typedArray && getTypedArrayDescriptor$8(structure), + valueOf: { value: getValueOf$8 }, + toJSON: { value: convertToJSON$8 }, + delete: { value: getDestructor$8(env) }, + [COPIER$8]: { value: getMemoryCopier$8(byteSize) }, + [NORMALIZER$8]: { value: get }, + }; const staticDescriptors = { - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, + [ALIGN$8]: { value: align }, + [SIZE$8]: { value: byteSize }, + [CLASS]: { value: errorClass }, + // the PROPS array is normally set in static.js; it needs to be set here for anyerror + // so we can add names to it as error sets are defined + [PROPS$8]: (name === 'anyerror') ? { value: [] } : undefined, }; - attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); - // replace regular setters with ones that change the active field - const setters = constructor.prototype[PROP_SETTERS$7]; - for (const [ name, init ] of Object.entries(memberInitializers)) { - if (init) { - setters[name] = init; + return attachDescriptors$8(constructor, instanceDescriptors, staticDescriptors); +} + +function isErrorJSON(arg) { + return typeof(arg) === 'object' && typeof(arg.error) === 'string' && Object.keys(arg).length === 1 ; +} + +class ZigErrorBase extends Error { + constructor(name, number) { + super(deanimalizeErrorName(name)); + this.number = number; + } + + [Symbol.toPrimitive](hint) { + if (hint === 'string') { + return Error.prototype.toString.call(this, hint); + } else { + return this.number; + } + } + + toJSON() { + return { error: this.message }; + } +} + +function throwNoInitializer$8(structure) { + const { name } = structure; + throw new TypeError(`An initializer must be provided to the constructor of ${name}, even when the intended value is undefined`); +} + +function throwBufferSizeMismatch$8(structure, dv, target = null) { + const { name, type, byteSize } = structure; + const actual = dv.byteLength; + const s = (byteSize !== 1) ? 's' : ''; + if (type === StructureType$8.Slice && !target) { + throw new TypeError(`${name} has elements that are ${byteSize} byte${s} in length, received ${actual}`); + } else { + const total = (type === StructureType$8.Slice) ? target.length * byteSize : byteSize; + throw new TypeError(`${name} has ${total} byte${s}, received ${actual}`); + } +} + +function throwBufferExpected$8(structure) { + const { type, byteSize, typedArray } = structure; + const s = (byteSize !== 1) ? 's' : ''; + const acceptable = [ 'ArrayBuffer', 'DataView' ].map(addArticle$8); + if (typedArray) { + acceptable.push(addArticle$8(typedArray.name)); + } + if (type === StructureType$8.Slice) { + throw new TypeError(`Expecting ${formatList$8(acceptable)} that can accommodate items ${byteSize} byte${s} in length`); + } else { + throw new TypeError(`Expecting ${formatList$8(acceptable)} that is ${byteSize} byte${s} in length`); + } +} + +function throwEnumExpected$8(structure, arg) { + const { name } = structure; + if (typeof(arg) === 'number' || typeof(arg) === 'bigint') { + throw new TypeError(`Value given does not correspond to an item of enum ${name}: ${arg}`); + } else { + throw new TypeError(`Enum item of the type ${name} expected, received ${arg}`); + } +} + +function throwErrorExpected$8(structure, arg) { + const { name } = structure; + const type = typeof(arg); + if (type === 'string' || type === 'number' || isErrorJSON(arg)) { + if (isErrorJSON(arg)) { + arg = `{ error: ${JSON.stringify(arg.error)} }`; + } + throw new TypeError(`Error ${type} does not corresponds to any error in error set ${name}: ${arg}`); + } else { + throw new TypeError(`Error of the type ${name} expected, received ${arg}`); + } +} + +function throwNotInErrorSet$8(structure) { + const { name } = structure; + throw new TypeError(`Error given is not a part of error set ${name}`); +} + +function throwMultipleUnionInitializers$8(structure) { + const { name } = structure; + throw new TypeError(`Only one property of ${name} can be given a value`); +} + +function throwInactiveUnionProperty$8(structure, name, currentName) { + throw new TypeError(`Accessing property ${name} when ${currentName} is active`); +} + +function throwMissingUnionInitializer$8(structure, arg, exclusion) { + const { name, instance: { members } } = structure; + const missing = members.slice(0, exclusion ? -1 : undefined).map(m => m.name); + throw new TypeError(`${name} needs an initializer for one of its union properties: ${missing.join(', ')}`); +} + +function throwInvalidInitializer$8(structure, expected, arg) { + const { name } = structure; + const acceptable = []; + if (Array.isArray(expected)) { + for (const type of expected) { + acceptable.push(addArticle$8(type)); } + } else { + acceptable.push(addArticle$8(expected)); } + const received = getDescription$8(arg); + throw new TypeError(`${name} expects ${formatList$8(acceptable)} as argument, received ${received}`); } -function normalizeUnion$7(cb, options) { - const object = {}; - for (const [ name, value ] of getUnionEntries$7.call(this, options)) { - object[name] = cb(value); + +function throwInvalidArrayInitializer$8(structure, arg, shapeless = false) { + const { instance: { members: [ member ] }, type, typedArray } = structure; + const acceptable = []; + const primitive = getPrimitiveType$8(member); + if (primitive) { + let object; + switch (member.structure?.type) { + case StructureType$8.Enumeration: object = 'enum item'; break; + case StructureType$8.ErrorSet: object = 'error'; break; + default: object = primitive; + } + acceptable.push(`array of ${object}s`); + } else { + acceptable.push(`array of objects`); } - return object; + if (typedArray) { + acceptable.push(typedArray.name); + } + if (type === StructureType$8.Slice && shapeless) { + acceptable.push(`length`); + } + throwInvalidInitializer$8(structure, acceptable.join(' or '), arg); } -function getUnionEntries$7(options) { - return { - [Symbol.iterator]: getUnionEntriesIterator$7.bind(this, options), - length: this[PROPS$7].length, - }; +function throwArrayLengthMismatch$8(structure, target, arg) { + const { name, length, instance: { members: [ member ] } } = structure; + const { structure: { constructor: elementConstructor} } = member; + const { length: argLength, constructor: argConstructor } = arg; + // get length from object whech it's a slice + const actualLength = target?.length ?? length; + const s = (actualLength !== 1) ? 's' : ''; + let received; + if (argConstructor === elementConstructor) { + received = `only a single one`; + } else if (argConstructor.child === elementConstructor) { + received = `a slice/array that has ${argLength}`; + } else { + received = `${argLength} initializer${argLength > 1 ? 's' : ''}`; + } + throw new TypeError(`${name} has ${actualLength} element${s}, received ${received}`); } -function getUnionIterator$7(options) { - const entries = getUnionEntries$7.call(this, options); - return entries[Symbol.iterator](); +function throwMissingInitializers$8(structure, missing) { + const { name } = structure; + throw new TypeError(`Missing initializers for ${name}: ${missing.join(', ')}`); } -function getUnionEntriesIterator$7(options) { - const self = this; - const props = this[PROPS$7]; - const getters = this[PROP_GETTERS$7]; - let index = 0; - return { - next() { - let value, done; - if (index < props.length) { - const current = props[index++]; - // get value of prop with no check - value = [ current, handleError$7(() => getters[current].call(self), options) ]; - done = false; - } else { - done = true; - } - return { value, done }; - }, - }; +function throwNoProperty$8(structure, propName) { + const { name, instance: { members } } = structure; + const member = members.find(m => m.name === propName); + if (member) { + throw new TypeError(`Comptime value cannot be changed: ${propName}`); + } else { + throw new TypeError(`${name} does not have a property with that name: ${propName}`); + } } -function defineVector$7(structure, env) { - const { - length, - byteSize, - align, - instance: { members: [ member ] }, - } = structure; - const { bitSize: elementBitSize, structure: elementStructure } = member; - const elementDescriptors = {}; - for (let i = 0, bitOffset = 0; i < length; i++, bitOffset += elementBitSize) { - const { get, set } = getDescriptor$7({ ...member, bitOffset }, env); - elementDescriptors[i] = { get, set, configurable: true }; +function throwArgumentCountMismatch$8(structure, actual) { + const { name, instance: { members } } = structure; + const argCount = members.length - 1; + const s = (argCount !== 1) ? 's' : ''; + throw new Error(`${name} expects ${argCount} argument${s}, received ${actual}`); +} + +function rethrowArgumentError$8(structure, index, err) { + const { name, instance: { members } } = structure; + // Zig currently does not provide the argument name + const argName = `args[${index}]`; + const argCount = members.length - 1; + const prefix = (index !== 0) ? '..., ' : ''; + const suffix = (index !== argCount - 1) ? ', ...' : ''; + const argLabel = prefix + argName + suffix; + const newError = new err.constructor(`${name}(${argLabel}): ${err.message}`); + newError.stack = err.stack; + throw newError; +} + +function throwNoCastingToPointer$8(structure) { + throw new TypeError(`Non-slice pointers can only be created with the help of the new operator`); +} + +function throwConstantConstraint$8(structure, pointer) { + const { name: target } = structure; + const { constructor: { name } } = pointer; + throw new TypeError(`Conversion of ${name} to ${target} requires an explicit cast`); +} + +function throwMisplacedSentinel$8(structure, value, index, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}, found at ${index}`); +} + +function throwMissingSentinel$8(structure, value, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}`); +} + +function throwTypeMismatch$8(expected, arg) { + const received = getDescription$8(arg); + throw new TypeError(`Expected ${addArticle$8(expected)}, received ${received}`) +} + +function throwInaccessiblePointer$8() { + throw new TypeError(`Pointers within an untagged union are not accessible`); +} + +function throwNullPointer$8() { + throw new TypeError(`Null pointer`); +} + +function throwInvalidPointerTarget$8(structure, arg) { + const { name } = structure; + let target; + if (arg != null) { + const type = typeof(arg); + const noun = (type === 'object' && arg.constructor !== Object) ? `${arg.constructor.name} object`: type; + const a = article$8(noun); + target = `${a} ${noun}`; + } else { + target = arg + ''; } - const propApplier = createPropertyApplier$7(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$7](arg); - } else if (arg?.[Symbol.iterator]) { - let argLen = arg.length; - if (typeof(argLen) !== 'number') { - arg = [ ...arg ]; - argLen = arg.length; - } - if (argLen !== length) { - throwArrayLengthMismatch$7(structure, this, arg); - } - let i = 0; - for (const value of arg) { - this[PROP_SETTERS$7][i++].call(this, value); - } - } else if (arg && typeof(arg) === 'object') { - if (propApplier.call(this, arg) === 0) { - throwInvalidArrayInitializer$7(structure, arg); - } - } else if (arg !== undefined) { - throwInvalidArrayInitializer$7(structure, arg); - } - }; - const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); - const typedArray = structure.typedArray = getTypedArrayClass$7(member); - const instanceDescriptors = { - ...elementDescriptors, - $: { get: getSelf$7, set: initializer }, - length: { value: length }, - dataView: getDataViewDescriptor$7(structure), - base64: getBase64Descriptor$7(structure), - typedArray: typedArray && getTypedArrayDescriptor$7(structure), - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - entries: { value: getVectorEntries$7 }, - delete: { value: getDestructor$7(structure) }, - [Symbol.iterator]: { value: getVectorIterator$7 }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [NORMALIZER$7]: { value: normalizeVector$7 }, - }; - const staticDescriptors = { - child: { get: () => elementStructure.constructor }, - [COMPAT$7]: { value: getCompatibleTags$7(structure) }, - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, - }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); + throw new TypeError(`${name} cannot point to ${target}`) } -function normalizeVector$7(cb, options) { - const array = []; - for (const [ index, value ] of getVectorEntries$7.call(this, options)) { - array.push(cb(value)); +function throwFixedMemoryTargetRequired$8(structure, arg) { + throw new TypeError(`Pointers in fixed memory cannot point to garbage-collected object`); +} + + +function throwOverflow$8(member, value) { + const typeName = getTypeName$8(member); + throw new TypeError(`${typeName} cannot represent the value given: ${value}`); +} + +function throwOutOfBound$8(member, index) { + const { name } = member; + throw new RangeError(`Index exceeds the size of ${name ?? 'array'}: ${index}`); +} + +function rethrowRangeError$8(member, index, err) { + if (err instanceof RangeError) { + throwOutOfBound$8(member, index); + } else { + throw err; } - return array; } -function getVectorIterator$7() { - const self = this; - const length = this.length; - let index = 0; - return { - next() { - let value, done; - if (index < length) { - const current = index++; - value = self[current]; - done = false; - } else { - done = true; - } - return { value, done }; - }, - }; +function throwNotUndefined$8(member) { + const { name } = member; + throw new RangeError(`Property ${name} can only be undefined`); } -function getVectorEntriesIterator$7() { - const self = this; - const length = this.length; - let index = 0; - return { - next() { - let value, done; - if (index < length) { - const current = index++; - value = [ current, self[current] ]; - done = false; +function throwNotOnByteBoundary$8(member) { + const { name, structure: { name: { struct }} } = member; + throw new TypeError(`Unable to create ${struct} as it is not situated on a byte boundary: ${name}`); +} + +function throwReadOnly$8() { + throw new TypeError(`Unable to modify read-only object`); +} + +function throwReadOnlyTarget$8(structure) { + const { name } = structure; + throw new TypeError(`${name} cannot point to a read-only object`); +} + +function throwAccessingOpaque$8(structure) { + const { name } = structure; + throw new TypeError(`Unable to access opaque structure ${name}`); +} + +function throwCreatingOpaque$8(structure) { + const { name } = structure; + throw new TypeError(`Unable to create instance of ${name}, as it is opaque`); +} + +function warnImplicitArrayCreation$8(structure, arg) { + const created = addArticle$8(structure.typedArray.name); + const source = addArticle$8(arg.constructor.name); + console.warn(`Implicitly creating ${created} from ${source}`); +} + +function deanimalizeErrorName(name) { + // deal with snake_case first + let s = name.replace(/_/g, ' '); + // then camelCase, using a try block in case Unicode regex fails + try { + s = s.replace(/(\p{Uppercase}+)(\p{Lowercase}*)/gu, (m0, m1, m2) => { + if (m1.length === 1) { + return ` ${m1.toLocaleLowerCase()}${m2}`; } else { - done = true; + if (m2) { + const acronym = m1.substring(0, m1.length - 1); + const letter = m1.charAt(m1.length - 1).toLocaleLowerCase(); + return ` ${acronym} ${letter}${m2}`; + } else { + return ` ${m1}`; + } } - return { value, done }; - }, - }; + }).trimStart(); + /* c8 ignore next 2 */ + } catch (err) { + } + return s.charAt(0).toLocaleUpperCase() + s.substring(1); } -function getVectorEntries$7() { - return { - [Symbol.iterator]: getVectorEntriesIterator$7.bind(this), - length: this.length, - }; +function getDescription$8(arg) { + const type = typeof(arg); + let s; + if (type === 'object') { + s = (arg) ? Object.prototype.toString.call(arg) : 'null'; + } else { + s = type; + } + return addArticle$8(s); } -const StructureType$7 = { - Primitive: 0, - Array: 1, - Struct: 2, - ExternStruct: 3, - PackedStruct: 4, - ArgStruct: 5, - ExternUnion: 6, - BareUnion: 7, - TaggedUnion: 8, - ErrorUnion: 9, - ErrorSet: 10, - Enumeration: 11, - Optional: 12, - Pointer: 13, - Slice: 14, - Vector: 15, - Opaque: 16, - Function: 17, -}; - -const factories$n = Array(Object.values(StructureType$7).length); +function addArticle$8(noun) { + return `${article$8(noun)} ${noun}`; +} -function usePrimitive$7() { - factories$n[StructureType$7.Primitive] = definePrimitive$7; +function article$8(noun) { + return /^\W*[aeiou]/i.test(noun) ? 'an' : 'a'; } -function useArray$7() { - factories$n[StructureType$7.Array] = defineArray$7; +function formatList$8(list, conj = 'or') { + const sep = ` ${conj} `; + if (list.length > 2) { + return list.slice(0, -1).join(', ') + sep + list[list.length - 1]; + } else { + return list.join(sep); + } } -function useStruct$7() { - factories$n[StructureType$7.Struct] = defineStructShape$7; +function getBoolAccessor$8(access, member) { + return cacheMethod$8(access, member, () => { + if (isByteAligned$8(member)) { + const { byteSize } = member; + const typeName = getTypeName$8({ type: MemberType$8.Int, bitSize: byteSize * 8 }); + if (access === 'get') { + const get = DataView.prototype[`get${typeName}`]; + return function(offset, littleEndian) { + return !!get.call(this, offset, littleEndian); + }; + } else { + const set = DataView.prototype[`set${typeName}`]; + const T = (byteSize > 4) ? 1n : 1; + const F = (byteSize > 4) ? 0n : 0; + return function(offset, value, littleEndian) { + set.call(this, offset, value ? T : F, littleEndian); + }; + } + } else { + return getExtendedTypeAccessor$8(access, member); + } + }); } -function usePackedStruct$7() { - factories$n[StructureType$7.PackedStruct] = defineStructShape$7; +function getNumericAccessor$8(access, member) { + return cacheMethod$8(access, member, (name) => { + if (DataView.prototype[name]) { + return DataView.prototype[name]; + } else { + return getExtendedTypeAccessor$8(access, member); + } + }); } -function useExternStruct$7() { - factories$n[StructureType$7.ExternStruct] = defineStructShape$7; +const factories$p = {}; + +function useExtendedBool$8() { + factories$p[MemberType$8.Bool] = getExtendedBoolAccessor$8; } -function useArgStruct$7() { - factories$n[StructureType$7.ArgStruct] = defineArgStruct$7; +function useExtendedInt$8() { + factories$p[MemberType$8.Int] = getExtendedIntAccessor$8; } -function useExternUnion$7() { - factories$n[StructureType$7.ExternUnion] = defineUnionShape$7; +function useExtendedUint$8() { + factories$p[MemberType$8.Uint] = getExtendedUintAccessor$8; } -function useBareUnion$7() { - factories$n[StructureType$7.BareUnion] = defineUnionShape$7; +function useExtendedFloat$8() { + factories$p[MemberType$8.Float] = getExtendedFloatAccessor$8; } -function useTaggedUnion$7() { - factories$n[StructureType$7.TaggedUnion] = defineUnionShape$7; +function getExtendedTypeAccessor$8(access, member) { + const f = factories$p[member.type]; + return f(access, member); } -function useErrorUnion$7() { - factories$n[StructureType$7.ErrorUnion] = defineErrorUnion$7; +function getExtendedBoolAccessor$8(access, member) { + const { bitOffset } = member; + const bitPos = bitOffset & 0x07; + const mask = 1 << bitPos; + const get = DataView.prototype.getInt8; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + return !!(n & mask); + }; + } else { + const set = DataView.prototype.setInt8; + return function(offset, value) { + const n = get.call(this, offset); + const b = (value) ? n | mask : n & ~mask; + set.call(this, offset, b); + }; + } } -function useErrorSet$7() { - factories$n[StructureType$7.ErrorSet] = defineErrorSet$7; +function getExtendedIntAccessor$8(access, member) { + if (isByteAligned$8(member)) { + return getAlignedIntAccessor$8(access, member) + } else { + return getUnalignedIntAccessor$8(access, member); + } } -function useEnumeration$7() { - factories$n[StructureType$7.Enumeration] = defineEnumerationShape$7; +function getExtendedUintAccessor$8(access, member) { + if (isByteAligned$8(member)) { + return getAlignedUintAccessor$8(access, member) + } else { + return getUnalignedUintAccessor$8(access, member); + } } -function useOptional$7() { - factories$n[StructureType$7.Optional] = defineOptional$7; +function getExtendedFloatAccessor$8(access, member) { + if (isByteAligned$8(member)) { + return getAlignedFloatAccessor$8(access, member) + } else { + return getUnalignedFloatAccessor$8(access, member); + } } -function usePointer$7() { - factories$n[StructureType$7.Pointer] = definePointer$7; +function getDataView$8(structure, arg, env) { + const { type, byteSize, typedArray } = structure; + let dv; + // not using instanceof just in case we're getting objects created in other contexts + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView') { + dv = arg; + } else if (tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + dv = env.obtainView(arg, 0, arg.byteLength); + } else if (typedArray && tag === typedArray.name || (tag === 'Uint8ClampedArray' && typedArray === Uint8Array)) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else if (tag === 'Uint8Array' && typeof(Buffer) === 'function' && arg instanceof Buffer) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else { + const memory = arg?.[MEMORY$8]; + if (memory) { + const { constructor, instance: { members: [ member ] } } = structure; + if (arg instanceof constructor) { + return memory; + } else if (type === StructureType$8.Array || type === StructureType$8.Slice || type === StructureType$8.Vector) { + const { byteSize: elementSize, structure: { constructor: Child } } = member; + const number = findElements$8(arg, Child); + if (number !== undefined) { + if (type === StructureType$8.Slice || number * elementSize === byteSize) { + return memory; + } else { + throwArrayLengthMismatch$8(structure, null, arg); + } + } + } + } + } + if (dv && byteSize !== undefined) { + checkDataViewSize$8(dv, structure); + } + return dv; } -function useSlice$7() { - factories$n[StructureType$7.Slice] = defineSlice$7; +function checkDataView$8(dv) { + if (dv?.[Symbol.toStringTag] !== 'DataView') { + throwTypeMismatch$8('a DataView', dv); + } + return dv; } -function useVector$7() { - factories$n[StructureType$7.Vector] = defineVector$7; +function checkDataViewSize$8(dv, structure) { + const { byteSize, type } = structure; + const multiple = type === StructureType$8.Slice; + if (multiple ? dv.byteLength % byteSize !== 0 : dv.byteLength !== byteSize) { + throwBufferSizeMismatch$8(structure, dv); + } } -function useOpaque$7() { - factories$n[StructureType$7.Opaque] = defineOpaque$7; +function setDataView$8(dv, structure, copy, handlers) { + const { byteSize, type, sentinel } = structure; + const multiple = type === StructureType$8.Slice; + if (!this[MEMORY$8]) { + const { shapeDefiner } = handlers; + checkDataViewSize$8(dv, structure); + const len = dv.byteLength / byteSize; + const source = { [MEMORY$8]: dv }; + sentinel?.validateData(source, len); + shapeDefiner.call(this, copy ? null : dv, len); + if (copy) { + this[COPIER$8](source); + } + } else { + const byteLength = multiple ? byteSize * this.length : byteSize; + if (dv.byteLength !== byteLength) { + throwBufferSizeMismatch$8(structure, dv, this); + } + const source = { [MEMORY$8]: dv }; + sentinel?.validateData(source, this.length); + this[COPIER$8](source); + } } -function getStructureFactory(type) { - const f = factories$n[type]; - return f; +function findElements$8(arg, Child) { + // casting to a array/slice + const { constructor: Arg } = arg; + if (Arg === Child) { + // matching object + return 1; + } else if (Arg.child === Child) { + // matching slice/array + return arg.length; + } } -function flagMemberUsage(member, features) { - const { type } = member; - switch (type) { - case MemberType$7.Bool: - features.useBool = true; - if (!isByteAligned$7(member)) { - features.useExtendedBool = true; - } - break; - case MemberType$7.Int: - features.useInt = true; - if(!isByteAligned$7(member) || !hasStandardIntSize(member)) { - features.useExtendedInt = true; - } - break; - case MemberType$7.Uint: - features.useUint = true; - if(!isByteAligned$7(member) || !hasStandardIntSize(member)) { - features.useExtendedUint = true; - } - break; - case MemberType$7.Float: - features.useFloat = true; - if (!isByteAligned$7(member) || !hasStandardFloatSize(member)) { - features.useExtendedFloat = true; - } - break; - case MemberType$7.EnumerationItem: { - features.useEnumerationItem = true; - const { type, structure } = member.structure.instance.members[0]; - flagMemberUsage({ ...member, type, structure }, features); - } break; - case MemberType$7.Error: - features.useError = true; - break; - case MemberType$7.Object: - features.useObject = true; - break; - case MemberType$7.Void: - features.useVoid = true; - break; - case MemberType$7.Null: - features.useNull = true; - break; - case MemberType$7.Undefined: - features.useUndefined = true; - break; - case MemberType$7.Type: - features.useType = true; - break; - case MemberType$7.Comptime: - features.useComptime = true; - break; - case MemberType$7.Static: - features.useStatic = true; - break; - case MemberType$7.Literal: - features.useLiteral = true; - break; +function requireDataView$8(structure, arg, env) { + const dv = getDataView$8(structure, arg, env); + if (!dv) { + throwBufferExpected$8(structure); } + return dv; } -function flagStructureUsage(structure, features) { - const { type } = structure; - const [ name ] = Object.entries(StructureType$7).find(a => a[1] === type); - features[`use${name}`] = true; - for (const members of [ structure.instance.members, structure.static.members ]) { - for (const member of members) { - flagMemberUsage(member, features); +function getTypedArrayClass$8(member) { + const { type: memberType, byteSize } = member; + if (memberType === MemberType$8.Int) { + switch (byteSize) { + case 1: return Int8Array; + case 2: return Int16Array; + case 4: return Int32Array; + case 8: return BigInt64Array; + } + } else if (memberType === MemberType$8.Uint) { + switch (byteSize) { + case 1: return Uint8Array; + case 2: return Uint16Array; + case 4: return Uint32Array; + case 8: return BigUint64Array; } + } else if (memberType === MemberType$8.Float) { + switch (byteSize) { + case 4: return Float32Array; + case 8: return Float64Array; + } + } else if (memberType === MemberType$8.Object) { + return member.structure.typedArray; } - switch (type) { - case StructureType$7.Pointer: - // pointer structure has Object member, while needing support for Uint - features.useUint = true; - break; - case StructureType$7.Enumeration: - // enum structure has Int/Uint member, while needing support for EnumerationItem - features.useEnumerationItem = true; - break; - case StructureType$7.ErrorSet: - // error set structures have Uint member, while needing support for Error - features.useError = true; - break; - } + return null; } -function getFeaturesUsed(structures) { - const features = {}; - for (const structure of structures) { - flagStructureUsage(structure, features); - } - return Object.keys(features); +function isTypedArray$8(arg, TypedArray) { + const tag = arg?.[Symbol.toStringTag]; + return (!!TypedArray && tag === TypedArray.name); } -function defineProperties$7(object, descriptors) { - for (const [ name, descriptor ] of Object.entries(descriptors)) { - if (descriptor) { - const { - set, - get, - value, - enumerable, - configurable = true, - writable = true, - } = descriptor; - Object.defineProperty(object, name, (get) - ? { get, set, configurable, enumerable } - : { value, configurable, enumerable, writable } - ); +function isCompatible$8(arg, constructor) { + const tags = constructor[COMPAT$8]; + if (tags) { + const tag = arg?.[Symbol.toStringTag]; + if (tags.includes(tag)) { + return true; } } - for (const symbol of Object.getOwnPropertySymbols(descriptors)) { - const descriptor = descriptors[symbol]; - if (descriptor) { - Object.defineProperty(object, symbol, descriptor); + if (constructor.child) { + if (findElements$8(arg, constructor.child) !== undefined) { + return true; } } + return false; } -function attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors) { - // create prototype for read-only objects - const prototypeRO = {}; - Object.setPrototypeOf(prototypeRO, constructor.prototype); - const instanceDescriptorsRO = {}; - const propSetters = {}; - for (const [ name, descriptor ] of Object.entries(instanceDescriptors)) { - if (descriptor?.set) { - instanceDescriptorsRO[name] = { ...descriptor, set: throwReadOnly$7 }; - // save the setters so we can initialize read-only objects - if (name !== '$') { - propSetters[name] = descriptor.set; - } - } else if (name === 'set') { - instanceDescriptorsRO[name] = { value: throwReadOnly$7, configurable: true, writable: true }; +function getCompatibleTags$8(structure) { + const { typedArray } = structure; + const tags = []; + if (typedArray) { + tags.push(typedArray.name); + tags.push('DataView'); + if (typedArray === Uint8Array || typedArray === Int8Array) { + tags.push('Uint8ClampedArray'); + tags.push('ArrayBuffer'); + tags.push('SharedArrayBuffer'); } } - const vivificate = instanceDescriptors[VIVIFICATOR$7]?.value; - const vivificateDescriptor = { - // vivificate child objects as read-only too - value: function(slot) { - return vivificate.call(this, slot, false); - } - }; - const { get, set } = instanceDescriptors.$; - defineProperties$7(constructor.prototype, { - [CONST$7]: { value: false }, - [ALL_KEYS$7]: { value: Object.keys(propSetters) }, - [SETTER$7]: { value: set }, - [GETTER$7]: { value: get }, - [PROP_SETTERS$7]: { value: propSetters }, - ...instanceDescriptors, - }); - defineProperties$7(constructor, { - [CONST_PROTOTYPE$7]: { value: prototypeRO }, - ...staticDescriptors, - }); - defineProperties$7(prototypeRO, { - constructor: { value: constructor, configurable: true }, - [CONST$7]: { value: true }, - [SETTER$7]: { value: throwReadOnly$7 }, - [VIVIFICATOR$7]: vivificate && vivificateDescriptor, - ...instanceDescriptorsRO, - }); - return constructor; + return tags; } -function createConstructor$7(structure, handlers, env) { - const { - byteSize, - align, - instance: { members, template }, - hasPointer, - } = structure; - const { - modifier, - initializer, - finalizer, - alternateCaster, - shapeDefiner, - } = handlers; - const hasSlots = needSlots$7(members); - // comptime fields are stored in the instance template's slots - let comptimeFieldSlots; - if (template?.[SLOTS$7]) { - const comptimeMembers = members.filter(m => isReadOnly$7(m.type)); - if (comptimeMembers.length > 0) { - comptimeFieldSlots = comptimeMembers.map(m => m.slot); - } +function isBuffer$8(arg, typedArray) { + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView' || tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + return true; + } else if (typedArray && tag === typedArray.name) { + return true; + } else { + return false; } - const cache = new ObjectCache$7(); - const constructor = function(arg, options = {}) { - const { - writable = true, - fixed = false, - } = options; - const creating = this instanceof constructor; - let self, dv; - if (creating) { - if (arguments.length === 0) { - throwNoInitializer$7(structure); - } - self = this; - if (hasSlots) { - self[SLOTS$7] = {}; - } - if (shapeDefiner) { - // provided by defineSlice(); the slice is different from other structures as it does not have - // a fixed size; memory is allocated by the slice initializer based on the argument given - initializer.call(self, arg, fixed); - dv = self[MEMORY$7]; +} + +function getTypeName$8(member) { + const { type, bitSize, byteSize } = member; + if (type === MemberType$8.Int) { + return `${bitSize <= 32 ? '' : 'Big' }Int${bitSize}`; + } else if (type === MemberType$8.Uint) { + return `${bitSize <= 32 ? '' : 'Big' }Uint${bitSize}`; + } else if (type === MemberType$8.Float) { + return `Float${bitSize}`; + } else if (type === MemberType$8.Bool) { + const boolSize = (byteSize !== undefined) ? byteSize * 8 : 1; + return `Bool${boolSize}`; + } else if (type === MemberType$8.Void) { + return `Null`; + } +} + +function getBigIntDescriptor$8(bitSize) { + const getWord = DataView.prototype.getBigUint64; + const setWord = DataView.prototype.setBigUint64; + const wordCount = Math.ceil(bitSize / 64); + return { + get: function(offset, littleEndian) { + let n = 0n; + if (littleEndian) { + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; + } } else { - self[MEMORY$7] = dv = env.allocateMemory(byteSize, align, fixed); - } - } else { - if (alternateCaster) { - // casting from number, string, etc. - self = alternateCaster.call(this, arg, options); - if (self !== false) { - return self; + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; } } - // look for buffer - dv = requireDataView$7(structure, arg, env); - if (self = cache.find(dv, writable)) { - return self; - } - self = Object.create(writable ? constructor.prototype : constructor[CONST_PROTOTYPE$7]); - if (shapeDefiner) { - setDataView$7.call(self, dv, structure, false, { shapeDefiner }); + return n; + }, + set: function(offset, value, littleEndian) { + let n = value; + const mask = 0xFFFFFFFFFFFFFFFFn; + if (littleEndian) { + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } } else { - self[MEMORY$7] = dv; - } - if (hasSlots) { - self[SLOTS$7] = {}; - if (hasPointer && arg instanceof constructor) { - // copy pointer from other object - self[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); - } + n <<= BigInt(wordCount * 64 - bitSize); + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } } + return n; + }, + }; +} + +function getAlignedIntAccessor$8(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$8({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const signMask = (bitSize <= 32) ? 2 ** (bitSize - 1) : 2n ** BigInt(bitSize - 1); + const valueMask = (bitSize <= 32) ? signMask - 1 : signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$8(bitSize); + const signMask = 2n ** BigInt(bitSize - 1); + const valueMask = signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; } - if (comptimeFieldSlots) { - for (const slot of comptimeFieldSlots) { - self[SLOTS$7][slot] = template[SLOTS$7][slot]; - } + } +} + +function getAlignedUintAccessor$8(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$8({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const valueMask = (bitSize <= 32) ? (2 ** bitSize) - 1 : (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; } - if (modifier) { - modifier.call(self); + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$8(bitSize); + const valueMask = (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; } - if (creating) { - // initialize object unless it's been done already - if (!shapeDefiner) { - initializer.call(self, arg); - } - if (!writable) { - // create object with read-only prototype - self = Object.assign(Object.create(constructor[CONST_PROTOTYPE$7]), self); - } + } +} + +function getUnalignedIntAccessor$8(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + // sub-8-bit numbers have real use cases + const signMask = 2 ** (bitSize - 1); + const valueMask = signMask - 1; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return (s & valueMask) - (s & signMask); + }; + } else { + const outsideMask = 0xFF ^ ((valueMask | signMask) << bitPos); + return function(offset, value) { + let b = get.call(this, offset); + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + b = (b & outsideMask) | (n << bitPos); + set.call(this, offset, b); + }; } - if (finalizer) { - self = finalizer.call(self); + } + return getUnalignedNumericAccessor$8(access, member); +} + +function getUnalignedUintAccessor$8(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + const valueMask = (2 ** bitSize - 1); + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return s & valueMask; + }; + } else { + const outsideMask = 0xFF ^ (valueMask << bitPos); + return function(offset, value) { + const n = get.call(this, offset); + const b = (n & outsideMask) | ((value & valueMask) << bitPos); + set.call(this, offset, b); + }; } - return cache.save(dv, writable, self); - }; - return constructor; + } + return getUnalignedNumericAccessor$8(access, member); } -function createPropertyApplier$7(structure) { - const { instance: { template } } = structure; - return function(arg) { - const argKeys = Object.keys(arg); - const propSetters = this[PROP_SETTERS$7]; - const allKeys = this[ALL_KEYS$7]; - // don't accept unknown props - for (const key of argKeys) { - if (!(key in propSetters)) { - throwNoProperty$7(structure, key); +function getAlignedFloatAccessor$8(access, member) { + const { bitSize, byteSize } = member; + if (bitSize === 16) { + const buf = new DataView(new ArrayBuffer(4)); + const set = DataView.prototype.setUint16; + const get = DataView.prototype.getUint16; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >>> 15; + const exp = (n & 0x7C00) >> 10; + const frac = n & 0x03FF; + if (exp === 0) { + return (sign) ? -0 : 0; + } else if (exp === 0x1F) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } + } + const n32 = (sign << 31) | ((exp - 15 + 127) << 23) | (frac << 13); + buf.setUint32(0, n32, littleEndian); + return buf.getFloat32(0, littleEndian); + } + } else { + return function(offset, value, littleEndian) { + buf.setFloat32(0, value, littleEndian); + const n = buf.getUint32(0, littleEndian); + const sign = n >>> 31; + const exp = (n & 0x7F800000) >> 23; + const frac = n & 0x007FFFFF; + const exp16 = (exp - 127 + 15); + let n16; + if (exp === 0) { + n16 = sign << 15; + } else if (exp === 0xFF) { + n16 = sign << 15 | 0x1F << 10 | (frac ? 1 : 0); + } else if (exp16 >= 31) { + n16 = sign << 15 | 0x1F << 10; + } else { + n16 = sign << 15 | exp16 << 10 | (frac >> 13); + } + set.call(this, offset, n16, littleEndian); } } - // checking each name so that we would see inenumerable initializers as well - let normalCount = 0; - let normalFound = 0; - let normalMissing = 0; - let specialFound = 0; - for (const key of allKeys) { - const set = propSetters[key]; - if (set.special) { - if (key in arg) { - specialFound++; + } else if (bitSize === 80) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + return w1 | w2 << 32n | w3 << 64n; + }; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 79n; + const exp = (n & 0x7FFF0000000000000000n) >> 64n; + const frac = n & 0x00007FFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } } - } else { - normalCount++; - if (key in arg) { - normalFound++; - } else if (set.required) { - normalMissing++; + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 11n) + BigInt((frac & (2n**11n - 1n)) >= 2n**10n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); + } + } else { + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n80; + if (exp === 0n) { + n80 = sign << 79n | (frac << 11n); + } else if (exp === 0x07FFn) { + n80 = sign << 79n | 0x7FFFn << 64n | (frac ? 0x00002000000000000000n : 0n) | 0x00008000000000000000n; + // ^ bit 61 ^ bit 63 + } else { + n80 = sign << 79n | (exp - 1023n + 16383n) << 64n | (frac << 11n) | 0x00008000000000000000n; + } + set.call(this, offset, n80, littleEndian); } } - if (normalMissing !== 0 && specialFound === 0) { - const missing = allKeys.filter(k => propSetters[k].required && !(k in arg)); - throwMissingInitializers$7(structure, missing); - } - if (specialFound + normalFound > argKeys.length) { - // some props aren't enumerable - for (const key of allKeys) { - if (key in arg) { - if (!argKeys.includes(key)) { - argKeys.push(key); + } else if (bitSize === 128) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + const w4 = BigInt(this.getUint32(offset + (littleEndian ? 12 : byteSize - 16), littleEndian)); + return w1 | w2 << 32n | w3 << 64n | w4 << 96n; + }; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + const w4 = (value >> 96n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + this.setUint32(offset + (littleEndian ? 12 : byteSize - 16), Number(w4), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 127n; + const exp = (n & 0x7FFF0000000000000000000000000000n) >> 112n; + const frac = n & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; } } + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; + } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 60n) + BigInt((frac & (2n**60n - 1n)) >= 2n**59n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); } - } - // apply default values unless all properties are initialized - if (normalFound < normalCount && specialFound === 0) { - if (template) { - if (template[MEMORY$7]) { - this[COPIER$7](template); + } else { + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n128; + if (exp === 0n) { + n128 = sign << 127n | (frac << 60n); + } else if (exp === 0x07FFn) { + n128 = sign << 127n | 0x7FFFn << 112n | (frac ? 1n : 0n); + } else { + n128 = sign << 127n | (exp - 1023n + 16383n) << 112n | (frac << 60n); } - this[POINTER_VISITOR$7]?.(copyPointer$7, { vivificate: true, source: template }); + set.call(this, offset, n128, littleEndian); } } - for (const key of argKeys) { - const set = propSetters[key]; - set.call(this, arg[key]); - } - return argKeys.length; - }; + } } -function needSlots$7(members) { - for (const { type } of members) { - switch (type) { - case MemberType$7.Object: - case MemberType$7.Comptime: - case MemberType$7.Type: - case MemberType$7.Literal: - return true; - } - } - return false; +function getUnalignedFloatAccessor$8(access, member) { + return getUnalignedNumericAccessor$8(access, member); } -function getSelf$7() { - return this; +function getUnalignedNumericAccessor$8(access, member) { + // pathological usage scenario--handle it anyway by copying the bitSize into a + // temporary buffer, bit-aligning the data + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + const byteSize = [ 1, 2, 4, 8 ].find(b => b * 8 >= bitSize) ?? Math.ceil(bitSize / 64) * 64; + const buf = new DataView(new ArrayBuffer(byteSize)); + if (access === 'get') { + const getAligned = getNumericAccessor$8('get', { ...member, byteSize }); + const copyBits = getBitAlignFunction$8(bitPos, bitSize, true); + return function(offset, littleEndian) { + copyBits(buf, this, offset); + return getAligned.call(buf, 0, littleEndian); + }; + } else { + const setAligned = getNumericAccessor$8('set', { ...member, byteSize }); + const applyBits = getBitAlignFunction$8(bitPos, bitSize, false); + return function(offset, value, littleEndian) { + setAligned.call(buf, 0, value, littleEndian); + applyBits(this, buf, offset); + }; + } } -function findAllObjects(structures, SLOTS) { - const list = []; - const found = new Map(); - const find = (object) => { - if (!object || found.get(object)) { - return; +const methodCache$8 = {}; + +function cacheMethod$8(access, member, cb) { + const { type, bitOffset, bitSize, structure } = member; + const bitPos = bitOffset & 0x07; + const typeName = getTypeName$8(member); + const suffix = isByteAligned$8(member) ? `` : `Bit${bitPos}`; + const isInt = type === MemberType$8.Int || type === MemberType$8.Uint; + let name = `${access}${typeName}${suffix}`; + let isSize = false, originalName = name; + if (isInt && bitSize === 64) { + const zigTypeName = structure?.name; + if (zigTypeName === 'usize' || zigTypeName === 'isize') { + name += 'Size'; + isSize = true; } - found.set(object, true); - list.push(object); - if (object[SLOTS]) { - for (const child of Object.values(object[SLOTS])) { - find(child); - } + } + let fn = methodCache$8[name]; + if (!fn) { + if (isInt && access === 'set') { + // add auto-conversion between number and bigint + const Primitive = getPrimitiveClass$8(member); + const set = cb(originalName); + fn = function(offset, value, littleEndian) { + set.call(this, offset, Primitive(value), littleEndian); + }; + } else if (isSize && access === 'get') { + // use number instead of bigint where possible + const get = cb(originalName); + const min = BigInt(Number.MIN_SAFE_INTEGER); + const max = BigInt(Number.MAX_SAFE_INTEGER); + fn = function(offset, littleEndian) { + const value = get.call(this, offset, littleEndian); + if (min <= value && value <= max) { + return Number(value); + } else { + return value; + } + }; + } else { + fn = cb(name); } - }; - for (const structure of structures) { - find(structure.instance.template); - find(structure.static.template); + if (fn && fn.name !== name) { + Object.defineProperty(fn, 'name', { value: name, configurable: true, writable: false }); + } + methodCache$8[name] = fn; } - return list; + return fn; } -function useAllStructureTypes$7() { - usePrimitive$7(); - useArray$7(); - useStruct$7(); - useExternStruct$7(); - usePackedStruct$7(); - useArgStruct$7(); - useExternUnion$7(); - useBareUnion$7(); - useTaggedUnion$7(); - useErrorUnion$7(); - useErrorSet$7(); - useEnumeration$7(); - useOptional$7(); - usePointer$7(); - useSlice$7(); - useVector$7(); - useOpaque$7(); +function useAllExtendedTypes$8() { + useExtendedBool$8(); + useExtendedInt$8(); + useExtendedUint$8(); + useExtendedFloat$8(); } -let ObjectCache$7 = class ObjectCache { - [0] = null; - [1] = null; +const MemberType$8 = { + Void: 0, + Bool: 1, + Int: 2, + Uint: 3, + Float: 4, + Object: 5, + Type: 6, + Comptime: 7, + Static: 8, + Literal: 9, + Null: 10, + Undefined: 11, +}; - find(dv, writable) { - const key = (writable) ? 0 : 1; - const map = this[key]; - return map?.get(dv); +function isReadOnly$8(type) { + switch (type) { + case MemberType$8.Type: + case MemberType$8.Comptime: + case MemberType$8.Literal: + return true; + default: + return false; } +} - save(dv, writable, object) { - const key = (writable) ? 0 : 1; - let map = this[key]; - if (!map) { - map = this[key] = new WeakMap(); - } - map.set(dv, object); - return object; - } -}; +const factories$o = {}; -function definePrimitive$7(structure, env) { - const { - byteSize, - align, - instance: { members: [ member ] }, - } = structure; - const { get, set } = getDescriptor$7(member, env); - const propApplier = createPropertyApplier$7(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER$7](arg); - } else { - if (arg && typeof(arg) === 'object') { - if (propApplier.call(this, arg) === 0) { - const type = getPrimitiveType$7(member); - throwInvalidInitializer$7(structure, type, arg); - } - } else if (arg !== undefined) { - set.call(this, arg); - } - } - }; - const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); - const typedArray = structure.typedArray = getTypedArrayClass$7(member); - const instanceDescriptors = { - $: { get, set }, - dataView: getDataViewDescriptor$7(structure), - base64: getBase64Descriptor$7(structure), - typedArray: typedArray && getTypedArrayDescriptor$7(structure), - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - delete: { value: getDestructor$7(env) }, - [Symbol.toPrimitive]: { value: get }, - [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, - [NORMALIZER$7]: { value: normalizeValue$7 }, - }; - const staticDescriptors = { - [COMPAT$7]: { value: getCompatibleTags$7(structure) }, - [ALIGN$7]: { value: align }, - [SIZE$7]: { value: byteSize }, - }; - return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); -} -function getIntRange$7(member) { - const { type, bitSize } = member; - const signed = (type === MemberType$7.Int); - let magBits = (signed) ? bitSize - 1 : bitSize; - if (bitSize <= 32) { - const max = 2 ** magBits - 1; - const min = (signed) ? -(2 ** magBits) : 0; - return { min, max }; - } else { - magBits = BigInt(magBits); - const max = 2n ** magBits - 1n; - const min = (signed) ? -(2n ** magBits) : 0n; - return { min, max }; - } +function useVoid$8() { + factories$o[MemberType$8.Void] = getVoidDescriptor$8; } -function getPrimitiveClass$7({ type, bitSize }) { - if (type === MemberType$7.Int || type === MemberType$7.Uint) { - if (bitSize <= 32) { - return Number; - } else { - return BigInt; - } - } else if (type === MemberType$7.Float) { - return Number; - } else if (type === MemberType$7.Bool) { - return Boolean; - } +function useBool$8() { + factories$o[MemberType$8.Bool] = getBoolDescriptor$8; } -function getPrimitiveType$7(member) { - const Primitive = getPrimitiveClass$7(member); - if (Primitive) { - return typeof(Primitive(0)); - } +function useInt$8() { + factories$o[MemberType$8.Int] = getIntDescriptor$8; } -function throwNoInitializer$7(structure) { - const { name } = structure; - throw new TypeError(`An initializer must be provided to the constructor of ${name}, even when the intended value is undefined`); +function useUint$8() { + factories$o[MemberType$8.Uint] = getUintDescriptor$8; } -function throwBufferSizeMismatch$7(structure, dv, target = null) { - const { name, type, byteSize } = structure; - const actual = dv.byteLength; - const s = (byteSize !== 1) ? 's' : ''; - if (type === StructureType$7.Slice && !target) { - throw new TypeError(`${name} has elements that are ${byteSize} byte${s} in length, received ${actual}`); - } else { - const total = (type === StructureType$7.Slice) ? target.length * byteSize : byteSize; - throw new TypeError(`${name} has ${total} byte${s}, received ${actual}`); - } +function useFloat$8() { + factories$o[MemberType$8.Float] = getFloatDescriptor$8; } -function throwBufferExpected$7(structure) { - const { type, byteSize, typedArray } = structure; - const s = (byteSize !== 1) ? 's' : ''; - const acceptable = [ 'ArrayBuffer', 'DataView' ].map(addArticle$7); - if (typedArray) { - acceptable.push(addArticle$7(typedArray.name)); - } - if (type === StructureType$7.Slice) { - throw new TypeError(`Expecting ${formatList$7(acceptable)} that can accommodate items ${byteSize} byte${s} in length`); - } else { - throw new TypeError(`Expecting ${formatList$7(acceptable)} that is ${byteSize} byte${s} in length`); - } +function useObject$8() { + factories$o[MemberType$8.Object] = getObjectDescriptor$8; } -function throwEnumExpected$7(structure, arg) { - const { name } = structure; - if (typeof(arg) === 'number' || typeof(arg) === 'bigint') { - throw new TypeError(`Value given does not correspond to an item of enum ${name}: ${arg}`); - } else { - throw new TypeError(`Enum item of the type ${name} expected, received ${arg}`); - } +function useType$8() { + factories$o[MemberType$8.Type] = getTypeDescriptor$8; } -function throwErrorExpected$7(structure, arg) { - const { name } = structure; - const type = typeof(arg); - if (type === 'string' || type === 'number') { - throw new TypeError(`Error ${type} does not corresponds to any error in error set ${name}: ${arg}`); - } else { - throw new TypeError(`Error of the type ${name} expected, received ${arg}`); - } +function useComptime$8() { + factories$o[MemberType$8.Comptime] = getComptimeDescriptor$8; } -function throwNotInErrorSet$7(structure) { - const { name } = structure; - throw new TypeError(`Error given is not a part of error set ${name}`); +function useStatic$8() { + factories$o[MemberType$8.Static] = getStaticDescriptor$8; } -function throwMultipleUnionInitializers$7(structure) { - const { name } = structure; - throw new TypeError(`Only one property of ${name} can be given a value`); +function useLiteral$8() { + factories$o[MemberType$8.Literal] = getLiteralDescriptor$8; } -function throwInactiveUnionProperty$7(structure, name, currentName) { - throw new TypeError(`Accessing property ${name} when ${currentName} is active`); +function useNull$8() { + factories$o[MemberType$8.Null] = getNullDescriptor$8; } -function throwMissingUnionInitializer$7(structure, arg, exclusion) { - const { name, instance: { members } } = structure; - const missing = members.slice(0, exclusion ? -1 : undefined).map(m => m.name); - throw new TypeError(`${name} needs an initializer for one of its union properties: ${missing.join(', ')}`); +function useUndefined$8() { + factories$o[MemberType$8.Undefined] = getUndefinedDescriptor$8; } -function throwInvalidInitializer$7(structure, expected, arg) { - const { name } = structure; - const acceptable = []; - if (Array.isArray(expected)) { - for (const type of expected) { - acceptable.push(addArticle$7(type)); - } - } else { - acceptable.push(addArticle$7(expected)); - } - const received = getDescription$7(arg); - throw new TypeError(`${name} expects ${formatList$7(acceptable)} as argument, received ${received}`); +const transformers = {}; + +function useEnumerationTransform() { + transformers[StructureType$8.Enumeration] = transformEnumerationDescriptor; } -function throwInvalidArrayInitializer$7(structure, arg, shapeless = false) { - const { instance: { members: [ member ] }, type, typedArray } = structure; - const acceptable = []; - const primitive = getPrimitiveType$7(member); - if (primitive) { - acceptable.push(`array of ${primitive}s`); - } else if (member.type === MemberType$7.EnumerationItem) { - acceptable.push(`array of enum items`); - } else { - acceptable.push(`array of objects`); - } - if (typedArray) { - acceptable.push(typedArray.name); - } - if (type === StructureType$7.Slice && shapeless) { - acceptable.push(`length`); - } - throwInvalidInitializer$7(structure, acceptable.join(' or '), arg); +function useErrorSetTransform() { + transformers[StructureType$8.ErrorSet] = transformErrorSetDescriptor; } -function throwArrayLengthMismatch$7(structure, target, arg) { - const { name, length, instance: { members: [ member ] } } = structure; - const { structure: { constructor: elementConstructor} } = member; - const { length: argLength, constructor: argConstructor } = arg; - // get length from object whech it's a slice - const actualLength = target?.length ?? length; - const s = (actualLength !== 1) ? 's' : ''; - let received; - if (argConstructor === elementConstructor) { - received = `only a single one`; - } else if (argConstructor.child === elementConstructor) { - received = `a slice/array that has ${argLength}`; - } else { - received = `${argLength} initializer${argLength > 1 ? 's' : ''}`; - } - throw new TypeError(`${name} has ${actualLength} element${s}, received ${received}`); +function isByteAligned$8({ bitOffset, bitSize, byteSize }) { + return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; } -function throwMissingInitializers$7(structure, missing) { - const { name } = structure; - throw new TypeError(`Missing initializers for ${name}: ${missing.join(', ')}`); +function getDescriptor$8(member, env) { + const f = factories$o[member.type]; + return f(member, env); } -function throwNoProperty$7(structure, propName) { - const { name, instance: { members } } = structure; - const member = members.find(m => m.name === propName); - if (member) { - throw new TypeError(`Comptime value cannot be changed: ${propName}`); - } else { - throw new TypeError(`${name} does not have a property with that name: ${propName}`); +function transformDescriptor(descriptor, member) { + const { structure } = member; + const t = transformers[structure?.type]; + return (t) ? t(descriptor, structure) : descriptor; +} + +function getVoidDescriptor$8(member, env) { + const { runtimeSafety } = env; + return { + get: function() { + return undefined; + }, + set: (runtimeSafety) + ? function(value) { + if (value !== undefined) { + throwNotUndefined$8(member); + } + } + : function() {}, } } -function throwArgumentCountMismatch$7(structure, actual) { - const { name, instance: { members } } = structure; - const argCount = members.length - 1; - const s = (argCount !== 1) ? 's' : ''; - throw new Error(`${name} expects ${argCount} argument${s}, received ${actual}`); +function getNullDescriptor$8(member, env) { + return { + get: function() { + return null; + }, + } } -function rethrowArgumentError$7(structure, index, err) { - const { name, instance: { members } } = structure; - // Zig currently does not provide the argument name - const argName = `args[${index}]`; - const argCount = members.length - 1; - const prefix = (index !== 0) ? '..., ' : ''; - const suffix = (index !== argCount - 1) ? ', ...' : ''; - const argLabel = prefix + argName + suffix; - const newError = new err.constructor(`${name}(${argLabel}): ${err.message}`); - newError.stack = err.stack; - throw newError; +function getUndefinedDescriptor$8(member, env) { + return { + get: function() { + return undefined; + }, + } } -function throwNoCastingToPointer$7(structure) { - throw new TypeError(`Non-slice pointers can only be created with the help of the new operator`); +function getBoolDescriptor$8(member, env) { + return getDescriptorUsing$8(member, env, getBoolAccessor$8) } -function throwConstantConstraint$7(structure, pointer) { - const { name: target } = structure; - const { constructor: { name } } = pointer; - throw new TypeError(`Conversion of ${name} to ${target} requires an explicit cast`); +function getIntDescriptor$8(member, env) { + const getDataViewAccessor = addRuntimeCheck$8(env, getNumericAccessor$8); + const descriptor = getDescriptorUsing$8(member, env, getDataViewAccessor); + return transformDescriptor(descriptor, member); } -function throwMisplacedSentinel$7(structure, value, index, length) { - const { name } = structure; - throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}, found at ${index}`); +function getUintDescriptor$8(member, env) { + const getDataViewAccessor = addRuntimeCheck$8(env, getNumericAccessor$8); + const descriptor = getDescriptorUsing$8(member, env, getDataViewAccessor); + return transformDescriptor(descriptor, member); } -function throwMissingSentinel$7(structure, value, length) { - const { name } = structure; - throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}`); +function addRuntimeCheck$8(env, getDataViewAccessor) { + return function (access, member) { + const { + runtimeSafety = true, + } = env; + const accessor = getDataViewAccessor(access, member); + if (runtimeSafety && access === 'set') { + const { min, max } = getIntRange$8(member); + return function(offset, value, littleEndian) { + if (value < min || value > max) { + throwOverflow$8(member, value); + } + accessor.call(this, offset, value, littleEndian); + }; + } + return accessor; + }; } -function throwTypeMismatch$7(expected, arg) { - const received = getDescription$7(arg); - throw new TypeError(`Expected ${addArticle$7(expected)}, received ${received}`) +function getFloatDescriptor$8(member, env) { + return getDescriptorUsing$8(member, env, getNumericAccessor$8) } -function throwInaccessiblePointer$7() { - throw new TypeError(`Pointers within an untagged union are not accessible`); +function transformEnumerationDescriptor(int, structure) { + const findEnum = function(value) { + const { constructor } = structure; + // the enumeration constructor returns the object for the int value + const item = constructor(value); + if (!item) { + throwEnumExpected$8(structure, value); + } + return item + }; + return { + get: (int.get.length === 0) + ? function getEnum(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } + return findEnum(value); + } + : function getEnumElement(index) { + const value = int.get.call(this, index); + return findEnum(value); + }, + set: (int.set.length === 1) + ? function setEnum(value, hint) { + if (hint !== 'number') { + const item = findEnum(value); + // call Symbol.toPrimitive directly as enum can be bigint or number + value = item[Symbol.toPrimitive](); + } + int.set.call(this, value); + } + : function setEnumElement(index, value) { + const item = findEnum(value); + int.set.call(this, index, item[Symbol.toPrimitive]()); + }, + }; } -function throwNullPointer$7() { - throw new TypeError(`Null pointer`); +function transformErrorSetDescriptor(int, structure) { + const findError = function(value) { + const { constructor } = structure; + const item = constructor(value); + if (!item) { + if (value instanceof Error) { + throwNotInErrorSet$8(structure); + } else { + throwErrorExpected$8(structure, value); + } + } + return item + }; + return { + get: (int.get.length === 0) + ? function getError(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } + return findError(value); + } + : function getErrorElement(index) { + const value = int.get.call(this, index); + return findError(value); + }, + set: (int.set.length === 1) + ? function setError(value, hint) { + if (hint !== 'number') { + const item = findError(value); + value = Number(item); + } + int.set.call(this, value); + } + : function setError(index, value) { + const item = findError(value); + value = Number(item); + int.set.call(this, index, value); + }, + }; } -function throwInvalidPointerTarget$7(structure, arg) { - const { name } = structure; - let target; - if (arg != null) { - const type = typeof(arg); - const noun = (type === 'object' && arg.constructor !== Object) ? `${arg.constructor.name} object`: type; - const a = article$7(noun); - target = `${a} ${noun}`; - } else { - target = arg + ''; +function isValueExpected$8(structure) { + switch (structure.type) { + case StructureType$8.Primitive: + case StructureType$8.ErrorUnion: + case StructureType$8.Optional: + case StructureType$8.Enumeration: + case StructureType$8.ErrorSet: + return true; + default: + return false; } - throw new TypeError(`${name} cannot point to ${target}`) } -function throwFixedMemoryTargetRequired$7(structure, arg) { - throw new TypeError(`Pointers in fixed memory cannot point to garbage-collected object`); +function getValue$8(slot) { + const object = this[SLOTS$8][slot] ?? this[VIVIFICATOR$8](slot); + return object[GETTER$8](); } - -function throwOverflow$7(member, value) { - const typeName = getTypeName$7(member); - throw new TypeError(`${typeName} cannot represent the value given: ${value}`); +function getObject$8(slot) { + const object = this[SLOTS$8][slot] ?? this[VIVIFICATOR$8](slot); + return object; } -function throwOutOfBound$7(member, index) { - const { name } = member; - throw new RangeError(`Index exceeds the size of ${name ?? 'array'}: ${index}`); +function setValue$8(slot, value) { + const object = this[SLOTS$8][slot] ?? this[VIVIFICATOR$8](slot); + object[SETTER$8](value); } -function rethrowRangeError$7(member, index, err) { - if (err instanceof RangeError) { - throwOutOfBound$7(member, index); +function bindSlot$8(slot, { get, set }) { + if (slot !== undefined) { + return { + get: function() { + return get.call(this, slot); + }, + set: (set) + ? function(arg) { + return set.call(this, slot, arg); + } + : undefined, + }; } else { - throw err; + // array accessors + return { get, set }; } } -function throwNotUndefined$7(member) { - const { name } = member; - throw new RangeError(`Property ${name} can only be undefined`); -} - -function throwNotOnByteBoundary$7(member) { - const { name, structure: { name: { struct }} } = member; - throw new TypeError(`Unable to create ${struct} as it is not situated on a byte boundary: ${name}`); +function getObjectDescriptor$8(member, env) { + const { structure, slot } = member; + return bindSlot$8(slot, { + get: isValueExpected$8(structure) ? getValue$8 : getObject$8, + set: setValue$8, + }); } -function throwReadOnly$7() { - throw new TypeError(`Unable to modify read-only object`); +function getType$8(slot) { + // unsupported types will have undefined structure + const structure = this[SLOTS$8][slot]; + return structure?.constructor; } -function throwReadOnlyTarget$7(structure) { - const { name } = structure; - throw new TypeError(`${name} cannot point to a read-only object`); +function getTypeDescriptor$8(member, env) { + const { slot } = member; + return bindSlot$8(slot, { get: getType$8 }); } -function throwAccessingOpaque$7(structure) { - const { name } = structure; - throw new TypeError(`Unable to access opaque structure ${name}`); +function getComptimeDescriptor$8(member, env) { + const { slot, structure } = member; + return bindSlot$8(slot, { + get: isValueExpected$8(structure) ? getValue$8 : getObject$8, + }); } -function throwCreatingOpaque$7(structure) { - const { name } = structure; - throw new TypeError(`Unable to create instance of ${name}, as it is opaque`); +function getStaticDescriptor$8(member, env) { + const { slot, structure } = member; + return bindSlot$8(slot, { + get: isValueExpected$8(structure) ? getValue$8 : getObject$8, + set: setValue$8, + }); } -function throwZigError(name) { - throw new Error(deanimalizeErrorName(name)); +function getLiteral$8(slot) { + const object = this[SLOTS$8][slot]; + return object.string; } -function warnImplicitArrayCreation$7(structure, arg) { - const created = addArticle$7(structure.typedArray.name); - const source = addArticle$7(arg.constructor.name); - console.warn(`Implicitly creating ${created} from ${source}`); +function getLiteralDescriptor$8(member, env) { + const { slot } = member; + return bindSlot$8(slot, { get: getLiteral$8 }); } -function deanimalizeErrorName(name) { - // deal with snake_case first - let s = name.replace(/_/g, ' '); - // then camelCase, using a try block in case Unicode regex fails - try { - s = s.replace(/(\p{Uppercase}+)(\p{Lowercase}*)/gu, (m0, m1, m2) => { - if (m1.length === 1) { - return ` ${m1.toLocaleLowerCase()}${m2}`; - } else { - if (m2) { - const acronym = m1.substring(0, m1.length - 1); - const letter = m1.charAt(m1.length - 1).toLocaleLowerCase(); - return ` ${acronym} ${letter}${m2}`; - } else { - return ` ${m1}`; +function getDescriptorUsing$8(member, env, getDataViewAccessor) { + const { + littleEndian = true, + } = env; + const { bitOffset, byteSize } = member; + const getter = getDataViewAccessor('get', member); + const setter = getDataViewAccessor('set', member); + if (bitOffset !== undefined) { + const offset = bitOffset >> 3; + return { + get: function getValue() { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return getter.call(this[MEMORY$8], offset, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$8.call(this)) { + return getter.call(this[MEMORY$8], offset, littleEndian); + } else { + throw err; + } + } + /* WASM-ONLY-END*/ + }, + set: function setValue(value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return setter.call(this[MEMORY$8], offset, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$8.call(this)) { + return setter.call(this[MEMORY$8], offset, value, littleEndian); + } else { + throw err; + } } + /* WASM-ONLY-END*/ } - }).trimStart(); - /* c8 ignore next 2 */ - } catch (err) { + } + } else { + return { + get: function getElement(index) { + try { + return getter.call(this[MEMORY$8], index * byteSize, littleEndian); + } catch (err) { + /* WASM-ONLY */ + if (err instanceof TypeError && restoreMemory$8.call(this)) { + return getter.call(this[MEMORY$8], index * byteSize, littleEndian); + } else { + /* WASM-ONLY-END */ + rethrowRangeError$8(member, index, err); + /* WASM-ONLY */ + } + /* WASM-ONLY-END */ + } + }, + set: function setElement(index, value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END */ + return setter.call(this[MEMORY$8], index * byteSize, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$8.call(this)) { + return setter.call(this[MEMORY$8], index * byteSize, value, littleEndian); + } else { + rethrowRangeError$8(member, index, err); + } + } + /* WASM-ONLY-END */ + }, + } } - return s.charAt(0).toLocaleUpperCase() + s.substring(1); } -function getDescription$7(arg) { - const type = typeof(arg); - let s; - if (type === 'object') { - s = (arg) ? Object.prototype.toString.call(arg) : 'null'; +function useAllMemberTypes$8() { + useVoid$8(); + useNull$8(); + useUndefined$8(); + useBool$8(); + useInt$8(); + useUint$8(); + useFloat$8(); + useObject$8(); + useType$8(); + useComptime$8(); + useStatic$8(); + useLiteral$8(); +} + +process.cwd(); + +useAllMemberTypes$8(); +useAllStructureTypes$8(); +useAllExtendedTypes$8(); + +const MEMORY$7 = Symbol('memory'); +const SLOTS$7 = Symbol('slots'); +const PARENT$7 = Symbol('parent'); +const NAME$7 = Symbol('name'); +const TAG$7 = Symbol('tag'); +const ITEMS$7 = Symbol('items'); +const PROPS$7 = Symbol('props'); +const GETTER$7 = Symbol('getter'); +const SETTER$7 = Symbol('setter'); +const ELEMENT_GETTER$7 = Symbol('elementGetter'); +const ELEMENT_SETTER$7 = Symbol('elementSetter'); +const LOCATION_GETTER$7 = Symbol('addressGetter'); +const LOCATION_SETTER$7 = Symbol('addressSetter'); +const TARGET_GETTER$7 = Symbol('targetGetter'); +const TARGET_SETTER$7 = Symbol('targetSetter'); +const FIXED_LOCATION$7 = Symbol('fixedLocation'); +const PROP_GETTERS$7 = Symbol('propGetters'); +const PROP_SETTERS$7 = Symbol('propSetters'); +const ALL_KEYS$7 = Symbol('allKeys'); +const LENGTH$7 = Symbol('length'); +const PROXY$7 = Symbol('proxy'); +const COMPAT$7 = Symbol('compat'); +const SIZE$7 = Symbol('size'); +const ALIGN$7 = Symbol('align'); +const ARRAY$7 = Symbol('array'); +const POINTER$7 = Symbol('pointer'); +const CONST$7 = Symbol('const'); +const CONST_PROTOTYPE$7 = Symbol('constProto'); +const COPIER$7 = Symbol('copier'); +const RESETTER$7 = Symbol('resetter'); +const NORMALIZER$7 = Symbol('normalizer'); +const VIVIFICATOR$7 = Symbol('vivificator'); +const POINTER_VISITOR$7 = Symbol('pointerVisitor'); +const ENVIRONMENT$7 = Symbol('environment'); +const MORE$7 = Symbol('more'); + +function getDestructor$7(env) { + return function() { + const dv = this[MEMORY$7]; + this[MEMORY$7] = null; + if (this[SLOTS$7]) { + this[SLOTS$7] = {}; + } + env.releaseFixedView(dv); + }; +} + +function getBitAlignFunction$7(bitPos, bitSize, toAligned) { + if (bitPos + bitSize <= 8) { + const mask = (2 ** bitSize) - 1; + if (toAligned) { + // from single byte + return function(dest, src, offset) { + const n = src.getUint8(offset); + const b = (n >> bitPos) & mask; + dest.setUint8(0, b); + }; + } else { + // to single byte + const destMask = 0xFF ^ (mask << bitPos); + return function(dest, src, offset) { + const n = src.getUint8(0); + const d = dest.getUint8(offset); + const b = (d & destMask) | ((n & mask) << bitPos); + dest.setUint8(offset, b); + }; + } } else { - s = type; + const leadBits = 8 - bitPos; + const leadMask = (2 ** leadBits) - 1; + if (toAligned) { + const trailBits = bitSize % 8; + const trailMask = (2 ** trailBits) - 1; + return function(dest, src, offset) { + let i = offset, j = 0; + let n = src.getUint8(i++), b; + let bitBuf = (n >> bitPos) & leadMask; + let bitCount = leadBits; + let remaining = bitSize; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + //bitCount += 8; + } + b = (remaining >= 8) ? bitBuf & 0xFF : bitBuf & trailMask; + dest.setUint8(j++, b); + bitBuf >>= 8; + //bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } else { + const trailBits = (bitSize - leadBits) % 8; + const trailMask = (2 ** trailBits) - 1; + const destMask1 = 0xFF ^ (leadMask << bitPos); + const destMask2 = 0xFF ^ trailMask; + return function(dest, src, offset) { + let i = 0, j = offset; + // preserve bits ahead of bitPos + let d = dest.getUint8(j), n, b; + let bitBuf = d & destMask1; + let bitCount = bitPos; + let remaining = bitSize + bitCount; + do { + if (remaining > bitCount) { + n = src.getUint8(i++); + bitBuf = bitBuf | (n << bitCount); + bitCount += 8; + } + if (remaining >= 8) { + b = bitBuf & 0xFF; + } else { + // preserve bits at the destination sitting behind the trailing bits + d = dest.getUint8(j); + b = (d & destMask2) | (bitBuf & trailMask); + } + dest.setUint8(j++, b); + bitBuf >>= 8; + bitCount -= 8; + remaining -= 8; + } while (remaining > 0); + } + } } - return addArticle$7(s); } -function addArticle$7(noun) { - return `${article$7(noun)} ${noun}`; +function getMemoryCopier$7(size, multiple = false) { + const copy = getCopyFunction$7(size, multiple); + return function(target) { + /* WASM-ONLY */ + restoreMemory$7.call(this); + restoreMemory$7.call(target); + /* WASM-ONLY-END */ + const src = target[MEMORY$7]; + const dest = this[MEMORY$7]; + copy(dest, src); + }; } -function article$7(noun) { - return /^\W*[aeiou]/i.test(noun) ? 'an' : 'a'; +function getCopyFunction$7(size, multiple = false) { + if (!multiple) { + const copier = copiers$7[size]; + if (copier) { + return copier; + } + } + if (!(size & 0x07)) return copy8x$7; + if (!(size & 0x03)) return copy4x$7; + if (!(size & 0x01)) return copy2x$7; + return copy1x$7; } -function formatList$7(list, conj = 'or') { - const sep = ` ${conj} `; - if (list.length > 2) { - return list.slice(0, -1).join(', ') + sep + list[list.length - 1]; - } else { - return list.join(sep); +const copiers$7 = { + 1: copy1$7, + 2: copy2$7, + 4: copy4$7, + 8: copy8$7, + 16: copy16$7, + 32: copy32$7, +}; + +function copy1x$7(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i++) { + dest.setInt8(i, src.getInt8(i)); } } -function getBoolAccessor$7(access, member) { - return cacheMethod$7(access, member, () => { - if (isByteAligned$7(member)) { - const { byteSize } = member; - const typeName = getTypeName$7({ type: MemberType$7.Int, bitSize: byteSize * 8 }); - if (access === 'get') { - const get = DataView.prototype[`get${typeName}`]; - return function(offset, littleEndian) { - return !!get.call(this, offset, littleEndian); - }; - } else { - const set = DataView.prototype[`set${typeName}`]; - const T = (byteSize > 4) ? 1n : 1; - const F = (byteSize > 4) ? 0n : 0; - return function(offset, value, littleEndian) { - set.call(this, offset, value ? T : F, littleEndian); - }; - } - } else { - return getExtendedTypeAccessor$7(access, member); - } - }); +function copy2x$7(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 2) { + dest.setInt16(i, src.getInt16(i, true), true); + } } -function getNumericAccessor$7(access, member) { - return cacheMethod$7(access, member, (name) => { - if (DataView.prototype[name]) { - return DataView.prototype[name]; - } else { - return getExtendedTypeAccessor$7(access, member); - } - }); +function copy4x$7(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 4) { + dest.setInt32(i, src.getInt32(i, true), true); + } } -const factories$m = {}; - -function useExtendedBool$7() { - factories$m[MemberType$7.Bool] = getExtendedBoolAccessor$7; +function copy8x$7(dest, src) { + for (let i = 0, len = dest.byteLength; i < len; i += 8) { + dest.setInt32(i, src.getInt32(i, true), true); + dest.setInt32(i + 4, src.getInt32(i + 4, true), true); + } } -function useExtendedInt$7() { - factories$m[MemberType$7.Int] = getExtendedIntAccessor$7; +function copy1$7(dest, src) { + dest.setInt8(0, src.getInt8(0)); } -function useExtendedUint$7() { - factories$m[MemberType$7.Uint] = getExtendedUintAccessor$7; +function copy2$7(dest, src) { + dest.setInt16(0, src.getInt16(0, true), true); } -function useExtendedFloat$7() { - factories$m[MemberType$7.Float] = getExtendedFloatAccessor$7; +function copy4$7(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); } -function getExtendedTypeAccessor$7(access, member) { - const f = factories$m[member.type]; - return f(access, member); +function copy8$7(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); } -function getExtendedBoolAccessor$7(access, member) { - const { bitOffset } = member; - const bitPos = bitOffset & 0x07; - const mask = 1 << bitPos; - const get = DataView.prototype.getInt8; - if (access === 'get') { - return function(offset) { - const n = get.call(this, offset); - return !!(n & mask); - }; - } else { - const set = DataView.prototype.setInt8; - return function(offset, value) { - const n = get.call(this, offset); - const b = (value) ? n | mask : n & ~mask; - set.call(this, offset, b); - }; - } +function copy16$7(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); } -function getExtendedIntAccessor$7(access, member) { - if (isByteAligned$7(member)) { - return getAlignedIntAccessor$7(access, member) - } else { - return getUnalignedIntAccessor$7(access, member); - } +function copy32$7(dest, src) { + dest.setInt32(0, src.getInt32(0, true), true); + dest.setInt32(4, src.getInt32(4, true), true); + dest.setInt32(8, src.getInt32(8, true), true); + dest.setInt32(12, src.getInt32(12, true), true); + dest.setInt32(16, src.getInt32(16, true), true); + dest.setInt32(20, src.getInt32(20, true), true); + dest.setInt32(24, src.getInt32(24, true), true); + dest.setInt32(28, src.getInt32(28, true), true); } -function getExtendedUintAccessor$7(access, member) { - if (isByteAligned$7(member)) { - return getAlignedUintAccessor$7(access, member) - } else { - return getUnalignedUintAccessor$7(access, member); - } +function getMemoryResetter$7(offset, size) { + const reset = getResetFunction$7(size); + return function() { + /* WASM-ONLY */ + restoreMemory$7.call(this); + /* WASM-ONLY-END */ + const dest = this[MEMORY$7]; + reset(dest, offset, size); + }; } -function getExtendedFloatAccessor$7(access, member) { - if (isByteAligned$7(member)) { - return getAlignedFloatAccessor$7(access, member) - } else { - return getUnalignedFloatAccessor$7(access, member); +function getResetFunction$7(size) { + const resetter = resetters$7[size]; + if (resetter) { + return resetter; } + if (!(size & 0x07)) return reset8x$7; + if (!(size & 0x03)) return reset4x$7; + if (!(size & 0x01)) return reset2x$7; + return reset1x$7; } -function getDataView$7(structure, arg, env) { - const { type, byteSize, typedArray } = structure; - let dv; - // not using instanceof just in case we're getting objects created in other contexts - const tag = arg?.[Symbol.toStringTag]; - if (tag === 'DataView') { - dv = arg; - } else if (tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { - dv = env.obtainView(arg, 0, arg.byteLength); - } else if (typedArray && tag === typedArray.name || (tag === 'Uint8ClampedArray' && typedArray === Uint8Array)) { - dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); - } else if (tag === 'Uint8Array' && typeof(Buffer) === 'function' && arg instanceof Buffer) { - dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); - } else { - const memory = arg?.[MEMORY$7]; - if (memory) { - const { constructor, instance: { members: [ member ] } } = structure; - if (arg instanceof constructor) { - return memory; - } else if (type === StructureType$7.Array || type === StructureType$7.Slice || type === StructureType$7.Vector) { - const { byteSize: elementSize, structure: { constructor: Child } } = member; - const number = findElements$7(arg, Child); - if (number !== undefined) { - if (type === StructureType$7.Slice || number * elementSize === byteSize) { - return memory; - } else { - throwArrayLengthMismatch$7(structure, null, arg); - } - } - } - } - } - if (dv && byteSize !== undefined) { - checkDataViewSize$7(dv, structure); - } - return dv; -} +const resetters$7 = { + 1: reset1$7, + 2: reset2$7, + 4: reset4$7, + 8: reset8$7, + 16: reset16$7, + 32: reset32$7, +}; -function checkDataView$7(dv) { - if (dv?.[Symbol.toStringTag] !== 'DataView') { - throwTypeMismatch$7('a DataView', dv); +function reset1x$7(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i++) { + dest.setInt8(i, 0); } - return dv; } -function checkDataViewSize$7(dv, structure) { - const { byteSize, type } = structure; - const multiple = type === StructureType$7.Slice; - if (multiple ? dv.byteLength % byteSize !== 0 : dv.byteLength !== byteSize) { - throwBufferSizeMismatch$7(structure, dv); +function reset2x$7(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 2) { + dest.setInt16(i, 0, true); } } -function setDataView$7(dv, structure, copy, handlers) { - const { byteSize, type, sentinel } = structure; - const multiple = type === StructureType$7.Slice; - if (!this[MEMORY$7]) { - const { shapeDefiner } = handlers; - checkDataViewSize$7(dv, structure); - const len = dv.byteLength / byteSize; - const source = { [MEMORY$7]: dv }; - sentinel?.validateData(source, len); - shapeDefiner.call(this, copy ? null : dv, len); - if (copy) { - this[COPIER$7](source); - } - } else { - const byteLength = multiple ? byteSize * this.length : byteSize; - if (dv.byteLength !== byteLength) { - throwBufferSizeMismatch$7(structure, dv, this); - } - const source = { [MEMORY$7]: dv }; - sentinel?.validateData(source, this.length); - this[COPIER$7](source); +function reset4x$7(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 4) { + dest.setInt32(i, 0, true); } } -function findElements$7(arg, Child) { - // casting to a array/slice - const { constructor: Arg } = arg; - if (Arg === Child) { - // matching object - return 1; - } else if (Arg.child === Child) { - // matching slice/array - return arg.length; +function reset8x$7(dest, offset, size) { + for (let i = offset, limit = offset + size; i < limit; i += 8) { + dest.setInt32(i, 0, true); + dest.setInt32(i + 4, 0, true); } } -function requireDataView$7(structure, arg, env) { - const dv = getDataView$7(structure, arg, env); - if (!dv) { - throwBufferExpected$7(structure); - } - return dv; +function reset1$7(dest, offset) { + dest.setInt8(offset, 0); } -function getTypedArrayClass$7(member) { - const { type: memberType, byteSize } = member; - if (memberType === MemberType$7.Int) { - switch (byteSize) { - case 1: return Int8Array; - case 2: return Int16Array; - case 4: return Int32Array; - case 8: return BigInt64Array; - } - } else if (memberType === MemberType$7.Uint) { - switch (byteSize) { - case 1: return Uint8Array; - case 2: return Uint16Array; - case 4: return Uint32Array; - case 8: return BigUint64Array; - } - } else if (memberType === MemberType$7.Float) { - switch (byteSize) { - case 4: return Float32Array; - case 8: return Float64Array; - } - } else if (memberType === MemberType$7.Object) { - return member.structure.typedArray; - } - return null; +function reset2$7(dest, offset) { + dest.setInt16(offset, 0, true); } -function isTypedArray$7(arg, TypedArray) { - const tag = arg?.[Symbol.toStringTag]; - return (!!TypedArray && tag === TypedArray.name); +function reset4$7(dest, offset) { + dest.setInt32(offset, 0, true); } -function isCompatible$7(arg, constructor) { - const tags = constructor[COMPAT$7]; - if (tags) { - const tag = arg?.[Symbol.toStringTag]; - if (tags.includes(tag)) { - return true; - } - } - if (constructor.child) { - if (findElements$7(arg, constructor.child) !== undefined) { - return true; - } - } - return false; +function reset8$7(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); } -function getCompatibleTags$7(structure) { - const { typedArray } = structure; - const tags = []; - if (typedArray) { - tags.push(typedArray.name); - tags.push('DataView'); - if (typedArray === Uint8Array || typedArray === Int8Array) { - tags.push('Uint8ClampedArray'); - tags.push('ArrayBuffer'); - tags.push('SharedArrayBuffer'); - } - } - return tags; +function reset16$7(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); } -function isBuffer$7(arg, typedArray) { - const tag = arg?.[Symbol.toStringTag]; - if (tag === 'DataView' || tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { - return true; - } else if (typedArray && tag === typedArray.name) { - return true; - } else { - return false; - } +function reset32$7(dest, offset) { + dest.setInt32(offset + 0, 0, true); + dest.setInt32(offset + 4, 0, true); + dest.setInt32(offset + 8, 0, true); + dest.setInt32(offset + 12, 0, true); + dest.setInt32(offset + 16, 0, true); + dest.setInt32(offset + 20, 0, true); + dest.setInt32(offset + 24, 0, true); + dest.setInt32(offset + 28, 0, true); } -function getTypeName$7(member) { - const { type, bitSize, byteSize } = member; - if (type === MemberType$7.Int) { - return `${bitSize <= 32 ? '' : 'Big' }Int${bitSize}`; - } else if (type === MemberType$7.Uint) { - return `${bitSize <= 32 ? '' : 'Big' }Uint${bitSize}`; - } else if (type === MemberType$7.Float) { - return `Float${bitSize}`; - } else if (type === MemberType$7.Bool) { - const boolSize = (byteSize !== undefined) ? byteSize * 8 : 1; - return `Bool${boolSize}`; - } else if (type === MemberType$7.Void) { - return `Null`; +function restoreMemory$7() { + const dv = this[MEMORY$7]; + const source = dv[MEMORY$7]; + if (!source || dv.buffer.byteLength !== 0) { + return false; } + const { memory, address, len } = source; + const newDV = new DataView(memory.buffer, address, len); + newDV[MEMORY$7] = source; + this[MEMORY$7] = newDV; + return true; } -function getBigIntDescriptor$7(bitSize) { - const getWord = DataView.prototype.getBigUint64; - const setWord = DataView.prototype.setBigUint64; - const wordCount = Math.ceil(bitSize / 64); - return { - get: function(offset, littleEndian) { - let n = 0n; - if (littleEndian) { - for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { - const w = getWord.call(this, j, littleEndian); - n = (n << 64n) | w; - } - } else { - for (let i = 0, j = offset; i < wordCount; i++, j += 8) { - const w = getWord.call(this, j, littleEndian); - n = (n << 64n) | w; - } +const decoders$7 = {}; +const encoders$7 = {}; + +function decodeText$7(arrays, encoding = 'utf-8') { + let decoder = decoders$7[encoding]; + if (!decoder) { + decoder = decoders$7[encoding] = new TextDecoder(encoding); + } + let array; + if (Array.isArray(arrays)) { + if (arrays.length === 1) { + array = arrays[0]; + } else { + let len = 0; + for (const a of arrays) { + len += a.length; } - return n; - }, - set: function(offset, value, littleEndian) { - let n = value; - const mask = 0xFFFFFFFFFFFFFFFFn; - if (littleEndian) { - for (let i = 0, j = offset; i < wordCount; i++, j += 8) { - const w = n & mask; - setWord.call(this, j, w, littleEndian); - n >>= 64n; - } - } else { - n <<= BigInt(wordCount * 64 - bitSize); - for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { - const w = n & mask; - setWord.call(this, j, w, littleEndian); - n >>= 64n; - } + const { constructor } = arrays[0]; + array = new constructor(len); + let offset = 0; + for (const a of arrays) { + array.set(a, offset); + offset += a.length; } - return n; - }, - }; + } + } else { + array = arrays; + } + return decoder.decode(array); } -function getAlignedIntAccessor$7(access, member) { - const { bitSize, byteSize } = member; - if (bitSize < 64) { - // actual number of bits needed when stored aligned - const typeName = getTypeName$7({ ...member, bitSize: byteSize * 8 }); - const get = DataView.prototype[`get${typeName}`]; - const set = DataView.prototype[`set${typeName}`]; - const signMask = (bitSize <= 32) ? 2 ** (bitSize - 1) : 2n ** BigInt(bitSize - 1); - const valueMask = (bitSize <= 32) ? signMask - 1 : signMask - 1n; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - return (n & valueMask) - (n & signMask); - }; - } else { - return function(offset, value, littleEndian) { - const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; - set.call(this, offset, n, littleEndian); - }; +function encodeText$7(text, encoding = 'utf-8') { + switch (encoding) { + case 'utf-16': { + const { length } = text; + const ta = new Uint16Array(length); + for (let i = 0; i < length; i++) { + ta[i] = text.charCodeAt(i); + } + return ta; } - } else { - // larger than 64 bits - const { get, set } = getBigIntDescriptor$7(bitSize); - const signMask = 2n ** BigInt(bitSize - 1); - const valueMask = signMask - 1n; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - return (n & valueMask) - (n & signMask); - }; - } else { - return function(offset, value, littleEndian) { - const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; - set.call(this, offset, n, littleEndian); - }; + default: { + let encoder = encoders$7[encoding]; + if (!encoder) { + encoder = encoders$7[encoding] = new TextEncoder(); + } + return encoder.encode(text); } } } -function getAlignedUintAccessor$7(access, member) { - const { bitSize, byteSize } = member; - if (bitSize < 64) { - // actual number of bits needed when stored aligned - const typeName = getTypeName$7({ ...member, bitSize: byteSize * 8 }); - const get = DataView.prototype[`get${typeName}`]; - const set = DataView.prototype[`set${typeName}`]; - const valueMask = (bitSize <= 32) ? (2 ** bitSize) - 1 : (2n ** BigInt(bitSize)) - 1n; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - return n & valueMask; - }; +function encodeBase64$7(dv) { + const ta = new Uint8Array(dv.buffer, dv.byteOffset, dv.byteLength); + const bstr = String.fromCharCode.apply(null, ta); + return btoa(bstr); +} + +function decodeBase64$7(str) { + const bstr = atob(str); + const ta = new Uint8Array(bstr.length); + for (let i = 0; i < ta.byteLength; i++) { + ta[i] = bstr.charCodeAt(i); + } + return new DataView(ta.buffer); +} + +function getValueOf$7() { + const map = new Map(); + const options = { error: 'throw' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$7]; + if (normalizer) { + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + map.set(value, result); + } + return result; } else { - return function(offset, value, littleEndian) { - const n = value & valueMask; - set.call(this, offset, n, littleEndian); - }; + return value; } - } else { - // larger than 64 bits - const { get, set } = getBigIntDescriptor$7(bitSize); - const valueMask = (2n ** BigInt(bitSize)) - 1n; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - return n & valueMask; - }; + }; + return process(this); +} + +const INT_MAX$7 = BigInt(Number.MAX_SAFE_INTEGER); +const INT_MIN$7 = BigInt(Number.MIN_SAFE_INTEGER); + +function convertToJSON$7() { + const map = new Map(); + const options = { error: 'return' }; + const process = function(value) { + const normalizer = value?.[NORMALIZER$7]; + if (normalizer) { + if (value instanceof Error) { + return { error: value.message }; + } + let result = map.get(value); + if (result === undefined) { + result = normalizer.call(value, process, options); + map.set(value, result); + } + return result; } else { - return function(offset, value, littleEndian) { - const n = value & valueMask; - set.call(this, offset, n, littleEndian); - }; + if (typeof(value) === 'bigint' && INT_MIN$7 <= value && value <= INT_MAX$7) { + return Number(value); + } + return value; } - } + }; + return process(this); } -function getUnalignedIntAccessor$7(access, member) { - const { bitSize, bitOffset } = member; - const bitPos = bitOffset & 0x07; - if (bitPos + bitSize <= 8) { - const set = DataView.prototype.setUint8; - const get = DataView.prototype.getUint8; - // sub-8-bit numbers have real use cases - const signMask = 2 ** (bitSize - 1); - const valueMask = signMask - 1; - if (access === 'get') { - return function(offset) { - const n = get.call(this, offset); - const s = n >>> bitPos; - return (s & valueMask) - (s & signMask); - }; +function normalizeValue$7(cb, options) { + const value = handleError$7(() => this.$, options); + return cb(value); +} + +function handleError$7(cb, options = {}) { + const { error = 'throw' } = options; + try { + return cb(); + } catch (err) { + if (error === 'return') { + return err; } else { - const outsideMask = 0xFF ^ ((valueMask | signMask) << bitPos); - return function(offset, value) { - let b = get.call(this, offset); - const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; - b = (b & outsideMask) | (n << bitPos); - set.call(this, offset, b); - }; + throw err; } } - return getUnalignedNumericAccessor$7(access, member); } -function getUnalignedUintAccessor$7(access, member) { - const { bitSize, bitOffset } = member; - const bitPos = bitOffset & 0x07; - if (bitPos + bitSize <= 8) { - const set = DataView.prototype.setUint8; - const get = DataView.prototype.getUint8; - const valueMask = (2 ** bitSize - 1); - if (access === 'get') { - return function(offset) { - const n = get.call(this, offset); - const s = n >>> bitPos; - return s & valueMask; - }; - } else { - const outsideMask = 0xFF ^ (valueMask << bitPos); - return function(offset, value) { - const n = get.call(this, offset); - const b = (n & outsideMask) | ((value & valueMask) << bitPos); - set.call(this, offset, b); - }; +function getDataViewDescriptor$7(structure, handlers = {}) { + return markAsSpecial$7({ + get() { + /* WASM-ONLY */ + restoreMemory$7.call(this); + /* WASM-ONLY-END */ + return this[MEMORY$7]; + }, + set(dv) { + checkDataView$7(dv); + setDataView$7.call(this, dv, structure, true, handlers); + }, + }); +} + +function getBase64Descriptor$7(structure, handlers = {}) { + return markAsSpecial$7({ + get() { + return encodeBase64$7(this.dataView); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$7('string', str); + } + const dv = decodeBase64$7(str); + setDataView$7.call(this, dv, structure, false, handlers); } - } - return getUnalignedNumericAccessor$7(access, member); + }); } -function getAlignedFloatAccessor$7(access, member) { - const { bitSize, byteSize } = member; - if (bitSize === 16) { - const buf = new DataView(new ArrayBuffer(4)); - const set = DataView.prototype.setUint16; - const get = DataView.prototype.getUint16; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - const sign = n >>> 15; - const exp = (n & 0x7C00) >> 10; - const frac = n & 0x03FF; - if (exp === 0) { - return (sign) ? -0 : 0; - } else if (exp === 0x1F) { - if (!frac) { - return (sign) ? -Infinity : Infinity; - } else { - return NaN; - } +function getStringDescriptor$7(structure, handlers = {}) { + const { sentinel, instance: { members }} = structure; + const { byteSize: charSize } = members[0]; + return markAsSpecial$7({ + get() { + const dv = this.dataView; + const TypedArray = (charSize === 1) ? Int8Array : Int16Array; + const ta = new TypedArray(dv.buffer, dv.byteOffset, this.length); + const s = decodeText$7(ta, `utf-${charSize * 8}`); + return (sentinel?.value === undefined) ? s : s.slice(0, -1); + }, + set(str) { + if (typeof(str) !== 'string') { + throwTypeMismatch$7('a string', str); + } + if (sentinel?.value !== undefined) { + if (str.charCodeAt(str.length - 1) !== sentinel.value) { + str = str + String.fromCharCode(sentinel.value); } - const n32 = (sign << 31) | ((exp - 15 + 127) << 23) | (frac << 13); - buf.setUint32(0, n32, littleEndian); - return buf.getFloat32(0, littleEndian); } - } else { - return function(offset, value, littleEndian) { - buf.setFloat32(0, value, littleEndian); - const n = buf.getUint32(0, littleEndian); - const sign = n >>> 31; - const exp = (n & 0x7F800000) >> 23; - const frac = n & 0x007FFFFF; - const exp16 = (exp - 127 + 15); - let n16; - if (exp === 0) { - n16 = sign << 15; - } else if (exp === 0xFF) { - n16 = sign << 15 | 0x1F << 10 | (frac ? 1 : 0); - } else if (exp16 >= 31) { - n16 = sign << 15 | 0x1F << 10; - } else { - n16 = sign << 15 | exp16 << 10 | (frac >> 13); - } - set.call(this, offset, n16, littleEndian); + const ta = encodeText$7(str, `utf-${charSize * 8}`); + const dv = new DataView(ta.buffer); + setDataView$7.call(this, dv, structure, false, handlers); + }, + }); +} + +function getTypedArrayDescriptor$7(structure, handlers = {}) { + const { typedArray } = structure; + return markAsSpecial$7({ + get() { + const dv = this.dataView; + const length = dv.byteLength / typedArray.BYTES_PER_ELEMENT; + return new typedArray(dv.buffer, dv.byteOffset, length); + }, + set(ta) { + if (!isTypedArray$7(ta, typedArray)) { + throwTypeMismatch$7(typedArray.name, ta); + } + const dv = new DataView(ta.buffer, ta.byteOffset, ta.byteLength); + setDataView$7.call(this, dv, structure, true, handlers); + }, + }); +} + +function markAsSpecial$7({ get, set }) { + get.special = set.special = true; + return { get, set }; +} + +function definePointer$7(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + isConst, + } = structure; + const { + runtimeSafety = true, + } = env; + const { structure: targetStructure } = member; + const { sentinel } = targetStructure; + const isTargetSlice = (targetStructure.type === StructureType$7.Slice); + const isTargetPointer = (targetStructure.type === StructureType$7.Pointer); + const hasLength = isTargetSlice && !sentinel; + const addressSize = (hasLength) ? byteSize / 2 : byteSize; + const { get: getAddress, set: setAddress } = getDescriptor$7({ + type: MemberType$7.Uint, + bitOffset: 0, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { byteSize: addressSize }, + }, env); + const { get: getLength, set: setLength } = (hasLength) ? getDescriptor$7({ + type: MemberType$7.Uint, + bitOffset: addressSize * 8, + bitSize: addressSize * 8, + byteSize: addressSize, + structure: { name: 'usize', byteSize: addressSize }, + }, env) : {}; + const updateTarget = function() { + const prevLocation = this[FIXED_LOCATION$7]; + if (prevLocation) { + const location = this[LOCATION_GETTER$7](); + if (location.address !== prevLocation.address || location.length !== prevLocation.length) { + const { constructor: Target } = targetStructure; + const dv = env.findMemory(location.address, location.length * Target[SIZE$7]); + const target = Target.call(ENVIRONMENT$7, dv, { writable: !isConst }); + this[SLOTS$7][0] = target; + this[FIXED_LOCATION$7] = location; + } + } + }; + const getTargetObject = function() { + updateTarget.call(this); + return this[SLOTS$7][0] ?? throwNullPointer$7(); + }; + const setTargetObject = function(arg) { + if (env.inFixedMemory(this)) { + // the pointer sits in fixed memory--apply the change immediately + if (env.inFixedMemory(arg)) { + const loc = { + address: env.getViewAddress(arg[MEMORY$7]), + length: (hasLength) ? arg.length : 1 + }; + addressSetter.call(this, loc); + this[FIXED_LOCATION$7] = loc; + } else { + throwFixedMemoryTargetRequired$7(); } } - } else if (bitSize === 80) { - const buf = new DataView(new ArrayBuffer(8)); - const get = function(offset, littleEndian) { - const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); - const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); - const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); - return w1 | w2 << 32n | w3 << 64n; - }; - const set = function(offset, value, littleEndian) { - const w1 = value & 0xFFFFFFFFn; - const w2 = (value >> 32n) & 0xFFFFFFFFn; - const w3 = (value >> 64n) & 0xFFFFFFFFn; - this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); - this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); - this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); - }; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - const sign = n >> 79n; - const exp = (n & 0x7FFF0000000000000000n) >> 64n; - const frac = n & 0x00007FFFFFFFFFFFFFFFn; - if (exp === 0n) { - return (sign) ? -0 : 0; - } else if (exp === 0x7FFFn) { - if (!frac) { - return (sign) ? -Infinity : Infinity; - } else { - return NaN; - } - } - const exp64 = exp - 16383n + 1023n; - if (exp64 >= 2047n) { - return (sign) ? -Infinity : Infinity; - } - const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 11n) + BigInt((frac & (2n**11n - 1n)) >= 2n**10n); - buf.setBigUint64(0, n64, littleEndian); - return buf.getFloat64(0, littleEndian); - } + this[SLOTS$7][0] = arg; + }; + const getTarget = isValueExpected$7(targetStructure) + ? function() { + const target = getTargetObject.call(this); + return target[GETTER$7](); + } + : getTargetObject; + const setTarget = function(value) { + updateTarget.call(this); + const object = this[SLOTS$7][0] ?? throwNullPointer$7(); + return object[SETTER$7](value); + }; + const alternateCaster = function(arg, options) { + const Target = targetStructure.constructor; + if ((this === ENVIRONMENT$7 || this === PARENT$7) || arg instanceof constructor) { + // casting from buffer to pointer is allowed only if request comes from the runtime + // casting from writable to read-only is also allowed + return false; + } else if (isPointerOf$7(arg, Target)) { + // const/non-const casting + return new constructor(Target(arg['*'], { writable: !isConst }), options); + } else if (isTargetSlice) { + // allow casting to slice through constructor of its pointer + return new constructor(Target(arg), options); } else { - return function(offset, value, littleEndian) { - buf.setFloat64(0, value, littleEndian); - const n = buf.getBigUint64(0, littleEndian); - const sign = n >> 63n; - const exp = (n & 0x7FF0000000000000n) >> 52n; - const frac = n & 0x000FFFFFFFFFFFFFn; - let n80; - if (exp === 0n) { - n80 = sign << 79n | (frac << 11n); - } else if (exp === 0x07FFn) { - n80 = sign << 79n | 0x7FFFn << 64n | (frac ? 0x00002000000000000000n : 0n) | 0x00008000000000000000n; - // ^ bit 61 ^ bit 63 - } else { - n80 = sign << 79n | (exp - 1023n + 16383n) << 64n | (frac << 11n) | 0x00008000000000000000n; - } - set.call(this, offset, n80, littleEndian); + throwNoCastingToPointer$7(); + } + }; + const finalizer = function() { + const handlers = (isTargetPointer) ? {} : proxyHandlers$f; + const proxy = new Proxy(this, handlers); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$7, { value: proxy }); + return proxy; + }; + const initializer = function(arg) { + const Target = targetStructure.constructor; + if (isPointerOf$7(arg, Target)) { + // initialize with the other pointer'structure target + if (!isConst && arg.constructor.const) { + throwConstantConstraint$7(structure, arg); } + arg = arg[SLOTS$7][0]; } - } else if (bitSize === 128) { - const buf = new DataView(new ArrayBuffer(8)); - const get = function(offset, littleEndian) { - const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); - const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); - const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); - const w4 = BigInt(this.getUint32(offset + (littleEndian ? 12 : byteSize - 16), littleEndian)); - return w1 | w2 << 32n | w3 << 64n | w4 << 96n; - }; - const set = function(offset, value, littleEndian) { - const w1 = value & 0xFFFFFFFFn; - const w2 = (value >> 32n) & 0xFFFFFFFFn; - const w3 = (value >> 64n) & 0xFFFFFFFFn; - const w4 = (value >> 96n) & 0xFFFFFFFFn; - this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); - this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); - this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); - this.setUint32(offset + (littleEndian ? 12 : byteSize - 16), Number(w4), littleEndian); - }; - if (access === 'get') { - return function(offset, littleEndian) { - const n = get.call(this, offset, littleEndian); - const sign = n >> 127n; - const exp = (n & 0x7FFF0000000000000000000000000000n) >> 112n; - const frac = n & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFn; - if (exp === 0n) { - return (sign) ? -0 : 0; - } else if (exp === 0x7FFFn) { - if (!frac) { - return (sign) ? -Infinity : Infinity; - } else { - return NaN; - } - } - const exp64 = exp - 16383n + 1023n; - if (exp64 >= 2047n) { - return (sign) ? -Infinity : Infinity; - } - const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 60n) + BigInt((frac & (2n**60n - 1n)) >= 2n**59n); - buf.setBigUint64(0, n64, littleEndian); - return buf.getFloat64(0, littleEndian); + if (arg instanceof Target) { + /* wasm-only */ + restoreMemory$7.call(arg); + /* wasm-only-end */ + if (isConst && !arg[CONST$7]) { + // create read-only version + arg = Target(arg, { writable: false }); + } else if (!isConst && arg[CONST$7]) { + throwReadOnlyTarget$7(structure); } - } else { - return function(offset, value, littleEndian) { - buf.setFloat64(0, value, littleEndian); - const n = buf.getBigUint64(0, littleEndian); - const sign = n >> 63n; - const exp = (n & 0x7FF0000000000000n) >> 52n; - const frac = n & 0x000FFFFFFFFFFFFFn; - let n128; - if (exp === 0n) { - n128 = sign << 127n | (frac << 60n); - } else if (exp === 0x07FFn) { - n128 = sign << 127n | 0x7FFFn << 112n | (frac ? 1n : 0n); - } else { - n128 = sign << 127n | (exp - 1023n + 16383n) << 112n | (frac << 60n); + } else if (isCompatible$7(arg, Target)) { + // autocast to target type + const dv = getDataView$7(targetStructure, arg, env); + arg = Target(dv, { writable: !isConst }); + } else if (arg !== undefined && !arg[MEMORY$7]) { + // autovivificate target object + const fixed = env.inFixedMemory(this); + const autoObj = new Target(arg, { writable: !isConst, fixed }); + if (runtimeSafety) { + // creation of a new slice using a typed array is probably + // not what the user wants; it's more likely that the intention + // is to point to the typed array but there's a mismatch (e.g. u32 vs i32) + if (targetStructure.typedArray && isBuffer$7(arg?.buffer)) { + warnImplicitArrayCreation$7(targetStructure, arg); } - set.call(this, offset, n128, littleEndian); } + arg = autoObj; + } else if (arg !== undefined) { + throwInvalidPointerTarget$7(structure, arg); } + this[TARGET_SETTER$7](arg); + }; + const constructor = structure.constructor = createConstructor$7(structure, { initializer, alternateCaster, finalizer }, env); + const addressSetter = function({ address, length }) { + setAddress.call(this, address); + setLength?.call(this, length); + }; + const addressGetter = function() { + const address = getAddress.call(this); + const length = (getLength) + ? getLength.call(this) + : (sentinel) + ? (address) ? env.findSentinel(address, sentinel.bytes) + 1 : 0 + : 1; + return { address, length }; + }; + const instanceDescriptors = { + '*': { get: getTarget, set: setTarget }, + '$': { get: getProxy$7, set: initializer }, + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + [TARGET_GETTER$7]: { value: getTargetObject }, + [TARGET_SETTER$7]: { value: setTargetObject }, + [LOCATION_GETTER$7]: { value: addressGetter }, + [LOCATION_SETTER$7]: { value: addressSetter }, + [POINTER_VISITOR$7]: { value: visitPointer$7 }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [VIVIFICATOR$7]: { value: throwNullPointer$7 }, + [NORMALIZER$7]: { value: normalizePointer$7 }, + [FIXED_LOCATION$7]: { value: undefined, writable: true }, + }; + const staticDescriptors = { + child: { get: () => targetStructure.constructor }, + const: { value: isConst }, + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizePointer$7(cb) { + let target; + try { + target = this['*']; + } catch (err) { + target = Symbol.for('inaccessible'); } + return cb(target); } -function getUnalignedFloatAccessor$7(access, member) { - return getUnalignedNumericAccessor$7(access, member); +function getProxy$7() { + return this[PROXY$7]; } -function getUnalignedNumericAccessor$7(access, member) { - // pathological usage scenario--handle it anyway by copying the bitSize into a - // temporary buffer, bit-aligning the data - const { bitSize, bitOffset } = member; - const bitPos = bitOffset & 0x07; - const byteSize = [ 1, 2, 4, 8 ].find(b => b * 8 >= bitSize) ?? Math.ceil(bitSize / 64) * 64; - const buf = new DataView(new ArrayBuffer(byteSize)); - if (access === 'get') { - const getAligned = getNumericAccessor$7('get', { ...member, byteSize }); - const copyBits = getBitAlignFunction$7(bitPos, bitSize, true); - return function(offset, littleEndian) { - copyBits(buf, this, offset); - return getAligned.call(buf, 0, littleEndian); - }; - } else { - const setAligned = getNumericAccessor$7('set', { ...member, byteSize }); - const applyBits = getBitAlignFunction$7(bitPos, bitSize, false); - return function(offset, value, littleEndian) { - setAligned.call(buf, 0, value, littleEndian); - applyBits(this, buf, offset); - }; +function copyPointer$7({ source }) { + const target = source[SLOTS$7][0]; + if (target) { + this[TARGET_SETTER$7](target); } } -const methodCache$7 = {}; +function resetPointer$7({ isActive }) { + if (this[SLOTS$7][0] && !isActive(this)) { + this[SLOTS$7][0] = undefined; + } +} -function cacheMethod$7(access, member, cb) { - const { type, bitOffset, bitSize, structure } = member; - const bitPos = bitOffset & 0x07; - const typeName = getTypeName$7(member); - const suffix = isByteAligned$7(member) ? `` : `Bit${bitPos}`; - const isInt = type === MemberType$7.Int || type === MemberType$7.Uint; - let name = `${access}${typeName}${suffix}`; - let isSize = false, originalName = name; - if (isInt && bitSize === 64) { - const zigTypeName = structure?.name; - if (zigTypeName === 'usize' || zigTypeName === 'isize') { - name += 'Size'; - isSize = true; +function disablePointer$7() { + const disabledProp = { get: throwInaccessiblePointer$7, set: throwInaccessiblePointer$7 }; + const disabledFunc = { value: throwInaccessiblePointer$7 }; + defineProperties$7(this[POINTER$7], { + '*': disabledProp, + '$': disabledProp, + [GETTER$7]: disabledFunc, + [SETTER$7]: disabledFunc, + [TARGET_GETTER$7]: disabledFunc, + }); +} + +function visitPointer$7(fn, options = {}) { + const { + source, + isActive = always$7, + isMutable = always$7, + } = options; + fn.call(this, { source, isActive, isMutable }); +} + +function isPointerOf$7(arg, Target) { + return (arg?.constructor?.child === Target && arg['*']); +} + +const proxyHandlers$f = { + get(pointer, name) { + if (name === POINTER$7) { + return pointer; + } else if (name in pointer) { + return pointer[name]; + } else { + const target = pointer[TARGET_GETTER$7](); + return target[name]; } - } - let fn = methodCache$7[name]; - if (!fn) { - if (isInt && access === 'set') { - // add auto-conversion between number and bigint - const Primitive = getPrimitiveClass$7(member); - const set = cb(originalName); - fn = function(offset, value, littleEndian) { - set.call(this, offset, Primitive(value), littleEndian); - }; - } else if (isSize && access === 'get') { - // use number instead of bigint where possible - const get = cb(originalName); - const min = BigInt(Number.MIN_SAFE_INTEGER); - const max = BigInt(Number.MAX_SAFE_INTEGER); - fn = function(offset, littleEndian) { - const value = get.call(this, offset, littleEndian); - if (min <= value && value <= max) { - return Number(value); - } else { - return value; - } - }; + }, + set(pointer, name, value) { + if (name in pointer) { + pointer[name] = value; } else { - fn = cb(name); + const target = pointer[TARGET_GETTER$7](); + target[name] = value; } - if (fn && fn.name !== name) { - Object.defineProperty(fn, 'name', { value: name, configurable: true, writable: false }); + return true; + }, + deleteProperty(pointer, name) { + if (name in pointer) { + delete pointer[name]; + } else { + const target = pointer[TARGET_GETTER$7](); + delete target[name]; } - methodCache$7[name] = fn; - } - return fn; -} + return true; + }, + has(pointer, name) { + if (name in pointer) { + return true; + } else { + const target = pointer[TARGET_GETTER$7](); + return name in target; + } + }, +}; -function useAllExtendedTypes$7() { - useExtendedBool$7(); - useExtendedInt$7(); - useExtendedUint$7(); - useExtendedFloat$7(); +function always$7() { + return true; } -const MemberType$7 = { - Void: 0, - Bool: 1, - Int: 2, - Uint: 3, - Float: 4, - EnumerationItem: 5, - Error: 6, - Object: 7, - Type: 8, - Comptime: 9, - Static: 10, - Literal: 11, - Null: 12, - Undefined: 13, -}; +function never$7() { + return false; +} -function isReadOnly$7(type) { - switch (type) { - case MemberType$7.Type: - case MemberType$7.Comptime: - case MemberType$7.Literal: - return true; - default: - return false; +function defineStructShape$7(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const memberDescriptors = {}; + for (const member of members) { + const { get, set } = getDescriptor$7(member, env); + memberDescriptors[member.name] = { get, set, configurable: true, enumerable: true }; + if (member.isRequired && set) { + set.required = true; + } } + const hasObject = !!members.find(m => m.type === MemberType$7.Object); + const propApplier = createPropertyApplier$7(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$7](arg); + if (hasPointer) { + this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); + } + } else if (arg && typeof(arg) === 'object') { + propApplier.call(this, arg); + } else if (arg !== undefined) { + throwInvalidInitializer$7(structure, 'object', arg); + } + }; + const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); + const instanceDescriptors = { + $: { get: getSelf$7, set: initializer }, + dataView: getDataViewDescriptor$7(structure), + base64: getBase64Descriptor$7(structure), + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getStructIterator$7 }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, + [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$f(structure, always$7) }, + [NORMALIZER$7]: { value: normalizeStruct$7 }, + [PROPS$7]: { value: members.map(m => m.name) }, + }; + const staticDescriptors = { + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); } -const factories$l = {}; - -function useVoid$7() { - factories$l[MemberType$7.Void] = getVoidDescriptor$7; +function normalizeStruct$7(cb, options) { + const object = {}; + for (const [ name, value ] of getStructEntries$7.call(this, options)) { + object[name] = cb(value); + } + return object; } -function useBool$7() { - factories$l[MemberType$7.Bool] = getBoolDescriptor$7; +function getStructEntries$7(options) { + return { + [Symbol.iterator]: getStructEntriesIterator$7.bind(this, options), + length: this[PROPS$7].length, + }; } -function useInt$7() { - factories$l[MemberType$7.Int] = getIntDescriptor$7; +function getStructIterator$7(options) { + const entries = getStructEntries$7.call(this, options); + return entries[Symbol.iterator](); } -function useUint$7() { - factories$l[MemberType$7.Uint] = getUintDescriptor$7; +function getStructEntriesIterator$7(options) { + const self = this; + const props = this[PROPS$7]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + value = [ current, handleError$7(() => self[current], options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getChildVivificator$f(structure) { + const { instance: { members } } = structure; + const objectMembers = {}; + for (const member of members.filter(m => m.type === MemberType$7.Object)) { + objectMembers[member.slot] = member; + } + return function vivificateChild(slot, writable = true) { + const member = objectMembers[slot]; + const { bitOffset, byteSize, structure: { constructor } } = member; + const dv = this[MEMORY$7]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + (bitOffset >> 3); + let len = byteSize; + if (len === undefined) { + if (bitOffset & 7) { + throwNotOnByteBoundary$7(member); + } + len = member.bitSize >> 3; + } + const childDV = new DataView(dv.buffer, offset, len); + const object = this[SLOTS$7][slot] = constructor.call(PARENT$7, childDV, { writable }); + return object; + } } -function useFloat$7() { - factories$l[MemberType$7.Float] = getFloatDescriptor$7; +function getPointerVisitor$f(structure, visitorOptions = {}) { + const { + isChildActive = always$7, + isChildMutable = always$7, + } = visitorOptions; + const { instance: { members } } = structure; + const pointerMembers = members.filter(m => m.structure.hasPointer); + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$7, + isMutable = always$7, + } = options; + const childOptions = { + ...options, + isActive: (object) => { + // make sure parent object is active, then check whether the child is active + return isActive(this) && isChildActive.call(this, object); + }, + isMutable: (object) => { + return isMutable(this) && isChildMutable.call(this, object); + }, + }; + for (const { slot } of pointerMembers) { + if (source) { + // when src is a the struct's template, most slots will likely be empty, + // since pointer fields aren't likely to have default values + const srcChild = source[SLOTS$7]?.[slot]; + if (!srcChild) { + continue; + } + childOptions.source = srcChild; + } + const child = this[SLOTS$7][slot] ?? (vivificate ? this[VIVIFICATOR$7](slot) : null); + if (child) { + child[POINTER_VISITOR$7](cb, childOptions); + } + } + }; } -function useEnumerationItem$7() { - factories$l[MemberType$7.EnumerationItem] = getEnumerationItemDescriptor$7; +function defineArgStruct$7(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const hasObject = !!members.find(m => m.type === MemberType$7.Object); + const constructor = structure.constructor = function(args) { + const dv = env.allocateMemory(byteSize, align); + this[MEMORY$7] = dv; + if (hasObject) { + this[SLOTS$7] = {}; + } + initializer.call(this, args); + }; + const argNames = members.slice(0, -1).map(m => m.name); + const argCount = argNames.length; + const initializer = function(args) { + if (args.length !== argCount) { + throwArgumentCountMismatch$7(structure, args.length); + } + for (const [ index, name ] of argNames.entries()) { + try { + this[name] = args[index]; + } catch (err) { + rethrowArgumentError$7(structure, index, err); + } + } + }; + const memberDescriptors = {}; + for (const member of members) { + memberDescriptors[member.name] = getDescriptor$7(member, env); + } + const isChildMutable = function(object) { + return (object === this.retval); + }; + defineProperties$7(constructor.prototype, { + ...memberDescriptors, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, + [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$f(structure, { isChildMutable }) }, + }); + defineProperties$7(constructor, { + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + }); + return constructor; } -function useError$7() { - factories$l[MemberType$7.Error] = getErrorDescriptor$7; +function defineArray$7(structure, env) { + const { + length, + byteSize, + align, + instance: { members: [ member ] }, + hasPointer, + } = structure; + const { get, set } = getDescriptor$7(member, env); + const hasStringProp = canBeString$7(member); + const propApplier = createPropertyApplier$7(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$7](arg); + if (hasPointer) { + this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); + } + } else { + if (typeof(arg) === 'string' && hasStringProp) { + arg = { string: arg }; + } + if (arg?.[Symbol.iterator]) { + arg = transformIterable$7(arg); + if (arg.length !== length) { + throwArrayLengthMismatch$7(structure, this, arg); + } + let i = 0; + for (const value of arg) { + set.call(this, i++, value); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$7(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$7(structure, arg); + } + } + }; + const finalizer = createArrayProxy$7; + const constructor = structure.constructor = createConstructor$7(structure, { initializer, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$7(member); + const hasObject = member.type === MemberType$7.Object; + const instanceDescriptors = { + $: { get: getProxy$7, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$7(structure), + base64: getBase64Descriptor$7(structure), + string: hasStringProp && getStringDescriptor$7(structure), + typedArray: typedArray && getTypedArrayDescriptor$7(structure), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$7 }, + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + [Symbol.iterator]: { value: getArrayIterator$7 }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$e(structure) }, + [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$e() }, + [NORMALIZER$7]: { value: normalizeArray$7 }, + }; + const staticDescriptors = { + child: { get: () => member.structure.constructor }, + [COMPAT$7]: { value: getCompatibleTags$7(structure) }, + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); } -function useObject$7() { - factories$l[MemberType$7.Object] = getObjectDescriptor$7; +function createArrayProxy$7() { + const proxy = new Proxy(this, proxyHandlers$e); + // hide the proxy so console wouldn't display a recursive structure + Object.defineProperty(this, PROXY$7, { value: proxy }); + return proxy; } -function useType$7() { - factories$l[MemberType$7.Type] = getTypeDescriptor$7; +function canBeString$7(member) { + return member.type === MemberType$7.Uint && [ 8, 16 ].includes(member.bitSize); } -function useComptime$7() { - factories$l[MemberType$7.Comptime] = getComptimeDescriptor$7; +function normalizeArray$7(cb, options) { + const array = []; + for (const [ index, value ] of getArrayEntries$7.call(this, options)) { + array.push(cb(value)); + } + return array; } -function useStatic$7() { - factories$l[MemberType$7.Static] = getStaticDescriptor$7; +function getArrayIterator$7() { + const self = this[ARRAY$7] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self.get(current); + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; } -function useLiteral$7() { - factories$l[MemberType$7.Literal] = getLiteralDescriptor$7; +function getArrayEntriesIterator$7(options) { + const self = this[ARRAY$7] ?? this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, handleError$7(() => self.get(current), options) ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; } -function useNull$7() { - factories$l[MemberType$7.Null] = getNullDescriptor$7; +function getArrayEntries$7(options) { + return { + [Symbol.iterator]: getArrayEntriesIterator$7.bind(this, options), + length: this.length, + }; } -function useUndefined$7() { - factories$l[MemberType$7.Undefined] = getUndefinedDescriptor$7; +function getChildVivificator$e(structure) { + const { instance: { members: [ member ]} } = structure; + const { byteSize, structure: elementStructure } = member; + return function getChild(index, writable = true) { + const { constructor } = elementStructure; + const dv = this[MEMORY$7]; + const parentOffset = dv.byteOffset; + const offset = parentOffset + byteSize * index; + const childDV = new DataView(dv.buffer, offset, byteSize); + const object = this[SLOTS$7][index] = constructor.call(PARENT$7, childDV, { writable }); + return object; + }; } -function isByteAligned$7({ bitOffset, bitSize, byteSize }) { - return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; +function getPointerVisitor$e(structure) { + return function visitPointers(cb, options = {}) { + const { + source, + vivificate = false, + isActive = always$7, + isMutable = always$7, + } = options; + const childOptions = { + ...options, + isActive: () => isActive(this), + isMutable: () => isMutable(this), + }; + for (let i = 0, len = this.length; i < len; i++) { + // no need to check for empty slots, since that isn't possible + if (source) { + childOptions.source = source?.[SLOTS$7][i]; + } + const child = this[SLOTS$7][i] ?? (vivificate ? this[VIVIFICATOR$7](i) : null); + if (child) { + child[POINTER_VISITOR$7](cb, childOptions); + } + } + }; } -function hasStandardIntSize({ bitSize }) { - return bitSize === 8 || bitSize === 16 || bitSize === 32 || bitSize === 64; +function transformIterable$7(arg) { + if (typeof(arg.length) === 'number') { + // it's an array of sort + return arg; + } + const iterator = arg[Symbol.iterator](); + const first = iterator.next(); + const length = first.value?.length; + if (typeof(length) === 'number' && Object.keys(first.value).join() === 'length') { + // return generator with length attached + return Object.assign((function*() { + let result; + while (!(result = iterator.next()).done) { + yield result.value; + } + })(), { length }); + } else { + const array = []; + let result = first; + while (!result.done) { + array.push(result.value); + result = iterator.next(); + } + return array; + } } -function hasStandardFloatSize({ bitSize }) { - return bitSize === 32 || bitSize === 64; -} +const proxyHandlers$e = { + get(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return array.get(index); + } else { + switch (name) { + case 'get': + if (!array[ELEMENT_GETTER$7]) { + array[ELEMENT_GETTER$7] = array.get.bind(array); + } + return array[ELEMENT_GETTER$7]; + case 'set': + if (!array[ELEMENT_SETTER$7]) { + array[ELEMENT_SETTER$7] = array.set.bind(array); + } + return array[ELEMENT_SETTER$7]; + case ARRAY$7: + return array; + default: + return array[name]; + } + } + }, + set(array, name, value) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + array.set(index, value); + } else { + switch (name) { + case 'get': + array[ELEMENT_GETTER$7] = value; + break; + case 'set': + array[ELEMENT_SETTER$7] = value; + break; + default: + array[name] = value; + } + } + return true; + }, + deleteProperty(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return false; + } else { + switch (name) { + case 'get': + delete array[ELEMENT_GETTER$7]; + break; + case 'set': + delete array[ELEMENT_SETTER$7]; + break; + default: + delete array[name]; + } + return true; + } + }, + has(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + return (index >= 0 && index < array.length); + } else { + return array[name]; + } + }, + ownKeys(array) { + const keys = []; + for (let i = 0, len = array.length; i < len; i++) { + keys.push(`${i}`); + } + keys.push('length', PROXY$7); + return keys; + }, + getOwnPropertyDescriptor(array, name) { + const index = (typeof(name) === 'symbol') ? 0 : name|0; + if (index !== 0 || index == name) { + if (index >= 0 && index < array.length) { + return { value: array.get(index), enumerable: true, writable: true, configurable: true }; + } + } else { + return Object.getOwnPropertyDescriptor(array, name); + } + }, +}; -function getDescriptor$7(member, env) { - const f = factories$l[member.type]; - return f(member, env); +function defineEnumerationShape$7(structure, env) { + const { + byteSize, + align, + instance: { + members: [ member ], + }, + } = structure; + const { get: getIndex, set: setIndex } = getDescriptor$7(member, env); + // get the enum descriptor instead of the int/uint descriptor + const { get, set } = getDescriptor$7({ ...member, type: MemberType$7.EnumerationItem, structure }, env); + const expected = [ 'string', 'number', 'tagged union' ]; + const propApplier = createPropertyApplier$7(structure); + const initializer = function(arg) { + if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$7(structure, expected, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'string' || typeof(arg) === 'number' || typeof(arg) === 'bigint') { + const items = constructor[ITEMS$7]; + let item = items[arg]; + if (!item) { + if (constructor[MORE$7] && typeof(arg) !== 'string') { + // create the item on-the-fly when enum is non-exhaustive + item = items[arg] = new constructor(undefined); + setIndex.call(item, arg); + defineProperties$7(item, { [NAME$7]: { value: `${arg}` } }); + } + } + return item; + } else if (arg?.[TAG$7] instanceof constructor) { + // a tagged union, return the active tag + return arg[TAG$7]; + } else if (!getDataView$7(structure, arg, env)) { + throwInvalidInitializer$7(structure, expected, arg); + } else { + return false; + } + }; + const constructor = structure.constructor = createConstructor$7(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass$7(member); + const toPrimitive = function(hint) { + return (hint === 'string') ? this.$[NAME$7] : getIndex.call(this); + }; + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$7(structure), + base64: getBase64Descriptor$7(structure), + typedArray: typedArray && getTypedArrayDescriptor$7(structure), + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + [Symbol.toPrimitive]: { value: toPrimitive }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [NORMALIZER$7]: { value: normalizeEnumerationItem$7 }, + }; + const staticDescriptors = { + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + [ITEMS$7]: { value: {} }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); +} +function normalizeEnumerationItem$7(cb) { + return cb(this.$[NAME$7]); } -function getVoidDescriptor$7(member, env) { - const { runtimeSafety } = env; - return { - get: function() { - return undefined; - }, - set: (runtimeSafety) - ? function(value) { - if (value !== undefined) { - throwNotUndefined$7(member); +function defineErrorSet$7(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { get: getIndex } = getDescriptor$7(member, env); + // get the error descriptor instead of the int/uint descriptor + const { get, set } = getDescriptor$7({ ...member, type: MemberType$7.Error, structure }, env); + const expected = [ 'string', 'number' ]; + const propApplier = createPropertyApplier$7(structure); + const initializer = function(arg) { + if (arg && typeof(arg) === 'object') { + try { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer$7(structure, expected, arg); + } + } catch (err) { + const { error } = arg; + if (typeof(error) === 'string') { + set.call(this, error); + } else { + throw err; } } - : function() {}, - } -} - -function getNullDescriptor$7(member, env) { - return { - get: function() { - return null; - }, - } -} - -function getUndefinedDescriptor$7(member, env) { - return { - get: function() { - return undefined; - }, - } -} - -function getBoolDescriptor$7(member, env) { - return getDescriptorUsing$7(member, env, getBoolAccessor$7) -} - -function getIntDescriptor$7(member, env) { - const getDataViewAccessor = addRuntimeCheck$7(env, getNumericAccessor$7); - return getDescriptorUsing$7(member, env, getDataViewAccessor) + } else if (arg !== undefined) { + set.call(this, arg); + } + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'number' || typeof(arg) === 'string') { + return constructor[ITEMS$7][arg]; + } else if (!getDataView$7(structure, arg, env)) { + throwInvalidInitializer$7(structure, expected, arg); + } else { + return false; + } + }; + const constructor = structure.constructor = createConstructor$7(structure, { initializer, alternateCaster }, env); + Object.setPrototypeOf(constructor.prototype, globalErrorSet$7.prototype); + const typedArray = structure.typedArray = getTypedArrayClass$7(member); + const getMessage = function() { return this.$.message; }; + const toStringTag = function() { return 'Error' }; + const toPrimitive = function(hint) { + if (hint === 'string') { + return Error.prototype.toString.call(this, hint); + } else { + return getIndex.call(this); + } + }; + const instanceDescriptors = { + $: { get, set }, + message: { get: getMessage }, + dataView: getDataViewDescriptor$7(structure), + base64: getBase64Descriptor$7(structure), + typedArray: typedArray && getTypedArrayDescriptor$7(structure), + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + // ensure that libraries that rely on the string tag for type detection will + // correctly identify the object as an error + [Symbol.toStringTag]: { get: toStringTag }, + [Symbol.toPrimitive]: { value: toPrimitive }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [NORMALIZER$7]: { value: get }, + }; + const staticDescriptors = { + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + [ITEMS$7]: { value: {} }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); } +let globalErrorSet$7; -function getUintDescriptor$7(member, env) { - const getDataViewAccessor = addRuntimeCheck$7(env, getNumericAccessor$7); - return getDescriptorUsing$7(member, env, getDataViewAccessor) +function getGlobalErrorSet$7() { + return globalErrorSet$7; } -function addRuntimeCheck$7(env, getDataViewAccessor) { - return function (access, member) { - const { - runtimeSafety = true, - } = env; - const accessor = getDataViewAccessor(access, member); - if (runtimeSafety && access === 'set') { - const { min, max } = getIntRange$7(member); - return function(offset, value, littleEndian) { - if (value < min || value > max) { - throwOverflow$7(member, value); +function defineErrorUnion$7(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const { get: getValue, set: setValue } = getDescriptor$7(members[0], env); + const { get: getError, set: setError } = getDescriptor$7(members[1], env); + const get = function() { + const error = getError.call(this, true); + if (error) { + throw error; + } else { + return getValue.call(this); + } + }; + const isValueVoid = members[0].type === MemberType$7.Void; + const acceptAny = members[1].structure.name === 'anyerror'; + const TargetError = (acceptAny) ? getGlobalErrorSet$7() : members[1].structure.constructor; + const isChildActive = function() { + return !getError.call(this, true); + }; + const clearValue = function() { + this[RESETTER$7](); + this[POINTER_VISITOR$7]?.(resetPointer$7); + }; + const hasObject = !!members.find(m => m.type === MemberType$7.Object); + const propApplier = createPropertyApplier$7(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$7](arg); + if (hasPointer) { + if (isChildActive.call(this)) { + this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); } - accessor.call(this, offset, value, littleEndian); - }; + } + } else if (arg instanceof TargetError) { + setError.call(this, arg); + clearValue.call(this); + } else if (arg !== undefined || isValueVoid) { + try { + // call setValue() first, in case it throws + setValue.call(this, arg); + setError.call(this, 0, true); + } catch (err) { + if (arg instanceof Error) { + // we give setValue a chance to see if the error is actually an acceptable value + // now is time to throw an error + throwNotInErrorSet$7(structure); + } else if (arg && typeof(arg) === 'object') { + try { + if (propApplier.call(this, arg) === 0) { + throw err; + } + } catch (err) { + const { error } = arg; + if (typeof(error) === 'string') { + setError.call(this, error); + clearValue.call(this); + } else { + throw err; + } + } + } else { + throw err; + } + } } - return accessor; + }; + const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); + const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; + const instanceDescriptors = { + '$': { get, set: initializer }, + dataView: getDataViewDescriptor$7(structure), + base64: getBase64Descriptor$7(structure), + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [RESETTER$7]: { value: getMemoryResetter$7(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, + [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$f(structure, { isChildActive }) }, + [NORMALIZER$7]: { value: normalizeValue$7 }, }; + const staticDescriptors = { + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); } -function getFloatDescriptor$7(member, env) { - return getDescriptorUsing$7(member, env, getNumericAccessor$7) -} - -function getValueDescriptor$7(member, env) { - // enum can be int or uint--need the type from the structure - const { type, structure } = member.structure.instance.members[0]; - // combine that with the offset/size - const valueMember = { ...member, type, structure }; - return getDescriptor$7(valueMember, env); -} - -function getEnumerationItemDescriptor$7(member, env) { - const { structure } = member; - const { get: getValue, set: setValue } = getValueDescriptor$7(member, env); - const findEnum = function(value) { - const { constructor } = structure; - // the enumeration constructor returns the object for the int value - const item = (value instanceof constructor) ? value : constructor(value); - if (!item) { - throwEnumExpected$7(structure, value); - } - return item +function defineOpaque$7(structure, env) { + const { + byteSize, + align, + } = structure; + const initializer = function() { + throwCreatingOpaque$7(structure); + }; + const valueAccessor = function() { + throwAccessingOpaque$7(structure); + }; + const toPrimitive = function(hint) { + const { name } = structure; + return `[opaque ${name}]`; + }; + const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); + const instanceDescriptors = { + $: { get: valueAccessor, set: valueAccessor }, + dataView: getDataViewDescriptor$7(structure), + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + [Symbol.toPrimitive]: { value: toPrimitive }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [NORMALIZER$7]: { value: normalizeOpaque$7 }, }; - return { - get: (getValue.length === 0) - ? function getEnum() { - const value = getValue.call(this); - return findEnum(value); - } - : function getEnumElement(index) { - const value = getValue.call(this, index); - return findEnum(value); - }, - set: (setValue.length === 1) - ? function setEnum(value) { - // call Symbol.toPrimitive directly as enum can be bigint or number - const item = findEnum(value); - setValue.call(this, item[Symbol.toPrimitive]()); - } - : function setEnumElement(index, value) { - const item = findEnum(value); - setValue.call(this, index, item[Symbol.toPrimitive]()); - }, + const staticDescriptors = { + [COMPAT$7]: { value: getCompatibleTags$7(structure) }, + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); +} +function normalizeOpaque$7(cb) { + return {}; } -function getErrorDescriptor$7(member, env) { - const { structure } = member; - const { name } = structure; - const { get: getValue, set: setValue } = getValueDescriptor$7(member, env); - const acceptAny = name === 'anyerror'; - const globalErrorSet = getGlobalErrorSet$7(); - const findError = function(value, allowZero = false) { - const { constructor } = structure; - let item; - if (value === 0 && allowZero) { - return; - } else if (value instanceof Error) { - if (value instanceof (acceptAny ? globalErrorSet : constructor)) { - item = value; - } else { - throwNotInErrorSet$7(structure); - } +function defineOptional$7(structure, env) { + const { + byteSize, + align, + instance: { members }, + hasPointer, + } = structure; + const { get: getValue, set: setValue } = getDescriptor$7(members[0], env); + const { get: getPresent, set: setPresent } = getDescriptor$7(members[1], env); + const hasPresentFlag = !(members[0].bitSize > 0 && members[0].bitOffset === members[1].bitOffset); + const get = function() { + const present = getPresent.call(this); + if (present) { + return getValue.call(this); } else { - item = acceptAny ? globalErrorSet[value] : constructor(value); - if (!item) { - throwErrorExpected$7(structure, value); - } + this[POINTER_VISITOR$7]?.(resetPointer$7); + return null; } - return item }; - return { - get: (getValue.length === 0) - ? function getError(allowZero) { - const value = getValue.call(this); - return findError(value, allowZero); - } - : function getErrorElement(index) { - const value = getValue.call(this, index); - return findError(value, false); - }, - set: (setValue.length === 1) - ? function setError(value, allowZero) { - const item = findError(value, allowZero); - setValue.call(this, Number(item ?? 0)); + const isValueVoid = members[0].type === MemberType$7.Void; + const isChildActive = getPresent; + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$7](arg); + if (hasPointer) { + // don't bother copying pointers when it's empty + if (isChildActive.call(arg)) { + this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); + } + } + } else if (arg === null) { + setPresent.call(this, false); + this[RESETTER$7]?.(); + // clear references so objects can be garbage-collected + this[POINTER_VISITOR$7]?.(resetPointer$7); + } else if (arg !== undefined || isValueVoid) { + // call setValue() first, in case it throws + setValue.call(this, arg); + if (hasPresentFlag || !env.inFixedMemory(this)) { + // since setValue() wouldn't write address into memory when the pointer is in + // relocatable memory, we need to use setPresent() in order to write something + // non-zero there so that we know the field is populated + setPresent.call(this, true); } - : function setError(index, value) { - const item = findError(value, false); - setValue.call(this, index, Number(item)); - }, + } }; + const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); + const { bitOffset: valueBitOffset, byteSize: valueByteSize } = members[0]; + const hasObject = !!members.find(m => m.type === MemberType$7.Object); + const instanceDescriptors = { + $: { get, set: initializer }, + dataView: getDataViewDescriptor$7(structure), + base64: getBase64Descriptor$7(structure), + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + // no need to reset the value when it's a pointer, since setPresent() would null out memory used by the pointer + [RESETTER$7]: !hasPointer && { value: getMemoryResetter$7(valueBitOffset / 8, valueByteSize) }, + [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, + [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$f(structure, { isChildActive }) }, + [NORMALIZER$7]: { value: normalizeValue$7 }, + }; + const staticDescriptors = { + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); } -function isValueExpected$7(structure) { - switch (structure.type) { - case StructureType$7.Primitive: - case StructureType$7.ErrorUnion: - case StructureType$7.Optional: - case StructureType$7.Enumeration: - case StructureType$7.ErrorSet: - return true; - default: - return false; - } -} - -function getValue$7(slot) { - const object = this[SLOTS$7][slot] ?? this[VIVIFICATOR$7](slot); - return object[GETTER$7](); -} - -function getObject$7(slot) { - const object = this[SLOTS$7][slot] ?? this[VIVIFICATOR$7](slot); - return object; -} - -function setValue$7(slot, value) { - const object = this[SLOTS$7][slot] ?? this[VIVIFICATOR$7](slot); - object[SETTER$7](value); -} - -function bindSlot$7(slot, { get, set }) { - if (slot !== undefined) { - return { - get: function() { - return get.call(this, slot); - }, - set: (set) - ? function(arg) { - return set.call(this, slot, arg); - } - : undefined, - }; - } else { - // array accessors - return { get, set }; +function defineSlice$7(structure, env) { + const { + align, + instance: { + members: [ member ], + }, + hasPointer, + } = structure; + const { get, set } = getDescriptor$7(member, env); + const { byteSize: elementSize, structure: elementStructure } = member; + const sentinel = getSentinel$7(structure, env); + if (sentinel) { + // zero-terminated strings aren't expected to be commonly used + // so we're not putting this prop into the standard structure + structure.sentinel = sentinel; } + const hasStringProp = canBeString$7(member); + const shapeDefiner = function(dv, length, fixed = false) { + if (!dv) { + dv = env.allocateMemory(length * elementSize, align, fixed); + } + this[MEMORY$7] = dv; + this[LENGTH$7] = length; + }; + const shapeChecker = function(arg, length) { + if (length !== this[LENGTH$7]) { + throwArrayLengthMismatch$7(structure, this, arg); + } + }; + // the initializer behave differently depending on whether it's called by the + // constructor or by a member setter (i.e. after object's shape has been established) + const propApplier = createPropertyApplier$7(structure); + const initializer = function(arg, fixed = false) { + if (arg instanceof constructor) { + if (!this[MEMORY$7]) { + shapeDefiner.call(this, null, arg.length, fixed); + } else { + shapeChecker.call(this, arg, arg.length); + } + this[COPIER$7](arg); + if (hasPointer) { + this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); + } + } else if (typeof(arg) === 'string' && hasStringProp) { + initializer.call(this, { string: arg }, fixed); + } else if (arg?.[Symbol.iterator]) { + arg = transformIterable$7(arg); + if (!this[MEMORY$7]) { + shapeDefiner.call(this, null, arg.length, fixed); + } else { + shapeChecker.call(this, arg, arg.length); + } + let i = 0; + for (const value of arg) { + sentinel?.validateValue(value, i, arg.length); + set.call(this, i++, value); + } + } else if (typeof(arg) === 'number') { + if (!this[MEMORY$7] && arg >= 0 && isFinite(arg)) { + shapeDefiner.call(this, null, arg); + } else { + throwInvalidArrayInitializer$7(structure, arg, !this[MEMORY$7]); + } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$7(structure, arg); + } + } else if (arg !== undefined) { + throwInvalidArrayInitializer$7(structure, arg); + } + }; + const finalizer = createArrayProxy$7; + const constructor = structure.constructor = createConstructor$7(structure, { initializer, shapeDefiner, finalizer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$7(member); + const hasObject = member.type === MemberType$7.Object; + const shapeHandlers = { shapeDefiner }; + const instanceDescriptors = { + $: { get: getProxy$7, set: initializer }, + length: { get: getLength$7 }, + dataView: getDataViewDescriptor$7(structure, shapeHandlers), + base64: getBase64Descriptor$7(structure, shapeHandlers), + string: hasStringProp && getStringDescriptor$7(structure, shapeHandlers), + typedArray: typedArray && getTypedArrayDescriptor$7(structure, shapeHandlers), + get: { value: get }, + set: { value: set }, + entries: { value: getArrayEntries$7 }, + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + [Symbol.iterator]: { value: getArrayIterator$7 }, + [COPIER$7]: { value: getMemoryCopier$7(elementSize, true) }, + [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$e(structure) }, + [POINTER_VISITOR$7]: hasPointer && { value: getPointerVisitor$e() }, + [NORMALIZER$7]: { value: normalizeArray$7 }, + }; + const staticDescriptors = { + child: { get: () => elementStructure.constructor }, + [COMPAT$7]: { value: getCompatibleTags$7(structure) }, + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: elementSize }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); } -function getObjectDescriptor$7(member, env) { - const { structure, slot } = member; - return bindSlot$7(slot, { - get: isValueExpected$7(structure) ? getValue$7 : getObject$7, - set: setValue$7, - }); -} - -function getType$7(slot) { - // unsupported types will have undefined structure - const structure = this[SLOTS$7][slot]; - return structure?.constructor; -} - -function getTypeDescriptor$7(member, env) { - const { slot } = member; - return bindSlot$7(slot, { get: getType$7 }); -} - -function getComptimeDescriptor$7(member, env) { - const { slot, structure } = member; - return bindSlot$7(slot, { - get: isValueExpected$7(structure) ? getValue$7 : getObject$7, - }); -} - -function getStaticDescriptor$7(member, env) { - const { slot, structure } = member; - return bindSlot$7(slot, { - get: isValueExpected$7(structure) ? getValue$7 : getObject$7, - set: setValue$7, - }); -} - -function getLiteral$7(slot) { - const object = this[SLOTS$7][slot]; - return object.string; -} - -function getLiteralDescriptor$7(member, env) { - const { slot } = member; - return bindSlot$7(slot, { get: getLiteral$7 }); +function getLength$7() { + return this[LENGTH$7]; } -function getDescriptorUsing$7(member, env, getDataViewAccessor) { +function getSentinel$7(structure, env) { const { - littleEndian = true, + runtimeSafety = true, } = env; - const { bitOffset, byteSize } = member; - const getter = getDataViewAccessor('get', member); - const setter = getDataViewAccessor('set', member); - if (bitOffset !== undefined) { - const offset = bitOffset >> 3; - return { - get: function getValue() { - /* WASM-ONLY */ - try { - /* WASM-ONLY-END*/ - return getter.call(this[MEMORY$7], offset, littleEndian); - /* WASM-ONLY */ - } catch (err) { - if (err instanceof TypeError && restoreMemory$7.call(this)) { - return getter.call(this[MEMORY$7], offset, littleEndian); - } else { - throw err; - } - } - /* WASM-ONLY-END*/ - }, - set: function setValue(value) { - /* WASM-ONLY */ - try { - /* WASM-ONLY-END*/ - return setter.call(this[MEMORY$7], offset, value, littleEndian); - /* WASM-ONLY */ - } catch (err) { - if (err instanceof TypeError && restoreMemory$7.call(this)) { - return setter.call(this[MEMORY$7], offset, value, littleEndian); - } else { - throw err; - } - } - /* WASM-ONLY-END*/ + const { + byteSize, + instance: { members: [ member, sentinel ], template }, + } = structure; + if (!sentinel) { + return; + } + const { get: getSentinelValue } = getDescriptor$7(sentinel, env); + const value = getSentinelValue.call(template, 0); + const { get } = getDescriptor$7(member, env); + const validateValue = (runtimeSafety) ? function(v, i, l) { + if (v === value && i !== l - 1) { + throwMisplacedSentinel$7(structure, v, i, l); + } else if (v !== value && i === l - 1) { + throwMissingSentinel$7(structure, value, i); + } + } : function(v, i, l) { + if (v !== value && i === l - 1) { + throwMissingSentinel$7(structure, value, l); + } + }; + const validateData = (runtimeSafety) ? function(source, len) { + for (let i = 0; i < len; i++) { + const v = get.call(source, i); + if (v === value && i !== len - 1) { + throwMisplacedSentinel$7(structure, value, i, len); + } else if (v !== value && i === len - 1) { + throwMissingSentinel$7(structure, value, len); } } - } else { - return { - get: function getElement(index) { - try { - return getter.call(this[MEMORY$7], index * byteSize, littleEndian); - } catch (err) { - /* WASM-ONLY */ - if (err instanceof TypeError && restoreMemory$7.call(this)) { - return getter.call(this[MEMORY$7], index * byteSize, littleEndian); - } else { - /* WASM-ONLY-END */ - rethrowRangeError$7(member, index, err); - /* WASM-ONLY */ - } - /* WASM-ONLY-END */ - } - }, - set: function setElement(index, value) { - /* WASM-ONLY */ - try { - /* WASM-ONLY-END */ - return setter.call(this[MEMORY$7], index * byteSize, value, littleEndian); - /* WASM-ONLY */ - } catch (err) { - if (err instanceof TypeError && restoreMemory$7.call(this)) { - return setter.call(this[MEMORY$7], index * byteSize, value, littleEndian); - } else { - rethrowRangeError$7(member, index, err); - } - } - /* WASM-ONLY-END */ - }, + } : function(source, len) { + if (len * byteSize === source[MEMORY$7].byteLength) { + const i = len - 1; + const v = get.call(source, i); + if (v !== value) { + throwMissingSentinel$7(structure, value, len); + } } - } -} - -function useAllMemberTypes$7() { - useVoid$7(); - useNull$7(); - useUndefined$7(); - useBool$7(); - useInt$7(); - useUint$7(); - useFloat$7(); - useEnumerationItem$7(); - useError$7(); - useObject$7(); - useType$7(); - useComptime$7(); - useStatic$7(); - useLiteral$7(); + }; + const bytes = template[MEMORY$7]; + return { value, bytes, validateValue, validateData }; } -function generateCode(definition, params) { - const { structures, options, keys } = definition; +function defineUnionShape$7(structure, env) { const { - runtimeURL, - binarySource = null, - topLevelAwait = true, - omitExports = false, - declareFeatures = false, - addonDir = null, - } = params; - const features = (declareFeatures) ? getFeaturesUsed(structures) : []; - const exports = getExports(structures); - const lines = []; - const add = manageIndentation(lines); - add(`import {`); - for (const name of [ 'createEnvironment', ...features ]) { - add(`${name},`); - } - add(`} from ${JSON.stringify(runtimeURL)};`); - // reduce file size by only including code of features actually used - // dead-code remover will take out code not referenced here - add(`\n// activate features`); - for (const feature of features) { - add(`${feature}();`); - } - // write out the structures as object literals - addStructureDefinitions(lines, definition); - add(`\n// create runtime environment`); - add(`const env = createEnvironment(${addonDir ? JSON.stringify({ addonDir }, undefined, 2) : null});`); - add(`const __zigar = env.getControlObject();`); - add(`\n// recreate structures`); - add(`env.recreateStructures(structures, options);`); - if (binarySource) { - add(`\n// initiate loading and compilation of WASM bytecodes`); - add(`const source = ${binarySource};`); - add(`env.loadModule(source)`); - // if top level await is used, we don't need to write changes into fixed memory buffers - add(`env.linkVariables(${!topLevelAwait});`); + type, + byteSize, + align, + instance: { members, template }, + hasPointer, + } = structure; + const { runtimeSafety } = env; + const isTagged = (type === StructureType$7.TaggedUnion); + const exclusion = (isTagged || (type === StructureType$7.BareUnion && runtimeSafety)); + const memberDescriptors = {}; + const memberInitializers = {}; + const memberValueGetters = {}; + const valueMembers = (exclusion) ? members.slice(0, -1) : members; + const selectorMember = (exclusion) ? members[members.length - 1] : null; + const { get: getSelector, set: setSelector } = (exclusion) ? getDescriptor$7(selectorMember, env) : {}; + const getActiveField = (isTagged) + ? function() { + const item = getSelector.call(this); + return item[NAME$7]; + } + : function() { + const index = getSelector.call(this); + return valueMembers[index].name; + }; + const setActiveField = (isTagged) + ? function(name) { + const { constructor } = selectorMember.structure; + setSelector.call(this, constructor[name]); + } + : function(name) { + const index = valueMembers.findIndex(m => m.name === name); + setSelector.call(this, index); + }; + for (const member of valueMembers) { + const { name } = member; + const { get: getValue, set: setValue } = getDescriptor$7(member, env); + const get = (exclusion) + ? function() { + const currentName = getActiveField.call(this); + if (name !== currentName) { + if (isTagged) { + // tagged union allows inactive member to be queried + return null; + } else { + // whereas bare union does not, since the condition is not detectable + // when runtime safety is off + throwInactiveUnionProperty$7(structure, name, currentName); + } + } + this[POINTER_VISITOR$7]?.(resetPointer$7); + return getValue.call(this); + } + : getValue; + const set = (exclusion && setValue) + ? function(value) { + const currentName = getActiveField.call(this); + if (name !== currentName) { + throwInactiveUnionProperty$7(structure, name, currentName); + } + setValue.call(this, value); + } + : setValue; + const init = (exclusion && setValue) + ? function(value) { + setActiveField.call(this, name); + setValue.call(this, value); + this[POINTER_VISITOR$7]?.(resetPointer$7); + } + : setValue; + memberDescriptors[name] = { get, set, configurable: true, enumerable: true }; + memberInitializers[name] = init; + memberValueGetters[name] = getValue; } - add(`\n// export root namespace and its methods and constants`); - add(`const { constructor } = root;`); - if (!omitExports) { - add(`export { constructor as default, __zigar }`); - // the first two exports are default and __zigar - const exportables = exports.slice(2); - if (exportables.length > 0) { - add(`export const {`); - for (const name of exportables) { - add(`${name},`); + const hasDefaultMember = !!valueMembers.find(m => !m.isRequired); + const memberKeys = Object.keys(memberDescriptors); + const propApplier = createPropertyApplier$7(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + /* WASM-ONLY-END */ + this[COPIER$7](arg); + if (hasPointer) { + this[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); } - add(`} = constructor;`); + } else if (arg && typeof(arg) === 'object') { + let found = 0; + for (const key of memberKeys) { + if (key in arg) { + found++; + } + } + if (found > 1) { + throwMultipleUnionInitializers$7(structure); + } + if (propApplier.call(this, arg) === 0 && !hasDefaultMember) { + throwMissingUnionInitializer$7(structure, arg, exclusion); + } + } else if (arg !== undefined) { + throwInvalidInitializer$7(structure, 'object with a single property', arg); } - } - if (topLevelAwait && binarySource) { - add(`await __zigar.init();`); - } - const code = lines.join('\n'); - return { code, exports, structures }; -} - -function addStructureDefinitions(lines, definition) { - const { structures, options, keys } = definition; - const { MEMORY, SLOTS, CONST } = keys; - const add = manageIndentation(lines); - const defaultStructure = { - constructor: null, - typedArray: null, - type: StructureType$7.Primitive, - name: undefined, - byteSize: 0, - align: 0, - isConst: false, - hasPointer: false, - instance: { - members: [], - methods: [], - template: null, - }, - static: { - members: [], - methods: [], - template: null, - }, }; - add(`\n// structure defaults`); - add(`const s = {`); - for (const [ name, value ] of Object.entries(defaultStructure)) { - switch (name) { - case 'instance': - case 'static': - add(`${name}: {`); - for (const [ name2, value2 ] of Object.entries(value)) { - add(`${name2}: ${JSON.stringify(value2)},`); - } - add(`},`); - break; - default: - add(`${name}: ${JSON.stringify(value)},`); + // non-tagged union as marked as not having pointers--if there're actually + // members with pointers, we need to disable them + const pointerMembers = members.filter(m => m.structure.hasPointer); + const hasInaccessiblePointer = !hasPointer && (pointerMembers.length > 0); + const modifier = (hasInaccessiblePointer && !env.comptime) + ? function() { + // make pointer access throw + this[POINTER_VISITOR$7](disablePointer$7, { vivificate: true }); } - } - add(`};`); - const defaultMember = { - type: MemberType$7.Void, - isRequired: false, + : undefined; + const constructor = structure.constructor = createConstructor$7(structure, { modifier, initializer }, env); + const fieldDescriptor = (isTagged) + ? { + // for tagged union, only the active field + get() { return [ getActiveField.call(this) ] } + } + : { + // for bare and extern union, all members are included + value: valueMembers.map(m => m.name) + }; + const isChildActive = (isTagged) + ? function(child) { + const name = getActiveField.call(this); + const active = memberValueGetters[name].call(this); + return child === active; + } + : never$7; + const hasAnyPointer = hasPointer || hasInaccessiblePointer; + const hasObject = !!members.find(m => m.type === MemberType$7.Object); + const instanceDescriptors = { + $: { get: getSelf$7, set: initializer, configurable: true }, + dataView: getDataViewDescriptor$7(structure), + base64: getBase64Descriptor$7(structure), + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + ...memberDescriptors, + [Symbol.iterator]: { value: getUnionIterator$7 }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [TAG$7]: isTagged && { get: getSelector, configurable: true }, + [VIVIFICATOR$7]: hasObject && { value: getChildVivificator$f(structure) }, + [POINTER_VISITOR$7]: hasAnyPointer && { value: getPointerVisitor$f(structure, { isChildActive }) }, + [PROP_GETTERS$7]: { value: memberValueGetters }, + [NORMALIZER$7]: { value: normalizeUnion$7 }, + [PROPS$7]: fieldDescriptor, + }; + const staticDescriptors = { + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, }; - add(`\n// member defaults`); - add(`const m = {`); - for (const [ name, value ] of Object.entries(defaultMember)) { - add(`${name}: ${JSON.stringify(value)},`); - } - add(`};`); - // create empty objects first, to allow objects to reference each other - add(``); - const structureNames = new Map(); - const structureMap = new Map(); - for (const [ index, structure ] of structures.entries()) { - const varname = `s${index}`; - structureNames.set(structure, varname); - structureMap.set(structure.constructor, structure); - } - for (const slice of chunk(structureNames.values(), 10)) { - add(`const ${slice.map(n => `${n} = {}`).join(', ')};`); - } - const objects = findAllObjects(structures, SLOTS); - const objectNames = new Map(); - const views = []; - for (const [ index, object ] of objects.entries()) { - const varname = `o${index}`; - objectNames.set(object, varname); - if (object[MEMORY]) { - views.push(object[MEMORY]); + attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); + // replace regular setters with ones that change the active field + const setters = constructor.prototype[PROP_SETTERS$7]; + for (const [ name, init ] of Object.entries(memberInitializers)) { + if (init) { + setters[name] = init; } } - for (const slice of chunk(objectNames.values(), 10)) { - add(`const ${slice.map(n => `${n} = {}`).join(', ')};`); +} +function normalizeUnion$7(cb, options) { + const object = {}; + for (const [ name, value ] of getUnionEntries$7.call(this, options)) { + object[name] = cb(value); } - // define buffers - const arrayBufferNames = new Map(); - for (const [ index, dv ] of views.entries()) { - if (!arrayBufferNames.get(dv.buffer)) { - const varname = `a${index}`; - arrayBufferNames.set(dv.buffer, varname); - if (dv.buffer.byteLength > 0) { - const ta = new Uint8Array(dv.buffer); - add(`const ${varname} = new Uint8Array([ ${ta.join(', ')} ]);`); + return object; +} + +function getUnionEntries$7(options) { + return { + [Symbol.iterator]: getUnionEntriesIterator$7.bind(this, options), + length: this[PROPS$7].length, + }; +} + +function getUnionIterator$7(options) { + const entries = getUnionEntries$7.call(this, options); + return entries[Symbol.iterator](); +} + +function getUnionEntriesIterator$7(options) { + const self = this; + const props = this[PROPS$7]; + const getters = this[PROP_GETTERS$7]; + let index = 0; + return { + next() { + let value, done; + if (index < props.length) { + const current = props[index++]; + // get value of prop with no check + value = [ current, handleError$7(() => getters[current].call(self), options) ]; + done = false; } else { - add(`const ${varname} = new Uint8Array();`); + done = true; } - } + return { value, done }; + }, + }; +} + +function defineVector$7(structure, env) { + const { + length, + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { bitSize: elementBitSize, structure: elementStructure } = member; + const elementDescriptors = {}; + for (let i = 0, bitOffset = 0; i < length; i++, bitOffset += elementBitSize) { + const { get, set } = getDescriptor$7({ ...member, bitOffset }, env); + elementDescriptors[i] = { get, set, configurable: true }; } - // add properties to objects - if (objects.length > 0) { - add('\n// define objects'); - for (const object of objects) { - const varname = objectNames.get(object); - const structure = structureMap.get(object.constructor); - const { [MEMORY]: dv, [SLOTS]: slots } = object; - add(`Object.assign(${varname}, {`); - if (structure) { - add(`structure: ${structureNames.get(structure)},`); + const propApplier = createPropertyApplier$7(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$7](arg); + } else if (arg?.[Symbol.iterator]) { + let argLen = arg.length; + if (typeof(argLen) !== 'number') { + arg = [ ...arg ]; + argLen = arg.length; } - if (dv) { - const buffer = arrayBufferNames.get(dv.buffer); - const pairs = [ `array: ${buffer}` ]; - if (dv.byteLength < dv.buffer.byteLength) { - pairs.push(`offset: ${dv.byteOffset}`); - pairs.push(`length: ${dv.byteLength}`); - } - add(`memory: { ${pairs.join(', ')} },`); - if (dv.hasOwnProperty('reloc')) { - add(`reloc: ${dv.reloc},`); - if (object[CONST]) { - add(`const: true,`); - } - } + if (argLen !== length) { + throwArrayLengthMismatch$7(structure, this, arg); } - const entries = (slots) ? Object.entries(slots).filter(a => a[1]) : []; - if (entries.length > 0) { - add(`slots: {`); - const pairs = entries.map(([slot, child]) => `${slot}: ${objectNames.get(child)}`); - for (const slice of chunk(pairs, 10)) { - add(slice.join(', ') + ','); - } - add(`},`); + let i = 0; + for (const value of arg) { + this[PROP_SETTERS$7][i++].call(this, value); } - add(`});`); - } - } - const methods = []; - for (const structure of structures) { - // add static members; instance methods are also static methods, so - // we don't need to add them separately - methods.push(...structure.static.methods); - } - const methodNames = new Map(); - if (methods.length > 0) { - add(`\n// define functions`); - for (const [ index, method ] of methods.entries()) { - const varname = `f${index}`; - methodNames.set(method, varname); - add(`const ${varname} = {`); - for (const [ name, value ] of Object.entries(method)) { - switch (name) { - case 'argStruct': - add(`${name}: ${structureNames.get(value)},`); - break; - default: - add(`${name}: ${JSON.stringify(value)},`); - } + } else if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + throwInvalidArrayInitializer$7(structure, arg); } - add(`};`); + } else if (arg !== undefined) { + throwInvalidArrayInitializer$7(structure, arg); } + }; + const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$7(member); + const instanceDescriptors = { + ...elementDescriptors, + $: { get: getSelf$7, set: initializer }, + length: { value: length }, + dataView: getDataViewDescriptor$7(structure), + base64: getBase64Descriptor$7(structure), + typedArray: typedArray && getTypedArrayDescriptor$7(structure), + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + entries: { value: getVectorEntries$7 }, + delete: { value: getDestructor$7(structure) }, + [Symbol.iterator]: { value: getVectorIterator$7 }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [NORMALIZER$7]: { value: normalizeVector$7 }, + }; + const staticDescriptors = { + child: { get: () => elementStructure.constructor }, + [COMPAT$7]: { value: getCompatibleTags$7(structure) }, + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); +} + +function normalizeVector$7(cb, options) { + const array = []; + for (const [ index, value ] of getVectorEntries$7.call(this, options)) { + array.push(cb(value)); } - add('\n// define structures'); - for (const structure of structures) { - const varname = structureNames.get(structure); - add(`Object.assign(${varname}, {`); - add(`...s,`); - for (const [ name, value ] of Object.entries(structure)) { - if (isDifferent(value, defaultStructure[name])) { - switch (name) { - case 'constructor': - case 'typedArray': - case 'sentinel': - break; - case 'instance': - case 'static': { - const { methods, members, template } = value; - add(`${name}: {`); - add(`members: [`); - for (const member of members) { - add(`{`); - add(`...m,`); - for (const [ name, value ] of Object.entries(member)) { - if (isDifferent(value, defaultMember[name])) { - switch (name) { - case 'structure': - add(`${name}: ${structureNames.get(value)},`); - break; - default: - add(`${name}: ${JSON.stringify(value)},`); - } - } - } - add(`},`); - } - add(`],`); - add(`methods: [`); - for (const slice of chunk(methods, 10)) { - add(slice.map(m => methodNames.get(m)).join(', ') + ','); - } - add(`],`); - if (template) { - add(`template: ${objectNames.get(template)}`); - } - add(`},`); - } break; - default: - add(`${name}: ${JSON.stringify(value)},`); - } + return array; +} + +function getVectorIterator$7() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = self[current]; + done = false; + } else { + done = true; } - } - add(`});`); - } - add(`const structures = [`); - for (const slice of chunk([ ...structureNames.values() ], 10)) { - add(slice.join(', ') + ','); - } - add(`];`); - const root = structures[structures.length - 1]; - add(`const root = ${structureNames.get(root)};`); - add(`const options = {`); - for (const [ name, value ] of Object.entries(options)) { - add(`${name}: ${value},`); - } - add(`};`); - return lines; + return { value, done }; + }, + }; +} + +function getVectorEntriesIterator$7() { + const self = this; + const length = this.length; + let index = 0; + return { + next() { + let value, done; + if (index < length) { + const current = index++; + value = [ current, self[current] ]; + done = false; + } else { + done = true; + } + return { value, done }; + }, + }; +} + +function getVectorEntries$7() { + return { + [Symbol.iterator]: getVectorEntriesIterator$7.bind(this), + length: this.length, + }; } -function getExports(structures) { - const root = structures[structures.length - 1]; - const { constructor } = root; - const exportables = []; - // export only members whose names are legal JS identifiers - const legal = /^[$\w]+$/; - for (const method of root.static.methods) { - if (legal.test(method.name)) { - exportables.push(method.name); - } - } - for (const member of root.static.members) { - // only read-only properties are exportable - if (isReadOnly$7(member.type) && legal.test(member.name)) { - try { - // make sure that getter wouldn't throw (possible with error union) - constructor[member.name]; - exportables.push(member.name); - } catch (err) { - } - } - } - return [ 'default', '__zigar', ...exportables ]; +const StructureType$7 = { + Primitive: 0, + Array: 1, + Struct: 2, + ExternStruct: 3, + PackedStruct: 4, + ArgStruct: 5, + ExternUnion: 6, + BareUnion: 7, + TaggedUnion: 8, + ErrorUnion: 9, + ErrorSet: 10, + Enumeration: 11, + Optional: 12, + Pointer: 13, + Slice: 14, + Vector: 15, + Opaque: 16, + Function: 17, +}; + +const factories$n = Array(Object.values(StructureType$7).length); + +function usePrimitive$7() { + factories$n[StructureType$7.Primitive] = definePrimitive$7; } -function manageIndentation(lines) { - let indent = 0; - return (s) => { - if (/^\s*[\]\}]/.test(s)) { - indent--; - } - const lastLine = lines[lines.length - 1]; - if ((lastLine?.endsWith('[') && s.startsWith(']')) - || (lastLine?.endsWith('{') && s.startsWith('}'))) { - lines[lines.length - 1] += s; - } else { - lines.push(' '.repeat(indent * 2) + s); - } - if (/[\[\{]\s*$/.test(s)) { - indent++; - } - }; +function useArray$7() { + factories$n[StructureType$7.Array] = defineArray$7; } -function isDifferent(value, def) { - if (value === def) { - return false; - } - if (def == null) { - return value != null; - } - if (typeof(def) === 'object' && typeof(value) === 'object') { - const valueKeys = Object.keys(value); - const defKeys = Object.keys(def); - if (valueKeys.length !== defKeys.length) { - return true; - } - for (const key of defKeys) { - if (isDifferent(value[key], def[key])) { - return true; - } - } - return false; - } - return true; +function useStruct$7() { + factories$n[StructureType$7.Struct] = defineStructShape$7; } -function* chunk(arr, n) { - if (!Array.isArray(arr)) { - arr = [ ...arr ]; - } - for (let i = 0; i < arr.length; i += n) { - yield arr.slice(i, i + n); - } +function usePackedStruct$7() { + factories$n[StructureType$7.PackedStruct] = defineStructShape$7; } -async function findFile(path, follow = true) { - try { - return await (follow ? stat(path) : lstat(path)); - } catch (err) { - } +function useExternStruct$7() { + factories$n[StructureType$7.ExternStruct] = defineStructShape$7; } -function findFileSync(path, follow = true) { - try { - return follow ? statSync(path) : lstatSync(path); - } catch (err) { - } +function useArgStruct$7() { + factories$n[StructureType$7.ArgStruct] = defineArgStruct$7; } -async function findMatchingFiles(dir, re) { - const map = new Map(); - const scanned = new Map(); - const scan = async (dir) => { - /* c8 ignore next 3 */ - if (scanned.get(dir)) { - return; - } - scanned.set(dir, true); - try { - const list = await readdir(dir); - for (const name of list) { - if (name.startsWith('.') || name === 'node_modules' || name === 'zig-cache') { - continue; - } - const path = join(dir, name); - const info = await findFile(path); - if (info?.isDirectory()) { - await scan(path); - } else if (info?.isFile() && re.test(name)) { - map.set(path, info); - } - } - /* c8 ignore next 2 */ - } catch (err) { - } - }; - await scan(dir); - return map; +function useExternUnion$7() { + factories$n[StructureType$7.ExternUnion] = defineUnionShape$7; } -function findMatchingFilesSync(dir, re) { - const map = new Map(); - const scanned = new Map(); - const scan = (dir) => { - /* c8 ignore next 3 */ - if (scanned.get(dir)) { - return; - } - scanned.set(dir, true); - try { - const list = readdirSync(dir); - for (const name of list) { - if (name.startsWith('.') || name === 'node_modules' || name === 'zig-cache') { - continue; - } - const path = join(dir, name); - const info = findFileSync(path); - if (info?.isDirectory()) { - scan(path); - } else if (info?.isFile() && re.test(name)) { - map.set(path, info); - } - } - /* c8 ignore next 2 */ - } catch (err) { - } - }; - scan(dir); - return map; +function useBareUnion$7() { + factories$n[StructureType$7.BareUnion] = defineUnionShape$7; } -async function acquireLock(pidPath, staleTime) { - while (true) { - try { - await createDirectory(dirname(pidPath)); - const handle = await open(pidPath, 'wx'); - handle.write(`${process.pid}`); - handle.close(); - break; - } catch (err) { - if (err.code === 'EEXIST') { - if (checkPidFile(pidPath, staleTime)) { - await delay(250); - continue; - } - } else { - throw err; - } - } - } +function useTaggedUnion$7() { + factories$n[StructureType$7.TaggedUnion] = defineUnionShape$7; } -function acquireLockSync(pidPath, staleTime) { - while (true) { - try { - createDirectorySync(dirname(pidPath)); - const handle = openSync(pidPath, 'wx'); - writeSync(handle, `${process.pid}`); - closeSync(handle); - break; - } catch (err) { - if (err.code === 'EEXIST') { - if (checkPidFile(pidPath, staleTime)) { - delaySync(250); - } - } else { - throw err; - } - } - } +function useErrorUnion$7() { + factories$n[StructureType$7.ErrorUnion] = defineErrorUnion$7; } -async function releaseLock(pidPath) { - await deleteFile(pidPath); +function useErrorSet$7() { + factories$n[StructureType$7.ErrorSet] = defineErrorSet$7; } -function releaseLockSync(pidPath) { - deleteFileSync(pidPath); +function useEnumeration$7() { + factories$n[StructureType$7.Enumeration] = defineEnumerationShape$7; } -function checkPidFile(pidPath, staleTime = 60000 * 5) { - let stale = false; - try { - const pid = loadFileSync(pidPath); - if (os.platform() === 'win32') { - execSync(`tasklist /nh /fi "pid eq ${pid}" | findstr .exe`, { stdio: 'pipe' }).toString(); - } else { - execSync(`ps -p ${pid}`).toString(); - } - const last = findFileSync(pidPath)?.mtime || 0; - const diff = new Date() - last; - if (diff > staleTime) { - stale = true; - } - } catch (err) { - stale = true; - } - if (stale) { - deleteFileSync(pidPath); - } - return !stale; +function useOptional$7() { + factories$n[StructureType$7.Optional] = defineOptional$7; } -async function copyFile(srcPath, dstPath) { - const info = await stat(srcPath); - const data = await readFile(srcPath); - await writeFile(dstPath, data); - await chmod(dstPath, info.mode); +function usePointer$7() { + factories$n[StructureType$7.Pointer] = definePointer$7; } -function copyFileSync(srcPath, dstPath) { - const info = statSync(srcPath); - const data = readFileSync(srcPath); - writeFileSync(dstPath, data); - chmodSync(dstPath, info.mode); +function useSlice$7() { + factories$n[StructureType$7.Slice] = defineSlice$7; } -async function loadFile(path, def) { - try { - return await readFile(path, 'utf8'); - } catch (err) { - return def; - } +function useVector$7() { + factories$n[StructureType$7.Vector] = defineVector$7; } -function loadFileSync(path, def) { - try { - return readFileSync(path, 'utf8'); - } catch (err) { - return def; - } +function useOpaque$7() { + factories$n[StructureType$7.Opaque] = defineOpaque$7; } -async function deleteFile(path) { - try { - await unlink(path); - } catch (err) { - if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { - throw err; +function defineProperties$7(object, descriptors) { + for (const [ name, descriptor ] of Object.entries(descriptors)) { + if (descriptor) { + const { + set, + get, + value, + enumerable, + configurable = true, + writable = true, + } = descriptor; + Object.defineProperty(object, name, (get) + ? { get, set, configurable, enumerable } + : { value, configurable, enumerable, writable } + ); } } -} - -function deleteFileSync(path) { - try { - unlinkSync(path); - } catch (err) { - if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { - throw err; + for (const symbol of Object.getOwnPropertySymbols(descriptors)) { + const descriptor = descriptors[symbol]; + if (descriptor) { + Object.defineProperty(object, symbol, descriptor); } } } -async function createDirectory(path) { - const exists = await findDirectory(path); - if (!exists) { - const { root, dir } = parse(path); - await createDirectory(dir); - try { - await mkdir(path); - } catch (err) { - /* c8 ignore next 3 */ - if (err.code != 'EEXIST') { - throw err; +function attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors) { + // create prototype for read-only objects + const prototypeRO = {}; + Object.setPrototypeOf(prototypeRO, constructor.prototype); + const instanceDescriptorsRO = {}; + const propSetters = {}; + for (const [ name, descriptor ] of Object.entries(instanceDescriptors)) { + if (descriptor?.set) { + instanceDescriptorsRO[name] = { ...descriptor, set: throwReadOnly$7 }; + // save the setters so we can initialize read-only objects + if (name !== '$') { + propSetters[name] = descriptor.set; } + } else if (name === 'set') { + instanceDescriptorsRO[name] = { value: throwReadOnly$7, configurable: true, writable: true }; } } + const vivificate = instanceDescriptors[VIVIFICATOR$7]?.value; + const vivificateDescriptor = { + // vivificate child objects as read-only too + value: function(slot) { + return vivificate.call(this, slot, false); + } + }; + const { get, set } = instanceDescriptors.$; + defineProperties$7(constructor.prototype, { + [CONST$7]: { value: false }, + [ALL_KEYS$7]: { value: Object.keys(propSetters) }, + [SETTER$7]: { value: set }, + [GETTER$7]: { value: get }, + [PROP_SETTERS$7]: { value: propSetters }, + ...instanceDescriptors, + }); + defineProperties$7(constructor, { + [CONST_PROTOTYPE$7]: { value: prototypeRO }, + ...staticDescriptors, + }); + defineProperties$7(prototypeRO, { + constructor: { value: constructor, configurable: true }, + [CONST$7]: { value: true }, + [SETTER$7]: { value: throwReadOnly$7 }, + [VIVIFICATOR$7]: vivificate && vivificateDescriptor, + ...instanceDescriptorsRO, + }); + return constructor; } -function createDirectorySync(path) { - const exists = findDirectorySync(path); - if (!exists) { - const { root, dir } = parse(path); - createDirectorySync(dir); - try { - mkdirSync(path); - } catch (err) { - /* c8 ignore next 3 */ - if (err.code != 'EEXIST') { - throw err; +function createConstructor$7(structure, handlers, env) { + const { + byteSize, + align, + instance: { members, template }, + hasPointer, + } = structure; + const { + modifier, + initializer, + finalizer, + alternateCaster, + shapeDefiner, + } = handlers; + const hasSlots = needSlots$7(members); + // comptime fields are stored in the instance template's slots + let comptimeFieldSlots; + if (template?.[SLOTS$7]) { + const comptimeMembers = members.filter(m => isReadOnly$7(m.type)); + if (comptimeMembers.length > 0) { + comptimeFieldSlots = comptimeMembers.map(m => m.slot); + } + } + const cache = new ObjectCache$7(); + const constructor = function(arg, options = {}) { + const { + writable = true, + fixed = false, + } = options; + const creating = this instanceof constructor; + let self, dv; + if (creating) { + if (arguments.length === 0) { + throwNoInitializer$7(structure); + } + self = this; + if (hasSlots) { + self[SLOTS$7] = {}; + } + if (shapeDefiner) { + // provided by defineSlice(); the slice is different from other structures as it does not have + // a fixed size; memory is allocated by the slice initializer based on the argument given + initializer.call(self, arg, fixed); + dv = self[MEMORY$7]; + } else { + self[MEMORY$7] = dv = env.allocateMemory(byteSize, align, fixed); + } + } else { + if (alternateCaster) { + // casting from number, string, etc. + self = alternateCaster.call(this, arg, options); + if (self !== false) { + return self; + } + } + // look for buffer + dv = requireDataView$7(structure, arg, env); + if (self = cache.find(dv, writable)) { + return self; + } + self = Object.create(writable ? constructor.prototype : constructor[CONST_PROTOTYPE$7]); + if (shapeDefiner) { + setDataView$7.call(self, dv, structure, false, { shapeDefiner }); + } else { + self[MEMORY$7] = dv; + } + if (hasSlots) { + self[SLOTS$7] = {}; + if (hasPointer && arg instanceof constructor) { + // copy pointer from other object + self[POINTER_VISITOR$7](copyPointer$7, { vivificate: true, source: arg }); + } } } - } -} - -async function findDirectory(path) { - return findFile(path); -} - -function findDirectorySync(path) { - return findFileSync(path); + if (comptimeFieldSlots) { + for (const slot of comptimeFieldSlots) { + self[SLOTS$7][slot] = template[SLOTS$7][slot]; + } + } + if (modifier) { + modifier.call(self); + } + if (creating) { + // initialize object unless it's been done already + if (!shapeDefiner) { + initializer.call(self, arg); + } + if (!writable) { + // create object with read-only prototype + self = Object.assign(Object.create(constructor[CONST_PROTOTYPE$7]), self); + } + } + if (finalizer) { + self = finalizer.call(self); + } + return cache.save(dv, writable, self); + }; + return constructor; } -async function deleteDirectory(dir) { - try { - const list = await readdir(dir); - for (const name of list) { - const path = join(dir, name); - const info = await findFile(path, false); - if (info?.isDirectory()) { - await deleteDirectory(path); - } else if (info) { - await deleteFile(path); +function createPropertyApplier$7(structure) { + const { instance: { template } } = structure; + return function(arg) { + const argKeys = Object.keys(arg); + const propSetters = this[PROP_SETTERS$7]; + const allKeys = this[ALL_KEYS$7]; + // don't accept unknown props + for (const key of argKeys) { + if (!(key in propSetters)) { + throwNoProperty$7(structure, key); + } + } + // checking each name so that we would see inenumerable initializers as well + let normalCount = 0; + let normalFound = 0; + let normalMissing = 0; + let specialFound = 0; + for (const key of allKeys) { + const set = propSetters[key]; + if (set.special) { + if (key in arg) { + specialFound++; + } + } else { + normalCount++; + if (key in arg) { + normalFound++; + } else if (set.required) { + normalMissing++; + } + } + } + if (normalMissing !== 0 && specialFound === 0) { + const missing = allKeys.filter(k => propSetters[k].required && !(k in arg)); + throwMissingInitializers$7(structure, missing); + } + if (specialFound + normalFound > argKeys.length) { + // some props aren't enumerable + for (const key of allKeys) { + if (key in arg) { + if (!argKeys.includes(key)) { + argKeys.push(key); + } + } } } - await rmdir(dir); - } catch (err) { - if (err.code !== 'ENOENT') { - throw err; + // apply default values unless all properties are initialized + if (normalFound < normalCount && specialFound === 0) { + if (template) { + if (template[MEMORY$7]) { + this[COPIER$7](template); + } + this[POINTER_VISITOR$7]?.(copyPointer$7, { vivificate: true, source: template }); + } } - } + for (const key of argKeys) { + const set = propSetters[key]; + set.call(this, arg[key]); + } + return argKeys.length; + }; } -function deleteDirectorySync(dir) { - try { - const list = readdirSync(dir); - for (const name of list) { - const path = join(dir, name); - const info = findFileSync(path, false); - if (info?.isDirectory()) { - deleteDirectorySync(path); - } else if (info) { - deleteFileSync(path); - } - } - rmdirSync(dir); - } catch (err) { - if (err.code !== 'ENOENT') { - throw err; +function needSlots$7(members) { + for (const { type } of members) { + switch (type) { + case MemberType$7.Object: + case MemberType$7.Comptime: + case MemberType$7.Type: + case MemberType$7.Literal: + return true; } } + return false; } -async function delay(ms) { - await new Promise(r => setTimeout(r, ms)); +function getSelf$7() { + return this; } -function delaySync(ms) { - const buffer = new SharedArrayBuffer(8); - const ta = new BigInt64Array(buffer); - Atomics.wait(ta, 0, 0n, ms); +function useAllStructureTypes$7() { + usePrimitive$7(); + useArray$7(); + useStruct$7(); + useExternStruct$7(); + usePackedStruct$7(); + useArgStruct$7(); + useExternUnion$7(); + useBareUnion$7(); + useTaggedUnion$7(); + useErrorUnion$7(); + useErrorSet$7(); + useEnumeration$7(); + useOptional$7(); + usePointer$7(); + useSlice$7(); + useVector$7(); + useOpaque$7(); } -function md5(text) { - const hash = createHash('md5'); - hash.update(text); - return hash.digest('hex'); -} +let ObjectCache$7 = class ObjectCache { + [0] = null; + [1] = null; -let isGNU; + find(dv, writable) { + const key = (writable) ? 0 : 1; + const map = this[key]; + return map?.get(dv); + } -function getPlatform() { - let platform = os.platform(); - if (platform === 'linux') { - // differentiate glibc from musl - if (isGNU === undefined) { - /* c8 ignore next 3 */ - if (process.versions?.electron || process.__nwjs) { - isGNU = true; - } else { - try { - execFileSync('getconf', [ 'GNU_LIBC_VERSION' ], { stdio: 'pipe' }); - isGNU = true; - /* c8 ignore next 3 */ - } catch (err) { - isGNU = false; - } - } - } - /* c8 ignore next 3 */ - if (!isGNU) { - platform += '-musl'; + save(dv, writable, object) { + const key = (writable) ? 0 : 1; + let map = this[key]; + if (!map) { + map = this[key] = new WeakMap(); } + map.set(dv, object); + return object; } - return platform; -} - -function getArch() { - return os.arch(); -} +}; -function normalizePath(url) { - let archive; - const parts = fileURLToPath(url).split(sep).map((part) => { - if (part === 'app.asar') { - archive = 'asar'; - return part + '.unpacked'; +function definePrimitive$7(structure, env) { + const { + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + const { get, set } = getDescriptor$7(member, env); + const propApplier = createPropertyApplier$7(structure); + const initializer = function(arg) { + if (arg instanceof constructor) { + this[COPIER$7](arg); + } else { + if (arg && typeof(arg) === 'object') { + if (propApplier.call(this, arg) === 0) { + const type = getPrimitiveType$7(member); + throwInvalidInitializer$7(structure, type, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } } - return part; - }); - const path = parts.join(sep); - return { path, archive } + }; + const constructor = structure.constructor = createConstructor$7(structure, { initializer }, env); + const typedArray = structure.typedArray = getTypedArrayClass$7(member); + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor$7(structure), + base64: getBase64Descriptor$7(structure), + typedArray: typedArray && getTypedArrayDescriptor$7(structure), + valueOf: { value: getValueOf$7 }, + toJSON: { value: convertToJSON$7 }, + delete: { value: getDestructor$7(env) }, + [Symbol.toPrimitive]: { value: get }, + [COPIER$7]: { value: getMemoryCopier$7(byteSize) }, + [NORMALIZER$7]: { value: normalizeValue$7 }, + }; + const staticDescriptors = { + [COMPAT$7]: { value: getCompatibleTags$7(structure) }, + [ALIGN$7]: { value: align }, + [SIZE$7]: { value: byteSize }, + }; + return attachDescriptors$7(constructor, instanceDescriptors, staticDescriptors); } - -async function compile(srcPath, modPath, options) { - const srcInfo = (srcPath) ? await findFile(srcPath) : null; - if (srcInfo === undefined) { - throw new Error(`Source file not found: ${srcPath}`); - } - if (srcInfo?.isDirectory()) { - srcPath = join(srcPath, '?'); +function getIntRange$7(member) { + const { type, bitSize } = member; + const signed = (type === MemberType$7.Int); + let magBits = (signed) ? bitSize - 1 : bitSize; + if (bitSize <= 32) { + const max = 2 ** magBits - 1; + const min = (signed) ? -(2 ** magBits) : 0; + return { min, max }; + } else { + magBits = BigInt(magBits); + const max = 2n ** magBits - 1n; + const min = (signed) ? -(2n ** magBits) : 0n; + return { min, max }; } - const config = createConfig(srcPath, modPath, options); - const { moduleDir, outputPath } = config; - let changed = false; - if (srcPath) { - const srcFileMap = await findMatchingFiles(moduleDir, /.\..*$/); - // see if the (re-)compilation is necessary - const soInfo = await findFile(outputPath); - if (soInfo) { - for (const [ name, info ] of srcFileMap) { - if (info.mtime > soInfo.mtime) { - changed = true; - break; - } - } +} + +function getPrimitiveClass$7({ type, bitSize }) { + if (type === MemberType$7.Int || type === MemberType$7.Uint) { + if (bitSize <= 32) { + return Number; } else { - changed = true; - } - if (!changed) { - // rebuild when exporter or build files have changed - const zigFolder = absolute('../zig'); - const zigFileMap = await findMatchingFiles(zigFolder, /\.zig$/); - for (const [ path, info ] of zigFileMap) { - if (info.mtime > soInfo.mtime) { - changed = true; - break; - } - } + return BigInt; } - if (changed) { - // add custom build file - for (const [ path, info ] of srcFileMap) { - switch (basename(path)) { - case 'build.zig': - config.buildFilePath = path; - break; - case 'build.zig.zon': - config.packageConfigPath = path; - break; - } - } - const { zigCmd, moduleBuildDir } = config; - // only one process can compile a given file at a time - const pidPath = `${moduleBuildDir}.pid`; - await acquireLock(pidPath); - try { - // create config file - await createProject(config, moduleBuildDir); - // then run the compiler - await runCompiler(zigCmd, moduleBuildDir); - } finally { - if (config.clean) { - await deleteDirectory(moduleBuildDir); - } - await releaseLock(pidPath); - } - } + } else if (type === MemberType$7.Float) { + return Number; + } else if (type === MemberType$7.Bool) { + return Boolean; } - return { outputPath, changed } } -function compileSync(srcPath, modPath, options) { - const srcInfo = (srcPath) ? findFileSync(srcPath) : null; - if (srcInfo === undefined) { - throw new Error(`Source file not found: ${srcPath}`); +function getPrimitiveType$7(member) { + const Primitive = getPrimitiveClass$7(member); + if (Primitive) { + return typeof(Primitive(0)); } - if (srcInfo?.isDirectory()) { - srcPath = join(srcPath, '?'); +} + +function throwNoInitializer$7(structure) { + const { name } = structure; + throw new TypeError(`An initializer must be provided to the constructor of ${name}, even when the intended value is undefined`); +} + +function throwBufferSizeMismatch$7(structure, dv, target = null) { + const { name, type, byteSize } = structure; + const actual = dv.byteLength; + const s = (byteSize !== 1) ? 's' : ''; + if (type === StructureType$7.Slice && !target) { + throw new TypeError(`${name} has elements that are ${byteSize} byte${s} in length, received ${actual}`); + } else { + const total = (type === StructureType$7.Slice) ? target.length * byteSize : byteSize; + throw new TypeError(`${name} has ${total} byte${s}, received ${actual}`); } - const config = createConfig(srcPath, modPath, options); - const { moduleDir, outputPath } = config; - let changed = false; - if (srcPath) { - const srcFileMap = findMatchingFilesSync(moduleDir, /.\..*$/); - // see if the (re-)compilation is necessary - const soInfo = findFileSync(outputPath); - if (soInfo) { - for (const [ path, info ] of srcFileMap) { - if (info.mtime > soInfo.mtime) { - changed = true; - break; - } - } - } else { - changed = true; - } - if (!changed) { - // rebuild when exporter or build files have changed - const zigFolder = absolute('../zig'); - const zigFileMap = findMatchingFilesSync(zigFolder, /\.zig$/); - for (const [ path, info ] of zigFileMap) { - if (info.mtime > soInfo.mtime) { - changed = true; - break; - } - } - } - if (changed) { - // add custom build file - for (const [ path, info ] of srcFileMap) { - switch (basename(path)) { - case 'build.zig': - config.buildFilePath = path; - break; - case 'build.zig.zon': - config.packageConfigPath = path; - break; - } - } - const { zigCmd, moduleBuildDir } = config; - // only one process can compile a given file at a time - const pidPath = `${moduleBuildDir}.pid`; - acquireLockSync(pidPath); - try { - // create config file - createProjectSync(config, moduleBuildDir); - // then run the compiler - runCompilerSync(zigCmd, moduleBuildDir); - } finally { - if (config.clean) { - deleteDirectorySync(moduleBuildDir); - } - releaseLockSync(pidPath); - } - } +} + +function throwBufferExpected$7(structure) { + const { type, byteSize, typedArray } = structure; + const s = (byteSize !== 1) ? 's' : ''; + const acceptable = [ 'ArrayBuffer', 'DataView' ].map(addArticle$7); + if (typedArray) { + acceptable.push(addArticle$7(typedArray.name)); + } + if (type === StructureType$7.Slice) { + throw new TypeError(`Expecting ${formatList$7(acceptable)} that can accommodate items ${byteSize} byte${s} in length`); + } else { + throw new TypeError(`Expecting ${formatList$7(acceptable)} that is ${byteSize} byte${s} in length`); } - return { outputPath, changed } } -async function runCompiler(zigCmd, soBuildDir) { - const options = { - cwd: soBuildDir, - windowsHide: true, - }; - return new Promise((resolve, reject) => { - exec(zigCmd, options, (err, stdout, stderr) => { - if (err) { - const log = stderr; - if (log) { - const logPath = join(soBuildDir, 'log'); - writeFile(logPath, log); - err = new Error(`Zig compilation failed\n\n${log}`); - } - reject(err); - } else { - resolve(); - } - }); - }); +function throwEnumExpected$7(structure, arg) { + const { name } = structure; + if (typeof(arg) === 'number' || typeof(arg) === 'bigint') { + throw new TypeError(`Value given does not correspond to an item of enum ${name}: ${arg}`); + } else { + throw new TypeError(`Enum item of the type ${name} expected, received ${arg}`); + } } -function runCompilerSync(zigCmd, soBuildDir) { - const options = { - cwd: soBuildDir, - windowsHide: true, - stdio: 'pipe', - }; - try { - execSync(zigCmd, options); - } catch (err) { - const log = err.stderr; - if (log) { - const logPath = join(soBuildDir, 'log'); - writeFileSync(logPath, log); - } - throw new Error(`Zig compilation failed\n\n${log}`); +function throwErrorExpected$7(structure, arg) { + const { name } = structure; + const type = typeof(arg); + if (type === 'string' || type === 'number') { + throw new TypeError(`Error ${type} does not corresponds to any error in error set ${name}: ${arg}`); + } else { + throw new TypeError(`Error of the type ${name} expected, received ${arg}`); } } -function formatProjectConfig(config) { - const lines = []; - const fields = [ - 'moduleName', 'modulePath', 'moduleDir', 'exporterPath', 'stubPath', 'outputPath', - 'useLibc', 'isWASM', - ]; - for (const [ name, value ] of Object.entries(config)) { - if (fields.includes(name)) { - const snakeCase = name.replace(/[A-Z]+/g, m => '_' + m.toLowerCase()); - lines.push(`pub const ${snakeCase} = ${JSON.stringify(value)};`); +function throwNotInErrorSet$7(structure) { + const { name } = structure; + throw new TypeError(`Error given is not a part of error set ${name}`); +} + +function throwMultipleUnionInitializers$7(structure) { + const { name } = structure; + throw new TypeError(`Only one property of ${name} can be given a value`); +} + +function throwInactiveUnionProperty$7(structure, name, currentName) { + throw new TypeError(`Accessing property ${name} when ${currentName} is active`); +} + +function throwMissingUnionInitializer$7(structure, arg, exclusion) { + const { name, instance: { members } } = structure; + const missing = members.slice(0, exclusion ? -1 : undefined).map(m => m.name); + throw new TypeError(`${name} needs an initializer for one of its union properties: ${missing.join(', ')}`); +} + +function throwInvalidInitializer$7(structure, expected, arg) { + const { name } = structure; + const acceptable = []; + if (Array.isArray(expected)) { + for (const type of expected) { + acceptable.push(addArticle$7(type)); } + } else { + acceptable.push(addArticle$7(expected)); } - return lines.join('\n'); + const received = getDescription$7(arg); + throw new TypeError(`${name} expects ${formatList$7(acceptable)} as argument, received ${received}`); } -async function createProject(config, dir) { - await createDirectory(dir); - const content = formatProjectConfig(config); - const cfgFilePath = join(dir, 'build-cfg.zig'); - await writeFile(cfgFilePath, content); - const buildFilePath = join(dir, 'build.zig'); - await copyFile(config.buildFilePath, buildFilePath); - if (config.packageConfigPath) { - const packageConfigPath = join(dir, 'build.zig.zon'); - await copyFile(config.packageConfigPath, packageConfigPath); +function throwInvalidArrayInitializer$7(structure, arg, shapeless = false) { + const { instance: { members: [ member ] }, type, typedArray } = structure; + const acceptable = []; + const primitive = getPrimitiveType$7(member); + if (primitive) { + acceptable.push(`array of ${primitive}s`); + } else if (member.type === MemberType$7.EnumerationItem) { + acceptable.push(`array of enum items`); + } else { + acceptable.push(`array of objects`); } + if (typedArray) { + acceptable.push(typedArray.name); + } + if (type === StructureType$7.Slice && shapeless) { + acceptable.push(`length`); + } + throwInvalidInitializer$7(structure, acceptable.join(' or '), arg); } -function createProjectSync(config, dir) { - createDirectorySync(dir); - const content = formatProjectConfig(config); - const cfgFilePath = join(dir, 'build-cfg.zig'); - writeFileSync(cfgFilePath, content); - const buildFilePath = join(dir, 'build.zig'); - copyFileSync(config.buildFilePath, buildFilePath); - if (config.packageConfigPath) { - const packageConfigPath = join(dir, 'build.zig.zon'); - copyFileSync(config.packageConfigPath, packageConfigPath); +function throwArrayLengthMismatch$7(structure, target, arg) { + const { name, length, instance: { members: [ member ] } } = structure; + const { structure: { constructor: elementConstructor} } = member; + const { length: argLength, constructor: argConstructor } = arg; + // get length from object whech it's a slice + const actualLength = target?.length ?? length; + const s = (actualLength !== 1) ? 's' : ''; + let received; + if (argConstructor === elementConstructor) { + received = `only a single one`; + } else if (argConstructor.child === elementConstructor) { + received = `a slice/array that has ${argLength}`; + } else { + received = `${argLength} initializer${argLength > 1 ? 's' : ''}`; + } + throw new TypeError(`${name} has ${actualLength} element${s}, received ${received}`); +} + +function throwMissingInitializers$7(structure, missing) { + const { name } = structure; + throw new TypeError(`Missing initializers for ${name}: ${missing.join(', ')}`); +} + +function throwNoProperty$7(structure, propName) { + const { name, instance: { members } } = structure; + const member = members.find(m => m.name === propName); + if (member) { + throw new TypeError(`Comptime value cannot be changed: ${propName}`); + } else { + throw new TypeError(`${name} does not have a property with that name: ${propName}`); } } -const cwd = process.cwd(); +function throwArgumentCountMismatch$7(structure, actual) { + const { name, instance: { members } } = structure; + const argCount = members.length - 1; + const s = (argCount !== 1) ? 's' : ''; + throw new Error(`${name} expects ${argCount} argument${s}, received ${actual}`); +} + +function rethrowArgumentError$7(structure, index, err) { + const { name, instance: { members } } = structure; + // Zig currently does not provide the argument name + const argName = `args[${index}]`; + const argCount = members.length - 1; + const prefix = (index !== 0) ? '..., ' : ''; + const suffix = (index !== argCount - 1) ? ', ...' : ''; + const argLabel = prefix + argName + suffix; + const newError = new err.constructor(`${name}(${argLabel}): ${err.message}`); + newError.stack = err.stack; + throw newError; +} -function getCachePath(options) { - const { - cacheDir = join(cwd, 'zigar-cache'), - } = options; - return cacheDir; +function throwNoCastingToPointer$7(structure) { + throw new TypeError(`Non-slice pointers can only be created with the help of the new operator`); } -function getModuleCachePath(srcPath, options) { - const { - optimize, - } = options; - const src = parse(srcPath); - const folder = basename(src.dir).slice(0, 16).trim() + '-' + md5(src.dir).slice(0, 8); - const cacheDir = getCachePath(options); - return join(cacheDir, folder, optimize, `${src.name}.zigar`); +function throwConstantConstraint$7(structure, pointer) { + const { name: target } = structure; + const { constructor: { name } } = pointer; + throw new TypeError(`Conversion of ${name} to ${target} requires an explicit cast`); } -function createConfig(srcPath, modPath, options = {}) { - const { - platform = getPlatform(), - arch = getArch(), - optimize = 'Debug', - isWASM = false, - useLibc = isWASM ? false : true, - clean = false, - buildDir = join(os.tmpdir(), 'zigar-build'), - zigCmd = (() => { - // translate from names used by Node to those used by Zig - const cpuArchs = { - arm: 'arm', - arm64: 'aarch64', - ia32: 'x86', - loong64: 'loong64', - mips: 'mips', - mipsel: 'mipsel', - ppc: 'powerpc', - ppc64: 'powerpc64', - s390: undefined, - s390x: 's390x', - x64: 'x86_64', - }; - const osTags = { - aix: 'aix', - darwin: 'macos', - freebsd: 'freebsd', - linux: 'linux-gnu', - openbsd: 'openbsd', - sunos: 'solaris', - win32: 'windows', - }; - const cpuArch = cpuArchs[arch] ?? arch; - const osTag = osTags[platform] ?? platform; - const args = [ - `build`, - `-Doptimize=${optimize}`, - `-Dtarget=${cpuArch}-${osTag}`, - ]; - return `zig ${args.join(' ')}`; - })(), - } = options; - const suffix = isWASM ? 'wasm' : 'c'; - const src = parse(srcPath ?? ''); - const mod = parse(modPath ?? ''); - const moduleName = mod.name || src.name; - const modulePath = (src.name !== '?') ? srcPath : undefined; - const moduleDir = src.dir; - const modulePrefix = basename(moduleName).slice(0, 16); - const moduleHash = md5(`${moduleDir}/${moduleName}`).slice(0, 8); - const moduleBuildDir = join(buildDir, modulePrefix + '-' + moduleHash); - const outputPath = (() => { - if (!modPath && isWASM) { - // save output in build folder - return join(moduleBuildDir, optimize, `${src.name}.wasm`); - } else { - const extensions = { - darwin: 'dylib', - win32: 'dll', - }; - const ext = extensions[platform] || 'so'; - return join(modPath, `${platform}.${arch}.${ext}`); - } - })(); - const exporterPath = absolute(`../zig/exporter-${suffix}.zig`); - const stubPath = absolute(`../zig/stub-${suffix}.zig`); - const buildFilePath = absolute(`../zig/build.zig`); - return { - platform, - arch, - optimize, - moduleName, - modulePath, - moduleDir, - moduleBuildDir, - exporterPath, - stubPath, - buildFilePath, - packageConfigPath: undefined, - outputPath, - clean, - zigCmd, - useLibc, - isWASM, - }; +function throwMisplacedSentinel$7(structure, value, index, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}, found at ${index}`); } -function absolute(relpath) { - // import.meta.url don't always yield the right URL when transpiled to CommonJS - // just use __dirname as it's going to be there - /* c8 ignore next 2 */ - if (typeof(__dirname) === 'string') { - return resolve(__dirname, relpath); - } else { - return fileURLToPath(new URL(relpath, import.meta.url)); - } +function throwMissingSentinel$7(structure, value, length) { + const { name } = structure; + throw new TypeError(`${name} expects the sentinel value ${value} at ${length - 1}`); } -const optionsForCompile = { - optimize: { - type: 'string', - enum: [ 'Debug', 'ReleaseSmall', 'ReleaseFast', 'ReleaseSafe' ], - title: 'Zig optimization mode', - }, - omitFunctions: { - type: 'boolean', - title: 'Omit all Zig functions', - }, - omitVariables: { - type: 'boolean', - title: 'Omit all variables', - }, - omitExports: { - type: 'boolean', - title: 'Omit export statements', - }, - useLibc: { - type: 'boolean', - title: 'Link in C standard library', - }, - topLevelAwait: { - type: 'boolean', - title: 'Use top-level await to load WASM file', - }, - buildDir: { - type: 'string', - title: 'Root directory where temporary build directories are placed', - }, - cacheDir: { - type: 'string', - title: 'Directory where compiled library files are placed', - }, - zigCmd: { - type: 'string', - title: 'Zig command used to build libraries', - }, - sourceFiles: { - type: 'object', - title: 'Map of modules to source files/directories', - }, - clean: { - type: 'boolean', - title: 'Remove temporary build directory after compilation finishes', - }, - targets: { - type: 'object', - title: 'List of cross-compilation targets', - }, -}; +function throwTypeMismatch$7(expected, arg) { + const received = getDescription$7(arg); + throw new TypeError(`Expected ${addArticle$7(expected)}, received ${received}`) +} -const optionsForTranspile = { - useReadFile: { - type: 'boolean', - title: 'Enable the use of readFile() to Load WASM file when library is used in Node.js', - }, - embedWASM: { - type: 'boolean', - title: 'Embed WASM file in JavaScript source code', - }, - stripWASM: { - type: 'boolean', - title: 'Remove unnecessary code from WASM file', - }, - keepNames: { - type: 'boolean', - title: 'Keep names of function in WASM binary when stripping', - }, -}; +function throwInaccessiblePointer$7() { + throw new TypeError(`Pointers within an untagged union are not accessible`); +} -const allOptions = { - ...optionsForCompile, - ...optionsForTranspile, -}; +function throwNullPointer$7() { + throw new TypeError(`Null pointer`); +} -function extractOptions(searchParams, availableOptions) { - const options = {}; - const names = Object.keys(availableOptions); - for (const [ name, string ] of searchParams) { - const key = getCamelCase(name, names); - const option = availableOptions[key]; - if (!option) { - throwUnknownOption(name); - } - if (key === 'optimize') { - options[key] = getCamelCase(string, [ 'Debug', 'ReleaseSafe', 'ReleaseFast', 'ReleaseSmall' ]); - } else { - switch (option.type) { - case 'boolean': - options[key] = !!parseInt(string); - break; - case 'number': - options[key] = parseInt(string); - break; - default: - options[key] = string; - } - } +function throwInvalidPointerTarget$7(structure, arg) { + const { name } = structure; + let target; + if (arg != null) { + const type = typeof(arg); + const noun = (type === 'object' && arg.constructor !== Object) ? `${arg.constructor.name} object`: type; + const a = article$7(noun); + target = `${a} ${noun}`; + } else { + target = arg + ''; } - return options; + throw new TypeError(`${name} cannot point to ${target}`) } -function getCamelCase(name, names) { - for (const nameCC of names) { - const nameSC = nameCC.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase(); - const nameKC = nameSC.replace(/_/g, '-'); - if (name === nameKC || name === nameSC || name === nameCC) { - return nameCC; - } - } - return name; +function throwFixedMemoryTargetRequired$7(structure, arg) { + throw new TypeError(`Pointers in fixed memory cannot point to garbage-collected object`); } -function throwUnknownOption(key) { - const adjective = (allOptions[key]) ? 'Unavailable' : 'Unrecognized'; - throw new Error(`${adjective} option: ${key}`); + +function throwOverflow$7(member, value) { + const typeName = getTypeName$7(member); + throw new TypeError(`${typeName} cannot represent the value given: ${value}`); } -async function findConfigFile(name, dir) { - const path = join(dir, name); - const info = await findFile(path); - if (info?.isFile()) { - return path; - } else { - const parent = dirname(dir); - if (parent !== dir) { - return findConfigFile(name, parent); - } - } +function throwOutOfBound$7(member, index) { + const { name } = member; + throw new RangeError(`Index exceeds the size of ${name ?? 'array'}: ${index}`); } -function findConfigFileSync(name, dir) { - const path = join(dir, name); - const info = findFileSync(path); - if (info?.isFile()) { - return path; +function rethrowRangeError$7(member, index, err) { + if (err instanceof RangeError) { + throwOutOfBound$7(member, index); } else { - const parent = dirname(dir); - if (parent !== dir) { - return findConfigFileSync(name, parent); - } + throw err; } } -async function loadConfigFile(cfgPath, availableOptions) { - const text = await loadFile(cfgPath); - return processConfigFile(text, cfgPath, availableOptions); +function throwNotUndefined$7(member) { + const { name } = member; + throw new RangeError(`Property ${name} can only be undefined`); } -function loadConfigFileSync(cfgPath, availableOptions) { - const text = loadFileSync(cfgPath); - return processConfigFile(text, cfgPath, availableOptions); +function throwNotOnByteBoundary$7(member) { + const { name, structure: { name: { struct }} } = member; + throw new TypeError(`Unable to create ${struct} as it is not situated on a byte boundary: ${name}`); } -function processConfigFile(text, cfgPath, availableOptions) { - const options = JSON.parse(text); - for (const [ key, value ] of Object.entries(options)) { - const option = availableOptions[key]; - if (!option) { - throwUnknownOption(key); - } - if (typeof(value) !== option.type) { - throw new Error(`${key} is expected to be a ${option.type}, received: ${value}`); - } - } - options.sourceFiles = getAbsoluteMapping(options.sourceFiles, dirname(cfgPath)); - return options; +function throwReadOnly$7() { + throw new TypeError(`Unable to modify read-only object`); } -function getAbsoluteMapping(sourceFiles, cfgDir) { - if (!sourceFiles) { - return; - } - const map = {}; - for (const [ module, source ] of Object.entries(sourceFiles)) { - const modulePath = resolve(cfgDir, module); - const sourcePath = resolve(cfgDir, source); - map[modulePath] = sourcePath; - } - return map; +function throwReadOnlyTarget$7(structure) { + const { name } = structure; + throw new TypeError(`${name} cannot point to a read-only object`); } -function findSourceFile$1(modulePath, options) { - const { sourceFiles } = options; - return sourceFiles?.[modulePath]; +function throwAccessingOpaque$7(structure) { + const { name } = structure; + throw new TypeError(`Unable to access opaque structure ${name}`); } -function addMethods(s, env) { - const add = (target, { methods }, pushThis) => { - const descriptors = {}; - const re = /^(get|set)\s+([\s\S]+)/; - for (const method of methods) { - const f = env.createCaller(method, pushThis); - const m = re.exec(f.name); - if (m) { - // getter/setter - const type = m[1], propName = m[2]; - const argRequired = (type === 'get') ? 0 : 1; - const argCount = getArgumentCount(method, pushThis); - // need to match arg count, since instance methods also show up as static methods - if (argCount === argRequired) { - let descriptor = descriptors[propName]; - if (!descriptor) { - descriptor = descriptors[propName] = { configurable: true, enumerable: true }; - } - descriptor[type] = f; - } - } else { - descriptors[f.name] = { value: f, configurable: true, writable: true }; - } - } - defineProperties$7(target, descriptors); - }; - add(s.constructor, s.static, false); - add(s.constructor.prototype, s.instance, true); +function throwCreatingOpaque$7(structure) { + const { name } = structure; + throw new TypeError(`Unable to create instance of ${name}, as it is opaque`); } -function getArgumentCount(method, pushThis) { - const { argStruct: { instance: { members } } } = method; - return members.length - (pushThis ? 2 : 1); +function warnImplicitArrayCreation$7(structure, arg) { + const created = addArticle$7(structure.typedArray.name); + const source = addArticle$7(arg.constructor.name); + console.warn(`Implicitly creating ${created} from ${source}`); } -function addStaticMembers(structure, env) { - const { - type, - constructor, - static: { members, template }, - } = structure; - if (members.length === 0) { - return; - } - const descriptors = {}; - for (const member of members) { - descriptors[member.name] = getDescriptor$7(member, env); - } - defineProperties$7(constructor, { - valueOf: { value: getValueOf$7 }, - toJSON: { value: convertToJSON$7 }, - ...descriptors, - [Symbol.iterator]: { value: getStructIterator$7 }, - // static variables are objects stored in the static template's slots - [SLOTS$7]: { value: template[SLOTS$7] }, - [PROPS$7]: { value: members.map(m => m.name) }, - [NORMALIZER$7]: { value: normalizeStruct$7 }, - }); - if (type === StructureType$7.Enumeration) { - const enums = constructor[ITEMS$7]; - for (const { name, slot } of members) { - if (name !== undefined) { - // place item in hash to facilitate lookup, - const item = constructor[SLOTS$7][slot]; - if (item instanceof constructor) { - // attach name to item so tagged union code can quickly find it - defineProperties$7(item, { [NAME$7]: { value: name } }); - const index = item[Symbol.toPrimitive](); - enums[index] = enums[name] = item; - } - } else { - // non-exhaustive enum - defineProperties$7(constructor, { [MORE$7]: { value: true } }); - } - } - } else if (type === StructureType$7.ErrorSet) { - const allErrors = getGlobalErrorSet$7(); - const errors = constructor[ITEMS$7]; - for (const { name, slot } of members) { - let error = constructor[SLOTS$7][slot]; - const index = Number(error); - const previous = allErrors[index]; - if (previous) { - if (!(previous instanceof constructor)) { - // error already exists in a previously defined set - // see if we should make that set a subclass or superclass of this one - const otherSet = previous.constructor; - const otherErrors = Object.values(otherSet[SLOTS$7]); - const errorIndices = Object.values(constructor[SLOTS$7]).map(e => Number(e)); - if (otherErrors.every(e => errorIndices.includes(Number(e)))) { - // this set contains the all errors of the other one, so it's a superclass - Object.setPrototypeOf(otherSet.prototype, constructor.prototype); - } else { - // make this set a subclass of the other - Object.setPrototypeOf(constructor.prototype, otherSet.prototype); - for (const otherError of otherErrors) { - if (errorIndices.includes(Number(otherError))) { - // this set should be this error object's class - Object.setPrototypeOf(otherError, constructor.prototype); - } - } - } - } - error = constructor[SLOTS$7][slot] = previous; - } else { - // set error message (overriding prototype) and add to hash - defineProperties$7(error, { message: { value: deanimalizeErrorName(name) } }); - allErrors[index] = allErrors[error.message] = allErrors[`${error}`] = error; - } - errors[index] = errors[error.message] = errors[`${error}`] = error; - } +function getDescription$7(arg) { + const type = typeof(arg); + let s; + if (type === 'object') { + s = (arg) ? Object.prototype.toString.call(arg) : 'null'; + } else { + s = type; } + return addArticle$7(s); } -class Environment { - context; - contextStack = []; - consolePending = []; - consoleTimeout = 0; - viewMap = new WeakMap(); - initPromise; - abandoned = false; - released = false; - littleEndian = true; - runtimeSafety = true; - comptime = false; - /* COMPTIME-ONLY */ - slotNumbers = {}; - slots = {}; - structures = []; - /* COMPTIME-ONLY-END */ - imports; - console = globalThis.console; - - /* - Functions to be defined in subclass: - - getBufferAddress(buffer: ArrayBuffer): bigint|number { - // return a buffer's address - } - allocateHostMemory(len: number, align: number): DataView { - // allocate memory and remember its address - } - allocateShadowMemory(len: number, align: number): DataView { - // allocate memory for shadowing objects - } - freeHostMemory(address: bigint|number, len: number, align: number): void { - // free previously allocated memory - } - freeShadowMemory(address: bigint|number, len: number, align: number): void { - // free memory allocated for shadow - } - allocateFixedMemory(len: number, align: number): DataView { - // allocate fixed memory and keep a reference to it - } - freeFixedMemory(address: bigint|number, len: number, align: number): void { - // free previously allocated fixed memory return the reference - } - obtainFixedView(address: bigint|number, len: number): DataView { - // obtain a data view of memory at given address - } - releaseFixedView(dv: DataView): void { - // release allocated memory stored in data view, doing nothing if data view - // does not contain fixed memory or if memory is static - } - inFixedMemory(object: object): boolean { - // return true/false depending on whether object is in fixed memory - } - copyBytes(dst: DataView, address: bigint|number, len: number): void { - // copy memory at given address into destination view - } - findSentinel(address: bigint|number, bytes: DataView): number { - // return offset where sentinel value is found - } - getMemoryOffset(address: bigint|number) number { - // return offset of address relative to start of module memory - } - recreateAddress(reloc: number) number { - // recreate address of memory belonging to module - } +function addArticle$7(noun) { + return `${article$7(noun)} ${noun}`; +} - getTargetAddress(target: object, cluster: object|undefined) { - // return the address of target's buffer if correctly aligned - } - */ +function article$7(noun) { + return /^\W*[aeiou]/i.test(noun) ? 'an' : 'a'; +} - startContext() { - if (this.context) { - this.contextStack.push(this.context); - } - this.context = new CallContext(); +function formatList$7(list, conj = 'or') { + const sep = ` ${conj} `; + if (list.length > 2) { + return list.slice(0, -1).join(', ') + sep + list[list.length - 1]; + } else { + return list.join(sep); } +} - endContext() { - this.context = this.contextStack.pop(); - } +function getBoolAccessor$7(access, member) { + return cacheMethod$7(access, member, () => { + if (isByteAligned$7(member)) { + const { byteSize } = member; + const typeName = getTypeName$7({ type: MemberType$7.Int, bitSize: byteSize * 8 }); + if (access === 'get') { + const get = DataView.prototype[`get${typeName}`]; + return function(offset, littleEndian) { + return !!get.call(this, offset, littleEndian); + }; + } else { + const set = DataView.prototype[`set${typeName}`]; + const T = (byteSize > 4) ? 1n : 1; + const F = (byteSize > 4) ? 0n : 0; + return function(offset, value, littleEndian) { + set.call(this, offset, value ? T : F, littleEndian); + }; + } + } else { + return getExtendedTypeAccessor$7(access, member); + } + }); +} - allocateMemory(len, align = 0, fixed = false) { - if (fixed) { - return this.allocateFixedMemory(len, align); +function getNumericAccessor$7(access, member) { + return cacheMethod$7(access, member, (name) => { + if (DataView.prototype[name]) { + return DataView.prototype[name]; } else { - return this.allocateRelocMemory(len, align); + return getExtendedTypeAccessor$7(access, member); } + }); +} + +const factories$m = {}; + +function useExtendedBool$7() { + factories$m[MemberType$7.Bool] = getExtendedBoolAccessor$7; +} + +function useExtendedInt$7() { + factories$m[MemberType$7.Int] = getExtendedIntAccessor$7; +} + +function useExtendedUint$7() { + factories$m[MemberType$7.Uint] = getExtendedUintAccessor$7; +} + +function useExtendedFloat$7() { + factories$m[MemberType$7.Float] = getExtendedFloatAccessor$7; +} + +function getExtendedTypeAccessor$7(access, member) { + const f = factories$m[member.type]; + return f(access, member); +} + +function getExtendedBoolAccessor$7(access, member) { + const { bitOffset } = member; + const bitPos = bitOffset & 0x07; + const mask = 1 << bitPos; + const get = DataView.prototype.getInt8; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + return !!(n & mask); + }; + } else { + const set = DataView.prototype.setInt8; + return function(offset, value) { + const n = get.call(this, offset); + const b = (value) ? n | mask : n & ~mask; + set.call(this, offset, b); + }; } +} - allocateRelocMemory(len, align) { - return this.obtainView(new ArrayBuffer(len), 0, len); +function getExtendedIntAccessor$7(access, member) { + if (isByteAligned$7(member)) { + return getAlignedIntAccessor$7(access, member) + } else { + return getUnalignedIntAccessor$7(access, member); } +} - registerMemory(dv, targetDV = null, targetAlign = undefined) { - const { memoryList } = this.context; - const address = this.getViewAddress(dv); - const index = findMemoryIndex(memoryList, address); - memoryList.splice(index, 0, { address, dv, len: dv.byteLength, targetDV, targetAlign }); - return address; +function getExtendedUintAccessor$7(access, member) { + if (isByteAligned$7(member)) { + return getAlignedUintAccessor$7(access, member) + } else { + return getUnalignedUintAccessor$7(access, member); } +} - unregisterMemory(address) { - const { memoryList } = this.context; - const index = findMemoryIndex(memoryList, address); - const prev = memoryList[index - 1]; - if (prev?.address === address) { - memoryList.splice(index - 1, 1); - } +function getExtendedFloatAccessor$7(access, member) { + if (isByteAligned$7(member)) { + return getAlignedFloatAccessor$7(access, member) + } else { + return getUnalignedFloatAccessor$7(access, member); } +} - findMemory(address, len) { - // check for null address (=== can't be used since address can be both number and bigint) - if (this.context) { - const { memoryList } = this.context; - const index = findMemoryIndex(memoryList, address); - const entry = memoryList[index - 1]; - if (entry?.address === address && entry.len === len) { - return entry.targetDV ?? entry.dv; - } else if (entry?.address <= address && address < add(entry.address, entry.len)) { - const offset = Number(address - entry.address); - const targetDV = entry.targetDV ?? entry.dv; - const isOpaque = len === undefined; - if (isOpaque) { - len = targetDV.byteLength - offset; - } - const dv = this.obtainView(targetDV.buffer, targetDV.byteOffset + offset, len); - if (isOpaque) { - // opaque structure--need to save the alignment - dv[ALIGN$7] = entry.targetAlign; - } - return dv; +function getDataView$7(structure, arg, env) { + const { type, byteSize, typedArray } = structure; + let dv; + // not using instanceof just in case we're getting objects created in other contexts + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView') { + dv = arg; + } else if (tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + dv = env.obtainView(arg, 0, arg.byteLength); + } else if (typedArray && tag === typedArray.name || (tag === 'Uint8ClampedArray' && typedArray === Uint8Array)) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else if (tag === 'Uint8Array' && typeof(Buffer) === 'function' && arg instanceof Buffer) { + dv = env.obtainView(arg.buffer, arg.byteOffset, arg.byteLength); + } else { + const memory = arg?.[MEMORY$7]; + if (memory) { + const { constructor, instance: { members: [ member ] } } = structure; + if (arg instanceof constructor) { + return memory; + } else if (type === StructureType$7.Array || type === StructureType$7.Slice || type === StructureType$7.Vector) { + const { byteSize: elementSize, structure: { constructor: Child } } = member; + const number = findElements$7(arg, Child); + if (number !== undefined) { + if (type === StructureType$7.Slice || number * elementSize === byteSize) { + return memory; + } else { + throwArrayLengthMismatch$7(structure, null, arg); + } + } } } - // not found in any of the buffers we've seen--assume it's fixed memory - return this.obtainFixedView(address, len ?? 0); } + if (dv && byteSize !== undefined) { + checkDataViewSize$7(dv, structure); + } + return dv; +} - getViewAddress(dv) { - const address = this.getBufferAddress(dv.buffer); - return add(address, dv.byteOffset); +function checkDataView$7(dv) { + if (dv?.[Symbol.toStringTag] !== 'DataView') { + throwTypeMismatch$7('a DataView', dv); } + return dv; +} - obtainView(buffer, offset, len) { - let entry = this.viewMap.get(buffer); - if (!entry) { - const dv = new DataView(buffer, offset, len); - this.viewMap.set(buffer, dv); - return dv; - } - if (entry instanceof DataView) { - // only one view created thus far--see if that's the matching one - if (entry.byteOffset === offset && entry.byteLength === len) { - return entry; - } else { - // no, need to replace the entry with a hash keyed by `offset:len` - const dv = entry; - const key = `${dv.byteOffset}:${dv.byteLength}`; - entry = { [key]: dv }; - this.viewMap.set(buffer, entry); - } - } - const key = `${offset}:${len}`; - let dv = entry[key]; - if (!dv) { - dv = entry[key] = new DataView(buffer, offset, len); - } - return dv; +function checkDataViewSize$7(dv, structure) { + const { byteSize, type } = structure; + const multiple = type === StructureType$7.Slice; + if (multiple ? dv.byteLength % byteSize !== 0 : dv.byteLength !== byteSize) { + throwBufferSizeMismatch$7(structure, dv); } +} - captureView(address, len, copy) { +function setDataView$7(dv, structure, copy, handlers) { + const { byteSize, type, sentinel } = structure; + const multiple = type === StructureType$7.Slice; + if (!this[MEMORY$7]) { + const { shapeDefiner } = handlers; + checkDataViewSize$7(dv, structure); + const len = dv.byteLength / byteSize; + const source = { [MEMORY$7]: dv }; + sentinel?.validateData(source, len); + shapeDefiner.call(this, copy ? null : dv, len); if (copy) { - // copy content into reloctable memory - const dv = this.allocateRelocMemory(len, 0); - if (len > 0) { - this.copyBytes(dv, address, len); - } - return dv; - } else { - // link into fixed memory - return this.obtainFixedView(address, len); + this[COPIER$7](source); + } + } else { + const byteLength = multiple ? byteSize * this.length : byteSize; + if (dv.byteLength !== byteLength) { + throwBufferSizeMismatch$7(structure, dv, this); } + const source = { [MEMORY$7]: dv }; + sentinel?.validateData(source, this.length); + this[COPIER$7](source); } +} - castView(structure, dv, writable) { - const { constructor, hasPointer } = structure; - const object = constructor.call(ENVIRONMENT$7, dv, { writable }); - if (hasPointer) { - // acquire targets of pointers - this.acquirePointerTargets(object); - } - return object; +function findElements$7(arg, Child) { + // casting to a array/slice + const { constructor: Arg } = arg; + if (Arg === Child) { + // matching object + return 1; + } else if (Arg.child === Child) { + // matching slice/array + return arg.length; } +} - /* COMPTIME-ONLY */ - getSlotNumber(scope, key) { - let slotNumber = this.slotNumbers[scope]; - if (!slotNumber) { - slotNumber = this.slotNumbers[scope] = { next: 0, map: {} }; - } - let slot = slotNumber.map[key]; - if (slot === undefined) { - slot = slotNumber.map[key] = slotNumber.next++; - } - return slot; - } - - readSlot(target, slot) { - const slots = target ? target[SLOTS$7] : this.slots; - return slots?.[slot]; +function requireDataView$7(structure, arg, env) { + const dv = getDataView$7(structure, arg, env); + if (!dv) { + throwBufferExpected$7(structure); } + return dv; +} - writeSlot(target, slot, value) { - const slots = target ? target[SLOTS$7] : this.slots; - if (slots) { - slots[slot] = value; +function getTypedArrayClass$7(member) { + const { type: memberType, byteSize } = member; + if (memberType === MemberType$7.Int) { + switch (byteSize) { + case 1: return Int8Array; + case 2: return Int16Array; + case 4: return Int32Array; + case 8: return BigInt64Array; + } + } else if (memberType === MemberType$7.Uint) { + switch (byteSize) { + case 1: return Uint8Array; + case 2: return Uint16Array; + case 4: return Uint32Array; + case 8: return BigUint64Array; + } + } else if (memberType === MemberType$7.Float) { + switch (byteSize) { + case 4: return Float32Array; + case 8: return Float64Array; } + } else if (memberType === MemberType$7.Object) { + return member.structure.typedArray; } + return null; +} - createTemplate(dv) { - return { - [MEMORY$7]: dv, - [SLOTS$7]: {} - }; - } +function isTypedArray$7(arg, TypedArray) { + const tag = arg?.[Symbol.toStringTag]; + return (!!TypedArray && tag === TypedArray.name); +} - beginStructure(def) { - const { - type, - name, - length, - byteSize, - align, - isConst, - hasPointer, - } = def; - return { - constructor: null, - typedArray: null, - type, - name, - length, - byteSize, - align, - isConst, - hasPointer, - instance: { - members: [], - methods: [], - template: null, - }, - static: { - members: [], - methods: [], - template: null, - }, - }; +function isCompatible$7(arg, constructor) { + const tags = constructor[COMPAT$7]; + if (tags) { + const tag = arg?.[Symbol.toStringTag]; + if (tags.includes(tag)) { + return true; + } } - - attachMember(structure, member, isStatic = false) { - const target = (isStatic) ? structure.static : structure.instance; - target.members.push(member); + if (constructor.child) { + if (findElements$7(arg, constructor.child) !== undefined) { + return true; + } } + return false; +} - attachMethod(structure, method, isStaticOnly = false) { - structure.static.methods.push(method); - if (!isStaticOnly) { - structure.instance.methods.push(method); +function getCompatibleTags$7(structure) { + const { typedArray } = structure; + const tags = []; + if (typedArray) { + tags.push(typedArray.name); + tags.push('DataView'); + if (typedArray === Uint8Array || typedArray === Int8Array) { + tags.push('Uint8ClampedArray'); + tags.push('ArrayBuffer'); + tags.push('SharedArrayBuffer'); } } + return tags; +} - attachTemplate(structure, template, isStatic = false) { - const target = (isStatic) ? structure.static : structure.instance; - target.template = template; +function isBuffer$7(arg, typedArray) { + const tag = arg?.[Symbol.toStringTag]; + if (tag === 'DataView' || tag === 'ArrayBuffer' || tag === 'SharedArrayBuffer') { + return true; + } else if (typedArray && tag === typedArray.name) { + return true; + } else { + return false; } +} - endStructure(structure) { - this.structures.push(structure); - this.finalizeStructure(structure); - for (const structure of this.structures) { - this.acquireDefaultPointers(structure); - } +function getTypeName$7(member) { + const { type, bitSize, byteSize } = member; + if (type === MemberType$7.Int) { + return `${bitSize <= 32 ? '' : 'Big' }Int${bitSize}`; + } else if (type === MemberType$7.Uint) { + return `${bitSize <= 32 ? '' : 'Big' }Uint${bitSize}`; + } else if (type === MemberType$7.Float) { + return `Float${bitSize}`; + } else if (type === MemberType$7.Bool) { + const boolSize = (byteSize !== undefined) ? byteSize * 8 : 1; + return `Bool${boolSize}`; + } else if (type === MemberType$7.Void) { + return `Null`; } +} - defineFactoryArgStruct() { - useBool$7(); - useObject$7(); - useArgStruct$7(); - const options = this.beginStructure({ - type: StructureType$7.Struct, - name: 'Options', - byteSize: 2, - hasPointer: false, - }); - this.attachMember(options, { - type: MemberType$7.Bool, - name: 'omitFunctions', - bitOffset: 0, - bitSize: 1, - byteSize: 1, - }); - this.attachMember(options, { - type: MemberType$7.Bool, - name: 'omitVariables', - bitOffset: 8, - bitSize: 1, - byteSize: 1, - }); - this.finalizeShape(options); - const structure = this.beginStructure({ - type: StructureType$7.ArgStruct, - name: 'factory', - byteSize: 2, - hasPointer: false, - }); - this.attachMember(structure, { - type: MemberType$7.Object, - name: '0', - bitOffset: 0, - bitSize: 16, - byteSize: 2, - slot: 0, - structure: options, - }); - this.attachMember(structure, { - type: MemberType$7.Void, - name: 'retval', - bitOffset: 16, - bitSize: 0, - byteSize: 0 - }); - this.finalizeShape(structure); - return structure.constructor; - } +function getBigIntDescriptor$7(bitSize) { + const getWord = DataView.prototype.getBigUint64; + const setWord = DataView.prototype.setBigUint64; + const wordCount = Math.ceil(bitSize / 64); + return { + get: function(offset, littleEndian) { + let n = 0n; + if (littleEndian) { + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; + } + } else { + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = getWord.call(this, j, littleEndian); + n = (n << 64n) | w; + } + } + return n; + }, + set: function(offset, value, littleEndian) { + let n = value; + const mask = 0xFFFFFFFFFFFFFFFFn; + if (littleEndian) { + for (let i = 0, j = offset; i < wordCount; i++, j += 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } + } else { + n <<= BigInt(wordCount * 64 - bitSize); + for (let i = 0, j = offset + (wordCount - 1) * 8; i < wordCount; i++, j -= 8) { + const w = n & mask; + setWord.call(this, j, w, littleEndian); + n >>= 64n; + } + } + return n; + }, + }; +} - acquireStructures(options) { - const { - omitFunctions = false, - omitVariables = isElectron(), - } = options; - createGlobalErrorSet(); - const thunkId = this.getFactoryThunk(); - const ArgStruct = this.defineFactoryArgStruct(); - const args = new ArgStruct([ { omitFunctions, omitVariables } ]); - this.comptime = true; - this.invokeThunk(thunkId, args); - this.comptime = false; +function getAlignedIntAccessor$7(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$7({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const signMask = (bitSize <= 32) ? 2 ** (bitSize - 1) : 2n ** BigInt(bitSize - 1); + const valueMask = (bitSize <= 32) ? signMask - 1 : signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$7(bitSize); + const signMask = 2n ** BigInt(bitSize - 1); + const valueMask = signMask - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return (n & valueMask) - (n & signMask); + }; + } else { + return function(offset, value, littleEndian) { + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } } +} - getRootModule() { - const root = this.structures[this.structures.length - 1]; - return root.constructor; +function getAlignedUintAccessor$7(access, member) { + const { bitSize, byteSize } = member; + if (bitSize < 64) { + // actual number of bits needed when stored aligned + const typeName = getTypeName$7({ ...member, bitSize: byteSize * 8 }); + const get = DataView.prototype[`get${typeName}`]; + const set = DataView.prototype[`set${typeName}`]; + const valueMask = (bitSize <= 32) ? (2 ** bitSize) - 1 : (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } + } else { + // larger than 64 bits + const { get, set } = getBigIntDescriptor$7(bitSize); + const valueMask = (2n ** BigInt(bitSize)) - 1n; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + return n & valueMask; + }; + } else { + return function(offset, value, littleEndian) { + const n = value & valueMask; + set.call(this, offset, n, littleEndian); + }; + } } +} - hasMethods() { - // all methods are static, so there's no need to check instance methods - return !!this.structures.find(s => s.static.methods.length > 0); +function getUnalignedIntAccessor$7(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + // sub-8-bit numbers have real use cases + const signMask = 2 ** (bitSize - 1); + const valueMask = signMask - 1; + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return (s & valueMask) - (s & signMask); + }; + } else { + const outsideMask = 0xFF ^ ((valueMask | signMask) << bitPos); + return function(offset, value) { + let b = get.call(this, offset); + const n = (value < 0) ? signMask | (value & valueMask) : value & valueMask; + b = (b & outsideMask) | (n << bitPos); + set.call(this, offset, b); + }; + } } + return getUnalignedNumericAccessor$7(access, member); +} - exportStructures() { - this.prepareObjectsForExport(); - const { structures, runtimeSafety, littleEndian } = this; - return { - structures, - options: { runtimeSafety, littleEndian }, - keys: { MEMORY: MEMORY$7, SLOTS: SLOTS$7, CONST: CONST$7 } - }; +function getUnalignedUintAccessor$7(access, member) { + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + if (bitPos + bitSize <= 8) { + const set = DataView.prototype.setUint8; + const get = DataView.prototype.getUint8; + const valueMask = (2 ** bitSize - 1); + if (access === 'get') { + return function(offset) { + const n = get.call(this, offset); + const s = n >>> bitPos; + return s & valueMask; + }; + } else { + const outsideMask = 0xFF ^ (valueMask << bitPos); + return function(offset, value) { + const n = get.call(this, offset); + const b = (n & outsideMask) | ((value & valueMask) << bitPos); + set.call(this, offset, b); + }; + } } + return getUnalignedNumericAccessor$7(access, member); +} - prepareObjectsForExport() { - const objects = findAllObjects(this.structures, SLOTS$7); - const list = []; - for (const object of objects) { - if (object[MEMORY$7]) { - if (this.inFixedMemory(object)) { - // replace fixed memory - const dv = object[MEMORY$7]; - const address = this.getViewAddress(dv); - const offset = this.getMemoryOffset(address); - const len = dv.byteLength; - const relocDV = this.captureView(address, len, true); - relocDV.reloc = offset; - object[MEMORY$7] = relocDV; - list.push({ offset, len, owner: object, replaced: false }); - } - } - } - // larger memory blocks come first - list.sort((a, b) => b.len - a.len); - for (const a of list) { - if (!a.replaced) { - for (const b of list) { - if (a !== b && !b.replaced) { - if (a.offset <= b.offset && b.offset < a.offset + a.len) { - // B is inside A--replace it with a view of A's buffer - const dv = a.owner[MEMORY$7]; - const pos = b.offset - a.offset + dv.byteOffset; - const newDV = this.obtainView(dv.buffer, pos, b.len); - newDV.reloc = b.offset; - b.owner[MEMORY$7] = newDV; - b.replaced = true; - } +function getAlignedFloatAccessor$7(access, member) { + const { bitSize, byteSize } = member; + if (bitSize === 16) { + const buf = new DataView(new ArrayBuffer(4)); + const set = DataView.prototype.setUint16; + const get = DataView.prototype.getUint16; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >>> 15; + const exp = (n & 0x7C00) >> 10; + const frac = n & 0x03FF; + if (exp === 0) { + return (sign) ? -0 : 0; + } else if (exp === 0x1F) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; } - } + } + const n32 = (sign << 31) | ((exp - 15 + 127) << 23) | (frac << 13); + buf.setUint32(0, n32, littleEndian); + return buf.getFloat32(0, littleEndian); } - } - } - - useStructures() { - const module = this.getRootModule(); - // add fixed memory object to list so they can be unlinked - const objects = findAllObjects(this.structures, SLOTS$7); - for (const object of objects) { - if (object[MEMORY$7] && this.inFixedMemory(object)) { - this.variables.push({ object }); + } else { + return function(offset, value, littleEndian) { + buf.setFloat32(0, value, littleEndian); + const n = buf.getUint32(0, littleEndian); + const sign = n >>> 31; + const exp = (n & 0x7F800000) >> 23; + const frac = n & 0x007FFFFF; + const exp16 = (exp - 127 + 15); + let n16; + if (exp === 0) { + n16 = sign << 15; + } else if (exp === 0xFF) { + n16 = sign << 15 | 0x1F << 10 | (frac ? 1 : 0); + } else if (exp16 >= 31) { + n16 = sign << 15 | 0x1F << 10; + } else { + n16 = sign << 15 | exp16 << 10 | (frac >> 13); + } + set.call(this, offset, n16, littleEndian); } } - // clear comptime-only variables - this.slots = {}; - this.structures = []; - module.__zigar = this.getControlObject(); - return module; - } - /* COMPTIME-ONLY-END */ - - finalizeShape(structure) { - const f = getStructureFactory(structure.type); - const constructor = f(structure, this); - if (typeof(constructor) === 'function') { - defineProperties$7(constructor, { - name: { value: structure.name, configurable: true }, - }); - if (!constructor.prototype.hasOwnProperty(Symbol.toStringTag)) { - defineProperties$7(constructor.prototype, { - [Symbol.toStringTag]: { value: structure.name, configurable: true }, - }); + } else if (bitSize === 80) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + return w1 | w2 << 32n | w3 << 64n; + }; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 79n; + const exp = (n & 0x7FFF0000000000000000n) >> 64n; + const frac = n & 0x00007FFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } + } + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; + } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 11n) + BigInt((frac & (2n**11n - 1n)) >= 2n**10n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); } - } - } - - finalizeStructure(structure) { - addStaticMembers(structure, this); - addMethods(structure, this); - } - - createCaller(method, useThis) { - const { name, argStruct, thunkId } = method; - const { constructor } = argStruct; - const self = this; - let f; - if (useThis) { - f = function(...args) { - return self.invokeThunk(thunkId, new constructor([ this, ...args ])); - }; } else { - f = function(...args) { - return self.invokeThunk(thunkId, new constructor(args)); - }; - } - Object.defineProperty(f, 'name', { value: name }); - return f; - } - - - getShadowAddress(target, cluster) { - if (cluster) { - const dv = target[MEMORY$7]; - if (cluster.address === undefined) { - const shadow = this.createClusterShadow(cluster); - cluster.address = this.getViewAddress(shadow[MEMORY$7]); + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n80; + if (exp === 0n) { + n80 = sign << 79n | (frac << 11n); + } else if (exp === 0x07FFn) { + n80 = sign << 79n | 0x7FFFn << 64n | (frac ? 0x00002000000000000000n : 0n) | 0x00008000000000000000n; + // ^ bit 61 ^ bit 63 + } else { + n80 = sign << 79n | (exp - 1023n + 16383n) << 64n | (frac << 11n) | 0x00008000000000000000n; + } + set.call(this, offset, n80, littleEndian); } - return add(cluster.address, dv.byteOffset); - } else { - const shadow = this.createShadow(target); - return this.getViewAddress(shadow[MEMORY$7]); } - } - - createShadow(object) { - const dv = object[MEMORY$7]; - // use the alignment of the structure; in the case of an opaque pointer's target, - // try to the alignment specified when the memory was allocated - const align = object.constructor[ALIGN$7] ?? dv[ALIGN$7]; - const shadow = Object.create(object.constructor.prototype); - const shadowDV = shadow[MEMORY$7] = this.allocateShadowMemory(dv.byteLength, align); - shadow[ATTRIBUTES] = { - address: this.getViewAddress(shadowDV), - len: shadowDV.byteLength, - align, + } else if (bitSize === 128) { + const buf = new DataView(new ArrayBuffer(8)); + const get = function(offset, littleEndian) { + const w1 = BigInt(this.getUint32(offset + (littleEndian ? 0 : byteSize - 4), littleEndian)); + const w2 = BigInt(this.getUint32(offset + (littleEndian ? 4 : byteSize - 8), littleEndian)); + const w3 = BigInt(this.getUint32(offset + (littleEndian ? 8 : byteSize - 12), littleEndian)); + const w4 = BigInt(this.getUint32(offset + (littleEndian ? 12 : byteSize - 16), littleEndian)); + return w1 | w2 << 32n | w3 << 64n | w4 << 96n; }; - return this.addShadow(shadow, object, align); - } - - addShadow(shadow, object, align) { - let { shadowMap } = this.context; - if (!shadowMap) { - shadowMap = this.context.shadowMap = new Map(); - } - shadowMap.set(shadow, object); - this.registerMemory(shadow[MEMORY$7], object[MEMORY$7], align); - return shadow; - } - - removeShadow(dv) { - const { shadowMap } = this.context; - if (shadowMap) { - for (const [ shadow ] of shadowMap) { - if (shadow[MEMORY$7] === dv) { - shadowMap.delete(shadow); - break; + const set = function(offset, value, littleEndian) { + const w1 = value & 0xFFFFFFFFn; + const w2 = (value >> 32n) & 0xFFFFFFFFn; + const w3 = (value >> 64n) & 0xFFFFFFFFn; + const w4 = (value >> 96n) & 0xFFFFFFFFn; + this.setUint32(offset + (littleEndian ? 0 : byteSize - 4), Number(w1), littleEndian); + this.setUint32(offset + (littleEndian ? 4 : byteSize - 8), Number(w2), littleEndian); + this.setUint32(offset + (littleEndian ? 8 : byteSize - 12), Number(w3), littleEndian); + this.setUint32(offset + (littleEndian ? 12 : byteSize - 16), Number(w4), littleEndian); + }; + if (access === 'get') { + return function(offset, littleEndian) { + const n = get.call(this, offset, littleEndian); + const sign = n >> 127n; + const exp = (n & 0x7FFF0000000000000000000000000000n) >> 112n; + const frac = n & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFn; + if (exp === 0n) { + return (sign) ? -0 : 0; + } else if (exp === 0x7FFFn) { + if (!frac) { + return (sign) ? -Infinity : Infinity; + } else { + return NaN; + } + } + const exp64 = exp - 16383n + 1023n; + if (exp64 >= 2047n) { + return (sign) ? -Infinity : Infinity; + } + const n64 = (sign << 63n) | (exp64 << 52n) | (frac >> 60n) + BigInt((frac & (2n**60n - 1n)) >= 2n**59n); + buf.setBigUint64(0, n64, littleEndian); + return buf.getFloat64(0, littleEndian); + } + } else { + return function(offset, value, littleEndian) { + buf.setFloat64(0, value, littleEndian); + const n = buf.getBigUint64(0, littleEndian); + const sign = n >> 63n; + const exp = (n & 0x7FF0000000000000n) >> 52n; + const frac = n & 0x000FFFFFFFFFFFFFn; + let n128; + if (exp === 0n) { + n128 = sign << 127n | (frac << 60n); + } else if (exp === 0x07FFn) { + n128 = sign << 127n | 0x7FFFn << 112n | (frac ? 1n : 0n); + } else { + n128 = sign << 127n | (exp - 1023n + 16383n) << 112n | (frac << 60n); } + set.call(this, offset, n128, littleEndian); } } } +} - updateShadows() { - const { shadowMap } = this.context; - if (!shadowMap) { - return; - } - for (const [ shadow, object ] of shadowMap) { - shadow[COPIER$7](object); - } - } +function getUnalignedFloatAccessor$7(access, member) { + return getUnalignedNumericAccessor$7(access, member); +} - updateShadowTargets() { - const { shadowMap } = this.context; - if (!shadowMap) { - return; - } - for (const [ shadow, object ] of shadowMap) { - object[COPIER$7](shadow); - } +function getUnalignedNumericAccessor$7(access, member) { + // pathological usage scenario--handle it anyway by copying the bitSize into a + // temporary buffer, bit-aligning the data + const { bitSize, bitOffset } = member; + const bitPos = bitOffset & 0x07; + const byteSize = [ 1, 2, 4, 8 ].find(b => b * 8 >= bitSize) ?? Math.ceil(bitSize / 64) * 64; + const buf = new DataView(new ArrayBuffer(byteSize)); + if (access === 'get') { + const getAligned = getNumericAccessor$7('get', { ...member, byteSize }); + const copyBits = getBitAlignFunction$7(bitPos, bitSize, true); + return function(offset, littleEndian) { + copyBits(buf, this, offset); + return getAligned.call(buf, 0, littleEndian); + }; + } else { + const setAligned = getNumericAccessor$7('set', { ...member, byteSize }); + const applyBits = getBitAlignFunction$7(bitPos, bitSize, false); + return function(offset, value, littleEndian) { + setAligned.call(buf, 0, value, littleEndian); + applyBits(this, buf, offset); + }; } +} - releaseShadows() { - const { shadowMap } = this.context; - if (!shadowMap) { - return; - } - for (const [ shadow ] of shadowMap) { - const { address, len, align } = shadow[ATTRIBUTES]; - this.freeShadowMemory(address, len, align); - } - } +const methodCache$7 = {}; - acquirePointerTargets(args) { - const env = this; - const pointerMap = new Map(); - const callback = function({ isActive, isMutable }) { - const pointer = this[POINTER$7]; - if (pointerMap.get(pointer)) { - return; - } else { - pointerMap.set(pointer, true); - } - const writable = !pointer.constructor.const; - const currentTarget = pointer[SLOTS$7][0]; - let newTarget, location; - if (isActive(this)) { - const Target = pointer.constructor.child; - if (!currentTarget || isMutable(this)) { - // obtain address and length from memory - location = pointer[LOCATION_GETTER$7](); - if (!isInvalidAddress(location.address)) { - // get view of memory that pointer points to - const len = (Target[SIZE$7] !== undefined) ? location.length * Target[SIZE$7] : undefined; - const dv = env.findMemory(location.address, len); - // create the target - newTarget = Target.call(ENVIRONMENT$7, dv, { writable }); - } else { - newTarget = null; - } - } else { - newTarget = currentTarget; - } - } - // acquire objects pointed to by pointers in target - currentTarget?.[POINTER_VISITOR$7]?.(callback, { vivificate: true, isMutable: () => writable }); - if (newTarget !== currentTarget) { - newTarget?.[POINTER_VISITOR$7]?.(callback, { vivificate: true, isMutable: () => writable }); - pointer[SLOTS$7][0] = newTarget; - if (env.inFixedMemory(pointer)) { - pointer[FIXED_LOCATION$7] = location; - } - } - }; - args[POINTER_VISITOR$7](callback, { vivificate: true }); +function cacheMethod$7(access, member, cb) { + const { type, bitOffset, bitSize, structure } = member; + const bitPos = bitOffset & 0x07; + const typeName = getTypeName$7(member); + const suffix = isByteAligned$7(member) ? `` : `Bit${bitPos}`; + const isInt = type === MemberType$7.Int || type === MemberType$7.Uint; + let name = `${access}${typeName}${suffix}`; + let isSize = false, originalName = name; + if (isInt && bitSize === 64) { + const zigTypeName = structure?.name; + if (zigTypeName === 'usize' || zigTypeName === 'isize') { + name += 'Size'; + isSize = true; + } } - - /* COMPTIME-ONLY */ - acquireDefaultPointers(structure) { - const { constructor, hasPointer, instance: { template } } = structure; - if (hasPointer && template && template[MEMORY$7]) { - // create a placeholder for retrieving default pointers - const placeholder = Object.create(constructor.prototype); - placeholder[MEMORY$7] = template[MEMORY$7]; - placeholder[SLOTS$7] = template[SLOTS$7]; - this.acquirePointerTargets(placeholder); + let fn = methodCache$7[name]; + if (!fn) { + if (isInt && access === 'set') { + // add auto-conversion between number and bigint + const Primitive = getPrimitiveClass$7(member); + const set = cb(originalName); + fn = function(offset, value, littleEndian) { + set.call(this, offset, Primitive(value), littleEndian); + }; + } else if (isSize && access === 'get') { + // use number instead of bigint where possible + const get = cb(originalName); + const min = BigInt(Number.MIN_SAFE_INTEGER); + const max = BigInt(Number.MAX_SAFE_INTEGER); + fn = function(offset, littleEndian) { + const value = get.call(this, offset, littleEndian); + if (min <= value && value <= max) { + return Number(value); + } else { + return value; + } + }; + } else { + fn = cb(name); } + if (fn && fn.name !== name) { + Object.defineProperty(fn, 'name', { value: name, configurable: true, writable: false }); + } + methodCache$7[name] = fn; } - /* COMPTIME-ONLY-END */ + return fn; } -class CallContext { - pointerProcessed = new Map(); - memoryList = []; - shadowMap = null; - /* WASM-ONLY */ - call = 0; - /* WASM-ONLY-END */ +function useAllExtendedTypes$7() { + useExtendedBool$7(); + useExtendedInt$7(); + useExtendedUint$7(); + useExtendedFloat$7(); } -function findSortedIndex(array, value, cb) { - let low = 0; - let high = array.length; - if (high === 0) { - return 0; - } - while (low < high) { - const mid = Math.floor((low + high) / 2); - const value2 = cb(array[mid]); - if (value2 <= value) { - low = mid + 1; - } else { - high = mid; - } +const MemberType$7 = { + Void: 0, + Bool: 1, + Int: 2, + Uint: 3, + Float: 4, + EnumerationItem: 5, + Error: 6, + Object: 7, + Type: 8, + Comptime: 9, + Static: 10, + Literal: 11, + Null: 12, + Undefined: 13, +}; + +function isReadOnly$7(type) { + switch (type) { + case MemberType$7.Type: + case MemberType$7.Comptime: + case MemberType$7.Literal: + return true; + default: + return false; } - return high; } -function findMemoryIndex(array, address) { - return findSortedIndex(array, address, m => m.address); +const factories$l = {}; + +function useVoid$7() { + factories$l[MemberType$7.Void] = getVoidDescriptor$7; } -function add(address, len) { - return address + ((typeof(address) === 'bigint') ? BigInt(len) : len); +function useBool$7() { + factories$l[MemberType$7.Bool] = getBoolDescriptor$7; } -function isInvalidAddress(address) { - if (typeof(address) === 'bigint') { - return address === 0xaaaaaaaaaaaaaaaan; - } else { - return address === 0xaaaaaaaa; - } +function useInt$7() { + factories$l[MemberType$7.Int] = getIntDescriptor$7; } -function isElectron() { - return typeof(process) === 'object' - && typeof(process?.versions) === 'object' - && !!process.versions?.electron; +function useUint$7() { + factories$l[MemberType$7.Uint] = getUintDescriptor$7; } -class WebAssemblyEnvironment extends Environment { - imports = { - getFactoryThunk: { argType: '', returnType: 'i' }, - allocateExternMemory: { argType: 'ii', returnType: 'i' }, - freeExternMemory: { argType: 'iii' }, - allocateShadowMemory: { argType: 'cii', returnType: 'v' }, - freeShadowMemory: { argType: 'ciii' }, - runThunk: { argType: 'iv', returnType: 'v' }, - isRuntimeSafetyActive: { argType: '', returnType: 'b' }, - }; - exports = { - allocateHostMemory: { argType: 'ii', returnType: 'v' }, - freeHostMemory: { argType: 'iii' }, - captureString: { argType: 'ii', returnType: 'v' }, - captureView: { argType: 'iib', returnType: 'v' }, - castView: { argType: 'vvb', returnType: 'v' }, - getSlotNumber: { argType: 'ii', returnType: 'i' }, - readSlot: { argType: 'vi', returnType: 'v' }, - writeSlot: { argType: 'viv' }, - getViewAddress: { argType: 'v', returnType: 'i' }, - beginDefinition: { returnType: 'v' }, - insertInteger: { argType: 'vsi', alias: 'insertProperty' }, - insertBoolean: { argType: 'vsb', alias: 'insertProperty' }, - insertString: { argType: 'vss', alias: 'insertProperty' }, - insertObject: { argType: 'vsv', alias: 'insertProperty' }, - beginStructure: { argType: 'v', returnType: 'v' }, - attachMember: { argType: 'vvb' }, - attachMethod: { argType: 'vvb' }, - createTemplate: { argType: 'v', returnType: 'v' }, - attachTemplate: { argType: 'vvb' }, - finalizeShape: { argType: 'v' }, - endStructure: { argType: 'v' }, - startCall: { argType: 'iv', returnType: 'i' }, - endCall: { argType: 'iv', returnType: 'i' }, - }; - nextValueIndex = 1; - valueTable = { 0: null }; - valueIndices = new Map; - memory = null; - // WASM is always little endian - littleEndian = true; +function useFloat$7() { + factories$l[MemberType$7.Float] = getFloatDescriptor$7; +} - allocateHostMemory(len, align) { - // allocate memory in both JavaScript and WASM space - const constructor = { [ALIGN$7]: align }; - const copier = getMemoryCopier$7(len); - const dv = this.allocateRelocMemory(len, align); - const shadowDV = this.allocateShadowMemory(len, align); - // create a shadow for the relocatable memory - const object = { constructor, [MEMORY$7]: dv, [COPIER$7]: copier }; - const shadow = { constructor, [MEMORY$7]: shadowDV, [COPIER$7]: copier }; - shadow[ATTRIBUTES] = { address: this.getViewAddress(shadowDV), len, align }; - this.addShadow(shadow, object, align); - return shadowDV; - } +function useEnumerationItem$7() { + factories$l[MemberType$7.EnumerationItem] = getEnumerationItemDescriptor$7; +} - freeHostMemory(address, len, align) { - const dv = this.findMemory(address, len); - this.removeShadow(dv); - this.unregisterMemory(address); - this.freeShadowMemory(address, len, align); - } +function useError$7() { + factories$l[MemberType$7.Error] = getErrorDescriptor$7; +} - getBufferAddress(buffer) { - return 0; - } +function useObject$7() { + factories$l[MemberType$7.Object] = getObjectDescriptor$7; +} - allocateFixedMemory(len, align) { - if (len === 0) { - return new DataView(this.memory.buffer, 0, 0); - } - const address = this.allocateExternMemory(len, align); - const dv = this.obtainFixedView(address, len); - dv[ALIGN$7] = align; - return dv; - } +function useType$7() { + factories$l[MemberType$7.Type] = getTypeDescriptor$7; +} - freeFixedMemory(address, len, align) { - if (len === 0) { - return; - } - this.freeExternMemory(address, len, align); - } +function useComptime$7() { + factories$l[MemberType$7.Comptime] = getComptimeDescriptor$7; +} - obtainFixedView(address, len) { - const { memory } = this; - if (len === 0 && address === -1431655766) { // 0xAAAAAAAA - address = 0; - } - const dv = this.obtainView(memory.buffer, address, len); - dv[MEMORY$7] = { memory, address, len }; - return dv; - } +function useStatic$7() { + factories$l[MemberType$7.Static] = getStaticDescriptor$7; +} - releaseFixedView(dv) { - dv.buffer; - const address = dv.byteOffset; - const len = dv.byteLength; - // only allocated memory would have align attached - const align = dv[ALIGN$7]; - if (align !== undefined) { - this.freeFixedMemory(address, len, align); - } - } +function useLiteral$7() { + factories$l[MemberType$7.Literal] = getLiteralDescriptor$7; +} - inFixedMemory(object) { - // reconnect any detached buffer before checking - if (!this.memory) { - return false; - } - restoreMemory$7.call(object); - return object[MEMORY$7].buffer === this.memory.buffer; - } +function useNull$7() { + factories$l[MemberType$7.Null] = getNullDescriptor$7; +} - copyBytes(dst, address, len) { - const { memory } = this; - const src = new DataView(memory.buffer, address, len); - const copy = getCopyFunction$7(len); - copy(dst, src); - } +function useUndefined$7() { + factories$l[MemberType$7.Undefined] = getUndefinedDescriptor$7; +} - findSentinel(address, bytes) { - const { memory } = this; - const len = bytes.byteLength; - const end = memory.buffer.byteLength - len + 1; - for (let i = address; i < end; i += len) { - const dv = new DataView(memory.buffer, i, len); - let match = true; - for (let j = 0; j < len; j++) { - const a = dv.getUint8(j); - const b = bytes.getUint8(j); - if (a !== b) { - match = false; - break; - } - } - if (match) { - return (i - address) / len; +function isByteAligned$7({ bitOffset, bitSize, byteSize }) { + return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; +} + +function getDescriptor$7(member, env) { + const f = factories$l[member.type]; + return f(member, env); +} + +function getVoidDescriptor$7(member, env) { + const { runtimeSafety } = env; + return { + get: function() { + return undefined; + }, + set: (runtimeSafety) + ? function(value) { + if (value !== undefined) { + throwNotUndefined$7(member); + } } - } + : function() {}, } +} - captureString(address, len) { - const { buffer } = this.memory; - const ta = new Uint8Array(buffer, address, len); - return decodeText$7(ta); +function getNullDescriptor$7(member, env) { + return { + get: function() { + return null; + }, } +} - getTargetAddress(target, cluster) { - if (this.inFixedMemory(target)) { - return this.getViewAddress(target[MEMORY$7]); - } - if (target[MEMORY$7].byteLength === 0) { - // it's a null pointer/empty slice - return 0; - } - // relocatable buffers always need shadowing - return false; +function getUndefinedDescriptor$7(member, env) { + return { + get: function() { + return undefined; + }, } +} - clearExchangeTable() { - if (this.nextValueIndex !== 1) { - this.nextValueIndex = 1; - this.valueTable = { 0: null }; - this.valueIndices = new Map(); - } - } +function getBoolDescriptor$7(member, env) { + return getDescriptorUsing$7(member, env, getBoolAccessor$7) +} - getObjectIndex(object) { - if (object) { - let index = this.valueIndices.get(object); - if (index === undefined) { - index = this.nextValueIndex++; - this.valueIndices.set(object, index); - this.valueTable[index] = object; - } - return index; - } else { - return 0; - } - } +function getIntDescriptor$7(member, env) { + const getDataViewAccessor = addRuntimeCheck$7(env, getNumericAccessor$7); + return getDescriptorUsing$7(member, env, getDataViewAccessor) +} - fromWebAssembly(type, arg) { - switch (type) { - case 'v': - case 's': return this.valueTable[arg]; - case 'i': return arg; - case 'b': return !!arg; - } - } +function getUintDescriptor$7(member, env) { + const getDataViewAccessor = addRuntimeCheck$7(env, getNumericAccessor$7); + return getDescriptorUsing$7(member, env, getDataViewAccessor) +} - toWebAssembly(type, arg) { - switch (type) { - case 'v': - case 's': return this.getObjectIndex(arg); - case 'i': return arg; - case 'b': return arg ? 1 : 0; +function addRuntimeCheck$7(env, getDataViewAccessor) { + return function (access, member) { + const { + runtimeSafety = true, + } = env; + const accessor = getDataViewAccessor(access, member); + if (runtimeSafety && access === 'set') { + const { min, max } = getIntRange$7(member); + return function(offset, value, littleEndian) { + if (value < min || value > max) { + throwOverflow$7(member, value); + } + accessor.call(this, offset, value, littleEndian); + }; } - } + return accessor; + }; +} - exportFunction(fn, argType = '', returnType = '') { - if (!fn) { - return () => {}; - } - return (...args) => { - args = args.map((arg, i) => this.fromWebAssembly(argType.charAt(i), arg)); - const retval = fn.apply(this, args); - return this.toWebAssembly(returnType, retval); - }; - } +function getFloatDescriptor$7(member, env) { + return getDescriptorUsing$7(member, env, getNumericAccessor$7) +} - importFunction(fn, argType = '', returnType = '') { - let needCallContext = false; - if (argType.startsWith('c')) { - needCallContext = true; - argType = argType.slice(1); - } - return (...args) => { - args = args.map((arg, i) => this.toWebAssembly(argType.charAt(i), arg)); - if (needCallContext) { - args = [ this.context.call, ...args ]; - } - const retval = fn.apply(this, args); - return this.fromWebAssembly(returnType, retval); - }; - } +function getValueDescriptor$7(member, env) { + // enum can be int or uint--need the type from the structure + const { type, structure } = member.structure.instance.members[0]; + // combine that with the offset/size + const valueMember = { ...member, type, structure }; + return getDescriptor$7(valueMember, env); +} - exportFunctions() { - const imports = {}; - for (const [ name, { argType, returnType, alias } ] of Object.entries(this.exports)) { - const fn = this[alias ?? name]; - imports[`_${name}`] = this.exportFunction(fn, argType, returnType); +function getEnumerationItemDescriptor$7(member, env) { + const { structure } = member; + const { get: getValue, set: setValue } = getValueDescriptor$7(member, env); + const findEnum = function(value) { + const { constructor } = structure; + // the enumeration constructor returns the object for the int value + const item = (value instanceof constructor) ? value : constructor(value); + if (!item) { + throwEnumExpected$7(structure, value); } - return imports; - } - - importFunctions(exports) { - for (const [ name, fn ] of Object.entries(exports)) { - const info = this.imports[name]; - if (info) { - const { argType, returnType } = info; - this[name] = this.importFunction(fn, argType, returnType); + return item + }; + return { + get: (getValue.length === 0) + ? function getEnum() { + const value = getValue.call(this); + return findEnum(value); } - } - } + : function getEnumElement(index) { + const value = getValue.call(this, index); + return findEnum(value); + }, + set: (setValue.length === 1) + ? function setEnum(value) { + // call Symbol.toPrimitive directly as enum can be bigint or number + const item = findEnum(value); + setValue.call(this, item[Symbol.toPrimitive]()); + } + : function setEnumElement(index, value) { + const item = findEnum(value); + setValue.call(this, index, item[Symbol.toPrimitive]()); + }, + }; +} - async instantiateWebAssembly(source) { - const res = await source; - const env = this.exportFunctions(); - const wasi = this.getWASI(); - const imports = { env, wasi_snapshot_preview1: wasi }; - if (res[Symbol.toStringTag] === 'Response') { - return WebAssembly.instantiateStreaming(res, imports); +function getErrorDescriptor$7(member, env) { + const { structure } = member; + const { name } = structure; + const { get: getValue, set: setValue } = getValueDescriptor$7(member, env); + const acceptAny = name === 'anyerror'; + const globalErrorSet = getGlobalErrorSet$7(); + const findError = function(value, allowZero = false) { + const { constructor } = structure; + let item; + if (value === 0 && allowZero) { + return; + } else if (value instanceof Error) { + if (value instanceof (acceptAny ? globalErrorSet : constructor)) { + item = value; + } else { + throwNotInErrorSet$7(structure); + } } else { - return WebAssembly.instantiate(res, imports); + item = acceptAny ? globalErrorSet[value] : constructor(value); + if (!item) { + throwErrorExpected$7(structure, value); + } } - } + return item + }; + return { + get: (getValue.length === 0) + ? function getError(allowZero) { + const value = getValue.call(this); + return findError(value, allowZero); + } + : function getErrorElement(index) { + const value = getValue.call(this, index); + return findError(value, false); + }, + set: (setValue.length === 1) + ? function setError(value, allowZero) { + const item = findError(value, allowZero); + setValue.call(this, Number(item ?? 0)); + } + : function setError(index, value) { + const item = findError(value, false); + setValue.call(this, index, Number(item)); + }, + }; +} - loadModule(source) { - return this.initPromise = (async () => { - const { instance } = await this.instantiateWebAssembly(source); - const { memory, _initialize } = instance.exports; - this.importFunctions(instance.exports); - this.trackInstance(instance); - this.runtimeSafety = this.isRuntimeSafetyActive(); - this.memory = memory; - _initialize?.(); - })(); +function isValueExpected$7(structure) { + switch (structure.type) { + case StructureType$7.Primitive: + case StructureType$7.ErrorUnion: + case StructureType$7.Optional: + case StructureType$7.Enumeration: + case StructureType$7.ErrorSet: + return true; + default: + return false; } +} + +function getValue$7(slot) { + const object = this[SLOTS$7][slot] ?? this[VIVIFICATOR$7](slot); + return object[GETTER$7](); +} + +function getObject$7(slot) { + const object = this[SLOTS$7][slot] ?? this[VIVIFICATOR$7](slot); + return object; +} - trackInstance(instance) { - // use WeakRef to detect whether web-assembly instance has been gc'ed - const ref = new WeakRef(instance); - Object.defineProperty(this, 'released', { get: () => !ref.deref(), enumerable: true }); - } +function setValue$7(slot, value) { + const object = this[SLOTS$7][slot] ?? this[VIVIFICATOR$7](slot); + object[SETTER$7](value); +} - linkVariables(writeBack) { - // linkage occurs when WASM compilation is complete and functions have been imported - // nothing needs to happen when WASM is not used - if (this.initPromise) { - this.initPromise = this.initPromise.then(() => super.linkVariables(writeBack)); - } +function bindSlot$7(slot, { get, set }) { + if (slot !== undefined) { + return { + get: function() { + return get.call(this, slot); + }, + set: (set) + ? function(arg) { + return set.call(this, slot, arg); + } + : undefined, + }; + } else { + // array accessors + return { get, set }; } +} - /* COMPTIME-ONLY */ - beginDefinition() { - return {}; - } +function getObjectDescriptor$7(member, env) { + const { structure, slot } = member; + return bindSlot$7(slot, { + get: isValueExpected$7(structure) ? getValue$7 : getObject$7, + set: setValue$7, + }); +} - insertProperty(def, name, value) { - def[name] = value; - } - /* COMPTIME-ONLY-END */ +function getType$7(slot) { + // unsupported types will have undefined structure + const structure = this[SLOTS$7][slot]; + return structure?.constructor; +} - getMemoryOffset(address) { - // WASM address space starts at 0 - return address; - } +function getTypeDescriptor$7(member, env) { + const { slot } = member; + return bindSlot$7(slot, { get: getType$7 }); +} - recreateAddress(reloc) { - return reloc; - } +function getComptimeDescriptor$7(member, env) { + const { slot, structure } = member; + return bindSlot$7(slot, { + get: isValueExpected$7(structure) ? getValue$7 : getObject$7, + }); +} - startCall(call, args) { - this.startContext(); - // call context, used by allocateShadowMemory and freeShadowMemory - this.context.call = call; - if (args[POINTER_VISITOR$7]) { - this.updatePointerAddresses(args); - } - // return address of shadow for argumnet struct - const address = this.getShadowAddress(args); - this.updateShadows(); - return address; - } +function getStaticDescriptor$7(member, env) { + const { slot, structure } = member; + return bindSlot$7(slot, { + get: isValueExpected$7(structure) ? getValue$7 : getObject$7, + set: setValue$7, + }); +} - endCall(call, args) { - this.updateShadowTargets(); - if (args[POINTER_VISITOR$7]) { - this.acquirePointerTargets(args); - } - this.releaseShadows(); - // restore the previous context if there's one - this.endContext(); - if (!this.context && this.flushConsole) { - this.flushConsole(); - } - } +function getLiteral$7(slot) { + const object = this[SLOTS$7][slot]; + return object.string; +} - async runThunk(thunkId, args) { - // wait for compilation - await this.initPromise; - // invoke runThunk() from WASM code - return this.runThunk(thunkId, args); - } +function getLiteralDescriptor$7(member, env) { + const { slot } = member; + return bindSlot$7(slot, { get: getLiteral$7 }); +} - invokeThunk(thunkId, args) { - // wasm-exporter.zig will invoke startCall() with the context address and the args - // we can't do pointer fix up here since we need the context in order to allocate - // memory from the WebAssembly allocator; pointer target acquisition will happen in - // endCall() - const err = this.runThunk(thunkId, args); - // errors returned by exported Zig functions are normally written into the - // argument object and get thrown when we access its retval property (a zig error union) - // error strings returned by the thunk are due to problems in the thunking process - // (i.e. bugs in export.zig) - if (err) { - if (err[Symbol.toStringTag] === 'Promise') { - // getting a promise, WASM is not yet ready - // wait for fulfillment, then either return result or throw - return err.then((err) => { - if (err) { - throwZigError(err); +function getDescriptorUsing$7(member, env, getDataViewAccessor) { + const { + littleEndian = true, + } = env; + const { bitOffset, byteSize } = member; + const getter = getDataViewAccessor('get', member); + const setter = getDataViewAccessor('set', member); + if (bitOffset !== undefined) { + const offset = bitOffset >> 3; + return { + get: function getValue() { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return getter.call(this[MEMORY$7], offset, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$7.call(this)) { + return getter.call(this[MEMORY$7], offset, littleEndian); + } else { + throw err; } - return args.retval; - }); - } else { - throwZigError(err); + } + /* WASM-ONLY-END*/ + }, + set: function setValue(value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END*/ + return setter.call(this[MEMORY$7], offset, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$7.call(this)) { + return setter.call(this[MEMORY$7], offset, value, littleEndian); + } else { + throw err; + } + } + /* WASM-ONLY-END*/ } } - return args.retval; - } - - getWASI() { - return { - proc_exit: (rval) => { - }, - fd_write: (fd, iovs_ptr, iovs_count, written_ptr) => { - if (fd === 1 || fd === 2) { - const dv = new DataView(this.memory.buffer); - let written = 0; - for (let i = 0, p = iovs_ptr; i < iovs_count; i++, p += 8) { - const buf_ptr = dv.getUint32(p, true); - const buf_len = dv.getUint32(p + 4, true); - const buf = new DataView(this.memory.buffer, buf_ptr, buf_len); - this.writeToConsole(buf); - written += buf_len; + } else { + return { + get: function getElement(index) { + try { + return getter.call(this[MEMORY$7], index * byteSize, littleEndian); + } catch (err) { + /* WASM-ONLY */ + if (err instanceof TypeError && restoreMemory$7.call(this)) { + return getter.call(this[MEMORY$7], index * byteSize, littleEndian); + } else { + /* WASM-ONLY-END */ + rethrowRangeError$7(member, index, err); + /* WASM-ONLY */ } - dv.setUint32(written_ptr, written, true); - return 0; - } else { - return 1; + /* WASM-ONLY-END */ } }, - random_get: (buf, buf_len) => { - const dv = new DataView(this.memory.buffer); - for (let i = 0; i < buf_len; i++) { - dv.setUint8(Math.floor(256 * Math.random())); + set: function setElement(index, value) { + /* WASM-ONLY */ + try { + /* WASM-ONLY-END */ + return setter.call(this[MEMORY$7], index * byteSize, value, littleEndian); + /* WASM-ONLY */ + } catch (err) { + if (err instanceof TypeError && restoreMemory$7.call(this)) { + return setter.call(this[MEMORY$7], index * byteSize, value, littleEndian); + } else { + rethrowRangeError$7(member, index, err); + } } - return 0; + /* WASM-ONLY-END */ }, - }; + } } } +function useAllMemberTypes$7() { + useVoid$7(); + useNull$7(); + useUndefined$7(); + useBool$7(); + useInt$7(); + useUint$7(); + useFloat$7(); + useEnumerationItem$7(); + useError$7(); + useObject$7(); + useType$7(); + useComptime$7(); + useStatic$7(); + useLiteral$7(); +} + +process.cwd(); + useAllMemberTypes$7(); useAllStructureTypes$7(); useAllExtendedTypes$7(); -/* COMPTIME-ONLY-END */ - -function createEnvironment(source) { - return new WebAssemblyEnvironment(); -} const MEMORY$6 = Symbol('memory'); const SLOTS$6 = Symbol('slots'); @@ -10637,11 +19610,6 @@ function useAllMemberTypes$6() { process.cwd(); -function findSourceFile(modulePath, options) { - const { sourceFiles } = options; - return sourceFiles?.[modulePath]; -} - useAllMemberTypes$6(); useAllStructureTypes$6(); useAllExtendedTypes$6(); diff --git a/zigar-compiler/test/integration/type-handling/error-set/as-static-variables.zig b/zigar-compiler/test/integration/type-handling/error-set/as-static-variables.zig index fb1a3973..f8aff1cb 100644 --- a/zigar-compiler/test/integration/type-handling/error-set/as-static-variables.zig +++ b/zigar-compiler/test/integration/type-handling/error-set/as-static-variables.zig @@ -13,6 +13,11 @@ pub const NormalError = error{ OutOfMemory, }; +pub const CommonError = error{ + OutOfMemory, + NoMoreBeer, +}; + pub const PossibleError = NormalError || StrangeError; pub var error_var = NormalError.FileNotFound; diff --git a/zigar-compiler/test/integration/type-handling/error-set/tests.js b/zigar-compiler/test/integration/type-handling/error-set/tests.js index 2a8b1478..0c2da0cf 100644 --- a/zigar-compiler/test/integration/type-handling/error-set/tests.js +++ b/zigar-compiler/test/integration/type-handling/error-set/tests.js @@ -19,14 +19,16 @@ export function addTests(importModule, options) { NormalError, StrangeError, PossibleError, + CommonError, print, } = await importTest('as-static-variables'); expect(NormalError.OutOfMemory).to.be.instanceOf(Error); - expect(NormalError.OutOfMemory).to.be.instanceOf(NormalError); - expect(PossibleError.OutOfMemory).to.be.instanceOf(PossibleError); + expect(NormalError.OutOfMemory in NormalError).to.be.true; + expect(NormalError.OutOfMemory).to.equal(PossibleError.OutOfMemory); + expect(PossibleError.OutOfMemory in PossibleError).to.be.true; expect(StrangeError.SystemIsOnFire).to.equal(PossibleError.SystemIsOnFire); - expect(StrangeError.SystemIsOnFire).to.be.instanceOf(PossibleError); - expect(() => StrangeError.SystemIsOnFire.$ = StrangeError.SystemIsOnFire).to.throw(TypeError); + expect(StrangeError.SystemIsOnFire in PossibleError).to.be.true; + expect(StrangeError.NoMoreBeer).to.equal(CommonError.NoMoreBeer); expect(module.error_var).to.equal(NormalError.FileNotFound); const [ before ] = await capture(() => print()); expect(before).to.equal('error.FileNotFound'); diff --git a/zigar-runtime/dist/index.js b/zigar-runtime/dist/index.js index 62a17b6c..0fe3d6c7 100644 --- a/zigar-runtime/dist/index.js +++ b/zigar-runtime/dist/index.js @@ -2,8 +2,8 @@ const MEMORY = Symbol('memory'); const SLOTS = Symbol('slots'); const PARENT = Symbol('parent'); const NAME = Symbol('name'); +const CLASS = Symbol('class'); const TAG = Symbol('tag'); -const ITEMS = Symbol('items'); const PROPS = Symbol('props'); const GETTER = Symbol('getter'); const SETTER = Symbol('setter'); @@ -419,12 +419,12 @@ function convertToJSON() { const process = function(value) { const normalizer = value?.[NORMALIZER]; if (normalizer) { - if (value instanceof Error) { - return { error: value.message }; - } let result = map.get(value); if (result === undefined) { result = normalizer.call(value, process, options); + if (typeof(result?.toJSON) === 'function') { + result = result.toJSON(); + } map.set(value, result); } return result; @@ -1318,9 +1318,7 @@ function defineEnumerationShape(structure, env) { members: [ member ], }, } = structure; - const { get: getIndex, set: setIndex } = getDescriptor(member, env); - // get the enum descriptor instead of the int/uint descriptor - const { get, set } = getDescriptor({ ...member, type: MemberType.EnumerationItem, structure }, env); + const { get, set } = getDescriptor(member, env); const expected = [ 'string', 'number', 'tagged union' ]; const propApplier = createPropertyApplier(structure); const initializer = function(arg) { @@ -1334,17 +1332,19 @@ function defineEnumerationShape(structure, env) { }; const alternateCaster = function(arg) { if (typeof(arg) === 'string' || typeof(arg) === 'number' || typeof(arg) === 'bigint') { - const items = constructor[ITEMS]; - let item = items[arg]; + let item = constructor[arg]; if (!item) { if (constructor[MORE] && typeof(arg) !== 'string') { // create the item on-the-fly when enum is non-exhaustive - item = items[arg] = new constructor(undefined); - setIndex.call(item, arg); - defineProperties(item, { [NAME]: { value: `${arg}` } }); + item = new constructor(undefined); + debugger; + set.call(item, arg, 'number'); + appendEnumeration(constructor, `${arg}`, item); } } return item; + } else if (arg instanceof constructor) { + return arg; } else if (arg?.[TAG] instanceof constructor) { // a tagged union, return the active tag return arg[TAG]; @@ -1357,7 +1357,7 @@ function defineEnumerationShape(structure, env) { const constructor = structure.constructor = createConstructor(structure, { initializer, alternateCaster }, env); const typedArray = structure.typedArray = getTypedArrayClass(member); const toPrimitive = function(hint) { - return (hint === 'string') ? this.$[NAME] : getIndex.call(this); + return (hint === 'string') ? this.$[NAME] : get.call(this, 'number'); }; const instanceDescriptors = { $: { get, set }, @@ -1374,7 +1374,6 @@ function defineEnumerationShape(structure, env) { const staticDescriptors = { [ALIGN]: { value: align }, [SIZE]: { value: byteSize }, - [ITEMS]: { value: {} }, }; return attachDescriptors(constructor, instanceDescriptors, staticDescriptors); } @@ -1382,6 +1381,25 @@ function normalizeEnumerationItem(cb) { return cb(this.$[NAME]); } +function appendEnumeration(enumeration, name, item) { + if (name !== undefined) { + // enum can have static variables + if (item instanceof enumeration) { + // attach name to item so tagged union code can quickly find it + defineProperties(item, { [NAME]: { value: name } }); + // call toPrimitive directly since enum can be bigint or number + const index = item[Symbol.toPrimitive](); + defineProperties(enumeration, { + [index]: { value: item }, + [name]: { value: item }, + }); + } + } else { + // non-exhaustive enum + defineProperties(enumeration, { [MORE]: { value: true } }); + } +} + function defineErrorUnion(structure, env) { const { byteSize, @@ -1392,18 +1410,17 @@ function defineErrorUnion(structure, env) { const { get: getValue, set: setValue } = getDescriptor(members[0], env); const { get: getError, set: setError } = getDescriptor(members[1], env); const get = function() { - const error = getError.call(this, true); - if (error) { - throw error; + const errNum = getError.call(this, 'number'); + if (errNum) { + throw getError.call(this); } else { return getValue.call(this); } }; const isValueVoid = members[0].type === MemberType.Void; - const acceptAny = members[1].structure.name === 'anyerror'; - const TargetError = (acceptAny) ? getGlobalErrorSet() : members[1].structure.constructor; + const errorSet = members[1].structure.constructor; const isChildActive = function() { - return !getError.call(this, true); + return !getError.call(this, 'number'); }; const clearValue = function() { this[RESETTER](); @@ -1419,33 +1436,26 @@ function defineErrorUnion(structure, env) { this[POINTER_VISITOR](copyPointer, { vivificate: true, source: arg }); } } - } else if (arg instanceof TargetError) { + } else if (arg instanceof errorSet[CLASS] && errorSet(arg)) { setError.call(this, arg); clearValue.call(this); } else if (arg !== undefined || isValueVoid) { try { // call setValue() first, in case it throws setValue.call(this, arg); - setError.call(this, 0, true); + setError.call(this, 0, 'number'); } catch (err) { if (arg instanceof Error) { // we give setValue a chance to see if the error is actually an acceptable value // now is time to throw an error throwNotInErrorSet(structure); + } else if (isErrorJSON(arg)) { + setError.call(this, arg); + clearValue.call(this); } else if (arg && typeof(arg) === 'object') { - try { - if (propApplier.call(this, arg) === 0) { - throw err; - } - } catch (err) { - const { error } = arg; - if (typeof(error) === 'string') { - setError.call(this, error); - clearValue.call(this); - } else { - throw err; - } - } + if (propApplier.call(this, arg) === 0) { + throw err; + } } else { throw err; } @@ -1581,86 +1591,6 @@ function defineOptional(structure, env) { return attachDescriptors(constructor, instanceDescriptors, staticDescriptors); } -function definePrimitive(structure, env) { - const { - byteSize, - align, - instance: { members: [ member ] }, - } = structure; - const { get, set } = getDescriptor(member, env); - const propApplier = createPropertyApplier(structure); - const initializer = function(arg) { - if (arg instanceof constructor) { - this[COPIER](arg); - } else { - if (arg && typeof(arg) === 'object') { - if (propApplier.call(this, arg) === 0) { - const type = getPrimitiveType(member); - throwInvalidInitializer(structure, type, arg); - } - } else if (arg !== undefined) { - set.call(this, arg); - } - } - }; - const constructor = structure.constructor = createConstructor(structure, { initializer }, env); - const typedArray = structure.typedArray = getTypedArrayClass(member); - const instanceDescriptors = { - $: { get, set }, - dataView: getDataViewDescriptor(structure), - base64: getBase64Descriptor(structure), - typedArray: typedArray && getTypedArrayDescriptor(structure), - valueOf: { value: getValueOf }, - toJSON: { value: convertToJSON }, - delete: { value: getDestructor(env) }, - [Symbol.toPrimitive]: { value: get }, - [COPIER]: { value: getMemoryCopier(byteSize) }, - [NORMALIZER]: { value: normalizeValue }, - }; - const staticDescriptors = { - [COMPAT]: { value: getCompatibleTags(structure) }, - [ALIGN]: { value: align }, - [SIZE]: { value: byteSize }, - }; - return attachDescriptors(constructor, instanceDescriptors, staticDescriptors); -} -function getIntRange(member) { - const { type, bitSize } = member; - const signed = (type === MemberType.Int); - let magBits = (signed) ? bitSize - 1 : bitSize; - if (bitSize <= 32) { - const max = 2 ** magBits - 1; - const min = (signed) ? -(2 ** magBits) : 0; - return { min, max }; - } else { - magBits = BigInt(magBits); - const max = 2n ** magBits - 1n; - const min = (signed) ? -(2n ** magBits) : 0n; - return { min, max }; - } -} - -function getPrimitiveClass({ type, bitSize }) { - if (type === MemberType.Int || type === MemberType.Uint) { - if (bitSize <= 32) { - return Number; - } else { - return BigInt; - } - } else if (type === MemberType.Float) { - return Number; - } else if (type === MemberType.Bool) { - return Boolean; - } -} - -function getPrimitiveType(member) { - const Primitive = getPrimitiveClass(member); - if (Primitive) { - return typeof(Primitive(0)); - } -} - function defineSlice(structure, env) { const { align, @@ -2200,10 +2130,12 @@ function useErrorUnion() { function useErrorSet() { factories$2[StructureType.ErrorSet] = defineErrorSet; + useErrorSetTransform(); } function useEnumeration() { factories$2[StructureType.Enumeration] = defineEnumerationShape; + useEnumerationTransform(); } function useOptional() { @@ -2212,6 +2144,7 @@ function useOptional() { function usePointer() { factories$2[StructureType.Pointer] = definePointer; + useUint(); } function useSlice() { @@ -2504,88 +2437,84 @@ class ObjectCache { } } -function defineErrorSet(structure, env) { +function definePrimitive(structure, env) { const { byteSize, align, instance: { members: [ member ] }, } = structure; - const { get: getIndex } = getDescriptor(member, env); - // get the error descriptor instead of the int/uint descriptor - const { get, set } = getDescriptor({ ...member, type: MemberType.Error, structure }, env); - const expected = [ 'string', 'number' ]; + const { get, set } = getDescriptor(member, env); const propApplier = createPropertyApplier(structure); const initializer = function(arg) { - if (arg && typeof(arg) === 'object') { - try { + if (arg instanceof constructor) { + this[COPIER](arg); + } else { + if (arg && typeof(arg) === 'object') { if (propApplier.call(this, arg) === 0) { - throwInvalidInitializer(structure, expected, arg); - } - } catch (err) { - const { error } = arg; - if (typeof(error) === 'string') { - set.call(this, error); - } else { - throw err; + const type = getPrimitiveType(member); + throwInvalidInitializer(structure, type, arg); } + } else if (arg !== undefined) { + set.call(this, arg); } - } else if (arg !== undefined) { - set.call(this, arg); } }; - const alternateCaster = function(arg) { - if (typeof(arg) === 'number' || typeof(arg) === 'string') { - return constructor[ITEMS][arg]; - } else if (!getDataView(structure, arg, env)) { - throwInvalidInitializer(structure, expected, arg); - } else { - return false; - } - }; - const constructor = structure.constructor = createConstructor(structure, { initializer, alternateCaster }, env); - Object.setPrototypeOf(constructor.prototype, globalErrorSet.prototype); + const constructor = structure.constructor = createConstructor(structure, { initializer }, env); const typedArray = structure.typedArray = getTypedArrayClass(member); - const getMessage = function() { return this.$.message; }; - const toStringTag = function() { return 'Error' }; - const toPrimitive = function(hint) { - if (hint === 'string') { - return Error.prototype.toString.call(this, hint); - } else { - return getIndex.call(this); - } - }; const instanceDescriptors = { $: { get, set }, - message: { get: getMessage }, dataView: getDataViewDescriptor(structure), base64: getBase64Descriptor(structure), typedArray: typedArray && getTypedArrayDescriptor(structure), valueOf: { value: getValueOf }, toJSON: { value: convertToJSON }, delete: { value: getDestructor(env) }, - // ensure that libraries that rely on the string tag for type detection will - // correctly identify the object as an error - [Symbol.toStringTag]: { get: toStringTag }, - [Symbol.toPrimitive]: { value: toPrimitive }, + [Symbol.toPrimitive]: { value: get }, [COPIER]: { value: getMemoryCopier(byteSize) }, - [NORMALIZER]: { value: get }, + [NORMALIZER]: { value: normalizeValue }, }; const staticDescriptors = { + [COMPAT]: { value: getCompatibleTags(structure) }, [ALIGN]: { value: align }, [SIZE]: { value: byteSize }, - [ITEMS]: { value: {} }, }; return attachDescriptors(constructor, instanceDescriptors, staticDescriptors); } -let globalErrorSet; +function getIntRange(member) { + const { type, bitSize } = member; + const signed = (type === MemberType.Int); + let magBits = (signed) ? bitSize - 1 : bitSize; + if (bitSize <= 32) { + const max = 2 ** magBits - 1; + const min = (signed) ? -(2 ** magBits) : 0; + return { min, max }; + } else { + magBits = BigInt(magBits); + const max = 2n ** magBits - 1n; + const min = (signed) ? -(2n ** magBits) : 0n; + return { min, max }; + } +} -function createGlobalErrorSet() { - globalErrorSet = function() {}; - Object.setPrototypeOf(globalErrorSet.prototype, Error.prototype); +function getPrimitiveClass({ type, bitSize }) { + if (type === MemberType.Int || type === MemberType.Uint) { + if (bitSize <= 32) { + return Number; + } else { + return BigInt; + } + } else if (type === MemberType.Float) { + return Number; + } else if (type === MemberType.Bool) { + return Boolean; + } } -function getGlobalErrorSet() { - return globalErrorSet; +function getPrimitiveType(member) { + const Primitive = getPrimitiveClass(member); + if (Primitive) { + return typeof(Primitive(0)); + } } const MemberType = { @@ -2594,15 +2523,13 @@ const MemberType = { Int: 2, Uint: 3, Float: 4, - EnumerationItem: 5, - Error: 6, - Object: 7, - Type: 8, - Comptime: 9, - Static: 10, - Literal: 11, - Null: 12, - Undefined: 13, + Object: 5, + Type: 6, + Comptime: 7, + Static: 8, + Literal: 9, + Null: 10, + Undefined: 11, }; function isReadOnly(type) { @@ -2638,14 +2565,6 @@ function useFloat() { factories$1[MemberType.Float] = getFloatDescriptor; } -function useEnumerationItem() { - factories$1[MemberType.EnumerationItem] = getEnumerationItemDescriptor; -} - -function useError() { - factories$1[MemberType.Error] = getErrorDescriptor; -} - function useObject() { factories$1[MemberType.Object] = getObjectDescriptor; } @@ -2674,6 +2593,16 @@ function useUndefined() { factories$1[MemberType.Undefined] = getUndefinedDescriptor; } +const transformers = {}; + +function useEnumerationTransform() { + transformers[StructureType.Enumeration] = transformEnumerationDescriptor; +} + +function useErrorSetTransform() { + transformers[StructureType.ErrorSet] = transformErrorSetDescriptor; +} + function isByteAligned({ bitOffset, bitSize, byteSize }) { return byteSize !== undefined || (!(bitOffset & 0x07) && !(bitSize & 0x07)) || bitSize === 0; } @@ -2683,6 +2612,12 @@ function getDescriptor(member, env) { return f(member, env); } +function transformDescriptor(descriptor, member) { + const { structure } = member; + const t = transformers[structure?.type]; + return (t) ? t(descriptor, structure) : descriptor; +} + function getVoidDescriptor(member, env) { const { runtimeSafety } = env; return { @@ -2721,12 +2656,14 @@ function getBoolDescriptor(member, env) { function getIntDescriptor(member, env) { const getDataViewAccessor = addRuntimeCheck(env, getNumericAccessor); - return getDescriptorUsing(member, env, getDataViewAccessor) + const descriptor = getDescriptorUsing(member, env, getDataViewAccessor); + return transformDescriptor(descriptor, member); } function getUintDescriptor(member, env) { const getDataViewAccessor = addRuntimeCheck(env, getNumericAccessor); - return getDescriptorUsing(member, env, getDataViewAccessor) + const descriptor = getDescriptorUsing(member, env, getDataViewAccessor); + return transformDescriptor(descriptor, member); } function addRuntimeCheck(env, getDataViewAccessor) { @@ -2752,92 +2689,83 @@ function getFloatDescriptor(member, env) { return getDescriptorUsing(member, env, getNumericAccessor) } -function getValueDescriptor(member, env) { - // enum can be int or uint--need the type from the structure - const { type, structure } = member.structure.instance.members[0]; - // combine that with the offset/size - const valueMember = { ...member, type, structure }; - return getDescriptor(valueMember, env); -} - -function getEnumerationItemDescriptor(member, env) { - const { structure } = member; - const { get: getValue, set: setValue } = getValueDescriptor(member, env); +function transformEnumerationDescriptor(int, structure) { const findEnum = function(value) { const { constructor } = structure; // the enumeration constructor returns the object for the int value - const item = (value instanceof constructor) ? value : constructor(value); + const item = constructor(value); if (!item) { throwEnumExpected(structure, value); } return item }; return { - get: (getValue.length === 0) - ? function getEnum() { - const value = getValue.call(this); + get: (int.get.length === 0) + ? function getEnum(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } return findEnum(value); } : function getEnumElement(index) { - const value = getValue.call(this, index); + const value = int.get.call(this, index); return findEnum(value); }, - set: (setValue.length === 1) - ? function setEnum(value) { - // call Symbol.toPrimitive directly as enum can be bigint or number - const item = findEnum(value); - setValue.call(this, item[Symbol.toPrimitive]()); + set: (int.set.length === 1) + ? function setEnum(value, hint) { + if (hint !== 'number') { + const item = findEnum(value); + // call Symbol.toPrimitive directly as enum can be bigint or number + value = item[Symbol.toPrimitive](); + } + int.set.call(this, value); } : function setEnumElement(index, value) { const item = findEnum(value); - setValue.call(this, index, item[Symbol.toPrimitive]()); + int.set.call(this, index, item[Symbol.toPrimitive]()); }, }; } -function getErrorDescriptor(member, env) { - const { structure } = member; - const { name } = structure; - const { get: getValue, set: setValue } = getValueDescriptor(member, env); - const acceptAny = name === 'anyerror'; - const globalErrorSet = getGlobalErrorSet(); - const findError = function(value, allowZero = false) { +function transformErrorSetDescriptor(int, structure) { + const findError = function(value) { const { constructor } = structure; - let item; - if (value === 0 && allowZero) { - return; - } else if (value instanceof Error) { - if (value instanceof (acceptAny ? globalErrorSet : constructor)) { - item = value; - } else { + const item = constructor(value); + if (!item) { + if (value instanceof Error) { throwNotInErrorSet(structure); - } - } else { - item = acceptAny ? globalErrorSet[value] : constructor(value); - if (!item) { + } else { throwErrorExpected(structure, value); - } - } + } + } return item }; return { - get: (getValue.length === 0) - ? function getError(allowZero) { - const value = getValue.call(this); - return findError(value, allowZero); + get: (int.get.length === 0) + ? function getError(hint) { + const value = int.get.call(this); + if (hint === 'number') { + return value; + } + return findError(value); } : function getErrorElement(index) { - const value = getValue.call(this, index); - return findError(value, false); + const value = int.get.call(this, index); + return findError(value); }, - set: (setValue.length === 1) - ? function setError(value, allowZero) { - const item = findError(value, allowZero); - setValue.call(this, Number(item ?? 0)); + set: (int.set.length === 1) + ? function setError(value, hint) { + if (hint !== 'number') { + const item = findError(value); + value = Number(item); + } + int.set.call(this, value); } : function setError(index, value) { - const item = findError(value, false); - setValue.call(this, index, Number(item)); + const item = findError(value); + value = Number(item); + int.set.call(this, index, value); }, }; } @@ -3009,6 +2937,126 @@ function getDescriptorUsing(member, env, getDataViewAccessor) { } } +let currentGlobalSet; +let currentErrorClass; + +function defineErrorSet(structure, env) { + const { + name, + byteSize, + align, + instance: { members: [ member ] }, + } = structure; + if (!currentErrorClass) { + currentErrorClass = class ZigError extends ZigErrorBase {}; + currentGlobalSet = defineErrorSet({ ...structure, name: 'anyerror' }, env); + } + if (currentGlobalSet && name === 'anyerror') { + structure.constructor = currentGlobalSet; + structure.typedArray = getTypedArrayClass(member); + return currentGlobalSet; + } + const errorClass = currentErrorClass; + const { get, set } = getDescriptor(member, env); + const expected = [ 'string', 'number' ]; + const propApplier = createPropertyApplier(structure); + const initializer = function(arg) { + if (arg instanceof constructor[CLASS]) { + set.call(this, arg); + } else if (arg && typeof(arg) === 'object' && !isErrorJSON(arg)) { + if (propApplier.call(this, arg) === 0) { + throwInvalidInitializer(structure, expected, arg); + } + } else if (arg !== undefined) { + set.call(this, arg); + } + }; + const alternateCaster = function(arg) { + if (typeof(arg) === 'number' || typeof(arg) === 'string') { + return constructor[arg]; + } else if (arg instanceof constructor[CLASS]) { + return constructor[Number(arg)]; + } else if (isErrorJSON(arg)) { + return constructor[`Error: ${arg.error}`]; + } else if (!getDataView(structure, arg, env)) { + throwInvalidInitializer(structure, expected, arg); + } else { + return false; + } + }; + // items are inserted when static members get attached in static.js + const constructor = structure.constructor = createConstructor(structure, { initializer, alternateCaster }, env); + const typedArray = structure.typedArray = getTypedArrayClass(member); + const instanceDescriptors = { + $: { get, set }, + dataView: getDataViewDescriptor(structure), + base64: getBase64Descriptor(structure), + typedArray: typedArray && getTypedArrayDescriptor(structure), + valueOf: { value: getValueOf }, + toJSON: { value: convertToJSON }, + delete: { value: getDestructor(env) }, + [COPIER]: { value: getMemoryCopier(byteSize) }, + [NORMALIZER]: { value: get }, + }; + const staticDescriptors = { + [ALIGN]: { value: align }, + [SIZE]: { value: byteSize }, + [CLASS]: { value: errorClass }, + // the PROPS array is normally set in static.js; it needs to be set here for anyerror + // so we can add names to it as error sets are defined + [PROPS]: (name === 'anyerror') ? { value: [] } : undefined, + }; + return attachDescriptors(constructor, instanceDescriptors, staticDescriptors); +} +function appendErrorSet(errorSet, name, es) { + // our Zig export code places error set instance into the static template, which we can't + // use since all errors need to have the same parent class; here we get the error number + // and create the actual error object if hasn't been created already for an earlier set + const number = es[GETTER]('number'); + let error = currentGlobalSet[number]; + if (!error) { + const errorClass = errorSet[CLASS]; + error = new errorClass(name, number); + } + const string = String(error); + const descriptors = { + [number]: { value: error }, + [string]: { value: error }, + [name]: { value: error }, + }; + defineProperties(errorSet, descriptors); + defineProperties(currentGlobalSet, descriptors); + // add name to prop list + currentGlobalSet[PROPS].push(name); +} + +function resetGlobalErrorSet() { + currentErrorClass = currentGlobalSet = undefined; +} + +function isErrorJSON(arg) { + return typeof(arg) === 'object' && typeof(arg.error) === 'string' && Object.keys(arg).length === 1 ; +} + +class ZigErrorBase extends Error { + constructor(name, number) { + super(deanimalizeErrorName(name)); + this.number = number; + } + + [Symbol.toPrimitive](hint) { + if (hint === 'string') { + return Error.prototype.toString.call(this, hint); + } else { + return this.number; + } + } + + toJSON() { + return { error: this.message }; + } +} + function throwNoInitializer(structure) { const { name } = structure; throw new TypeError(`An initializer must be provided to the constructor of ${name}, even when the intended value is undefined`); @@ -3052,7 +3100,10 @@ function throwEnumExpected(structure, arg) { function throwErrorExpected(structure, arg) { const { name } = structure; const type = typeof(arg); - if (type === 'string' || type === 'number') { + if (type === 'string' || type === 'number' || isErrorJSON(arg)) { + if (isErrorJSON(arg)) { + arg = `{ error: ${JSON.stringify(arg.error)} }`; + } throw new TypeError(`Error ${type} does not corresponds to any error in error set ${name}: ${arg}`); } else { throw new TypeError(`Error of the type ${name} expected, received ${arg}`); @@ -3098,9 +3149,13 @@ function throwInvalidArrayInitializer(structure, arg, shapeless = false) { const acceptable = []; const primitive = getPrimitiveType(member); if (primitive) { - acceptable.push(`array of ${primitive}s`); - } else if (member.type === MemberType.EnumerationItem) { - acceptable.push(`array of enum items`); + let object; + switch (member.structure?.type) { + case StructureType.Enumeration: object = 'enum item'; break; + case StructureType.ErrorSet: object = 'error'; break; + default: object = primitive; + } + acceptable.push(`array of ${object}s`); } else { acceptable.push(`array of objects`); } @@ -4076,9 +4131,6 @@ function addStaticMembers(structure, env) { constructor, static: { members, template }, } = structure; - if (members.length === 0) { - return; - } const descriptors = {}; for (const member of members) { descriptors[member.name] = getDescriptor(member, env); @@ -4089,62 +4141,18 @@ function addStaticMembers(structure, env) { ...descriptors, [Symbol.iterator]: { value: getStructIterator }, // static variables are objects stored in the static template's slots - [SLOTS]: { value: template[SLOTS] }, - [PROPS]: { value: members.map(m => m.name) }, + [SLOTS]: template ? { value: template[SLOTS] } : undefined, + // anyerror would have props already + [PROPS]: !constructor[PROPS] ? { value: members.map(m => m.name) } : undefined, [NORMALIZER]: { value: normalizeStruct }, }); if (type === StructureType.Enumeration) { - const enums = constructor[ITEMS]; for (const { name, slot } of members) { - if (name !== undefined) { - // place item in hash to facilitate lookup, - const item = constructor[SLOTS][slot]; - if (item instanceof constructor) { - // attach name to item so tagged union code can quickly find it - defineProperties(item, { [NAME]: { value: name } }); - const index = item[Symbol.toPrimitive](); - enums[index] = enums[name] = item; - } - } else { - // non-exhaustive enum - defineProperties(constructor, { [MORE]: { value: true } }); - } + appendEnumeration(constructor, name, constructor[SLOTS][slot]); } } else if (type === StructureType.ErrorSet) { - const allErrors = getGlobalErrorSet(); - const errors = constructor[ITEMS]; for (const { name, slot } of members) { - let error = constructor[SLOTS][slot]; - const index = Number(error); - const previous = allErrors[index]; - if (previous) { - if (!(previous instanceof constructor)) { - // error already exists in a previously defined set - // see if we should make that set a subclass or superclass of this one - const otherSet = previous.constructor; - const otherErrors = Object.values(otherSet[SLOTS]); - const errorIndices = Object.values(constructor[SLOTS]).map(e => Number(e)); - if (otherErrors.every(e => errorIndices.includes(Number(e)))) { - // this set contains the all errors of the other one, so it's a superclass - Object.setPrototypeOf(otherSet.prototype, constructor.prototype); - } else { - // make this set a subclass of the other - Object.setPrototypeOf(constructor.prototype, otherSet.prototype); - for (const otherError of otherErrors) { - if (errorIndices.includes(Number(otherError))) { - // this set should be this error object's class - Object.setPrototypeOf(otherError, constructor.prototype); - } - } - } - } - error = constructor[SLOTS][slot] = previous; - } else { - // set error message (overriding prototype) and add to hash - defineProperties(error, { message: { value: deanimalizeErrorName(name) } }); - allErrors[index] = allErrors[error.message] = allErrors[`${error}`] = error; - } - errors[index] = errors[error.message] = errors[`${error}`] = error; + appendErrorSet(constructor, name, constructor[SLOTS][slot]); } } } @@ -4411,7 +4419,7 @@ class Environment { return placeholder.structure; } }; - createGlobalErrorSet(); + resetGlobalErrorSet(); const objectPlaceholders = new Map(); for (const structure of structures) { // recreate the actual template using the provided placeholder @@ -5316,4 +5324,4 @@ function createEnvironment(source) { } /* RUNTIME-ONLY-END */ -export { createEnvironment, useArgStruct, useArray, useBareUnion, useBool, useComptime, useEnumeration, useEnumerationItem, useError, useErrorSet, useErrorUnion, useExtendedBool, useExtendedFloat, useExtendedInt, useExtendedUint, useExternStruct, useExternUnion, useFloat, useInt, useLiteral, useNull, useObject, useOpaque, useOptional, usePackedStruct, usePointer, usePrimitive, useSlice, useStatic, useStruct, useTaggedUnion, useType, useUint, useUndefined, useVector, useVoid }; +export { createEnvironment, useArgStruct, useArray, useBareUnion, useBool, useComptime, useEnumeration, useErrorSet, useErrorUnion, useExtendedBool, useExtendedFloat, useExtendedInt, useExtendedUint, useExternStruct, useExternUnion, useFloat, useInt, useLiteral, useNull, useObject, useOpaque, useOptional, usePackedStruct, usePointer, usePrimitive, useSlice, useStatic, useStruct, useTaggedUnion, useType, useUint, useUndefined, useVector, useVoid }; diff --git a/zigar-runtime/src/error-union.js b/zigar-runtime/src/error-union.js index 4d96988a..e2f8475f 100644 --- a/zigar-runtime/src/error-union.js +++ b/zigar-runtime/src/error-union.js @@ -28,7 +28,7 @@ export function defineErrorUnion(structure, env) { } }; const isValueVoid = members[0].type === MemberType.Void; - const TargetError = members[1].structure.constructor[CLASS]; + const errorSet = members[1].structure.constructor; const isChildActive = function() { return !getError.call(this, 'number'); }; @@ -46,7 +46,7 @@ export function defineErrorUnion(structure, env) { this[POINTER_VISITOR](copyPointer, { vivificate: true, source: arg }); } } - } else if (arg instanceof TargetError) { + } else if (arg instanceof errorSet[CLASS] && errorSet(arg)) { setError.call(this, arg); clearValue.call(this); } else if (arg !== undefined || isValueVoid) {