UNPKG

enhance-data-view

Version:

Reactive DataView extension with chainable API for type-safe binary data manipulation.

1,511 lines 53.8 kB
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
    typeof define === 'function' && define.amd ? define(['exports'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.EDataView = {}));
})(this, (function (exports) { 'use strict';

    /** Unique symbol identifying type definition objects */
    const TypeDefinitionSymbol = Symbol("TYPE_DEFINITION");
    /**
     * Type guard for TypeDefinition objects
     * @param test - Value to check
     * @returns Whether the value is a valid TypeDefinition
     */
    function isTypeDefinition(test) {
        if (typeof test !== "object" || test === null) {
            return false;
        }
        if (test.isTypeDefinition === TypeDefinitionSymbol) {
            return true;
        }
        return false;
    }
    /**
     * Reads typed data from DataView
     * @param view - Source DataView
     * @param type - Type definition
     * @param offset - Read offset in bytes
     * @param littleEndian - Byte order (default: big-endian)
     * @returns Decoded value
     * @example
     * const num = get(view, INT, 0x10, true);
     */
    function get(view, type, offset, littleEndian) {
        return type.getter({
            view,
            offset,
            littleEndian
        });
    }
    /**
     * Reads array of typed data from DataView
     * @param view - Source DataView
     * @param type - Element type definition
     * @param offset - Starting offset in bytes
     * @param length - Number of elements to read
     * @param littleEndian - Byte order (default: big-endian)
     * @returns Array of decoded values
     * @example
     * const coords = getArray(view, FLOAT, 0x20, 3);
     */
    function getArray(view, type, offset, length, littleEndian) {
        const result = new Array(length);
        const size = type.size;
        for (let i = 0; i < length; i++) {
            result[i] = type.getter({
                view,
                offset: offset + size * i,
                littleEndian
            });
        }
        return result;
    }
    /**
     * Writes typed data to DataView
     * @param view - Target DataView
     * @param type - Type definition
     * @param offset - Write offset in bytes
     * @param value - Value to encode
     * @param littleEndian - Byte order (default: big-endian)
     * @example
     * set(view, FLOAT, 0x08, 3.14159);
     */
    function set(view, type, offset, value, littleEndian) {
        return type.setter({
            view,
            offset,
            littleEndian
        }, value);
    }
    /**
     * Writes array of typed data to DataView
     * @param view - Target DataView
     * @param type - Element type definition
     * @param offset - Starting offset in bytes
     * @param array - Values to encode
     * @param littleEndian - Byte order (default: big-endian)
     * @example
     * setArray(view, INT, 0x30, [1, 2, 3]);
     */
    function setArray(view, type, offset, array, littleEndian) {
        const length = array.length;
        const size = type.size;
        for (let i = 0; i < length; i++) {
            type.setter({
                view,
                offset: offset + size * i,
                littleEndian
            }, array[i]);
        }
    }
    /**
     * Converts DataView region to reactive object
     * @param view - Source DataView
     * @param type - Type definition
     * @param offset - Byte offset or offset getter
     * @param littleEndian - Byte order (default: big-endian)
     * @returns Reactive proxy object
     * @remarks Property accesses trigger automatic get/set operations
     * @example
     * const player = reactive(view, PlayerStruct, 0x100);
     * player.health = 80; // Automatically writes to DataView
     */
    function reactive(view, type, offset, littleEndian) {
        const baseOffset = typeof offset === "function" ? offset : () => offset;
        return type.reactive({
            view,
            littleEndian,
            localOffset: 0,
            baseOffset,
            cacheGetter: () => void 0
        });
    }
    /**
     * Creates reactive reference for value types
     * @param view - Source DataView
     * @param type - Type definition
     * @param offset - Byte offset or offset getter
     * @param littleEndian - Byte order (default: big-endian)
     * @returns Reactive reference object
     * @remarks Optimized for primitive/value type access
     * @example
     * const hp = ref(view, UINT, 0x104);
     * console.log(hp.value); // Reads from DataView
     * hp.value = 100;       // Writes to DataView
     */
    function ref(view, type, offset, littleEndian) {
        const baseOffset = typeof offset === "function" ? offset : () => offset;
        let cachedGetter;
        return {
            [OperationRawSymbol]() {
                return {
                    value: type.getter({
                        view,
                        offset: baseOffset(),
                        littleEndian
                    })
                };
            },
            get value() {
                if (cachedGetter) {
                    return cachedGetter();
                }
                return type.reactive({
                    view,
                    littleEndian,
                    localOffset: 0,
                    baseOffset,
                    cacheGetter: (getter) => cachedGetter = getter
                });
            },
            set value(value) {
                type.setter({
                    view,
                    offset: baseOffset(),
                    littleEndian
                }, value);
            }
        };
    }
    /**
     * Symbol for retrieving raw values from reactive objects
     * @remarks Reactive objects must implement this symbol
     */
    const OperationRawSymbol = Symbol("TYPE_DEFINITION_RAW");
    /**
     * Extracts raw value from reactive objects
     * @param value - Reactive proxy or raw value
     * @returns Underlying non-reactive value
     * @example
     * const raw = toRaw(reactiveObj);
     */
    function toRaw(value) {
        const target = value;
        if (typeof target === "object" && target !== null) {
            const getter = target[OperationRawSymbol];
            if (getter) {
                return getter();
            }
        }
        return target;
    }
    /**
     * Creates reference for nested reactive property
     * @param target - Reactive source object
     * @param key - Property key to reference
     * @returns Reactive reference to specified property
     * @example
     * const hpRef = toRef(player, 'health');
     */
    function toRef(target, key) {
        return {
            [OperationRawSymbol]() {
                return {
                    value: target[key]
                };
            },
            get value() {
                return target[key];
            },
            set value(value) {
                target[key] = value;
            }
        };
    }

    /**
     * Creates a configurable primitive type definition
     * @param name - Initial type name (optional)
     * @returns Mutable primitive type definition
     * @remarks
     * - Start with this to define custom binary types
     * - Chain configuration methods before freezing
     * @example
     * const Float32 = definePrimitive<number>('float32')
     *   .setSize(4)
     *   .setGetter(ctx => ctx.view.getFloat32(ctx.offset, ctx.littleEndian))
     *   .setSetter((ctx, value) => ctx.view.setFloat32(ctx.offset, value, ctx.littleEndian))
     *   .freeze();
     */
    function definePrimitive(name) {
        // Configuration state
        let _name = name;
        let _size;
        let _align;
        let _getter;
        let _setter;
        let _reactive;
        const setName = (name) => {
            _name = name;
            return typeDefinition;
        };
        const setSize = (size) => {
            _size = size;
            return typeDefinition;
        };
        const setAlign = (align) => {
            _align = align;
            return typeDefinition;
        };
        const setGetter = (getter) => {
            _getter = getter;
            return typeDefinition;
        };
        const setSetter = (setter) => {
            _setter = setter;
            return typeDefinition;
        };
        const setReactive = (reactive) => {
            _reactive = reactive;
            return typeDefinition;
        };
        const freeze = () => {
            const newDefinition = clone();
            return Object.freeze({
                isTypeDefinition: TypeDefinitionSymbol,
                name: newDefinition.name,
                size: newDefinition.size,
                align: newDefinition.align,
                getter: newDefinition.getter,
                setter: newDefinition.setter,
                reactive: newDefinition.reactive,
                clone: newDefinition.clone
            });
        };
        const clone = (name) => definePrimitive(name ?? _name)
            .setSize(_size)
            .setAlign(_align)
            .setGetter(_getter)
            .setSetter(_setter)
            .setReactive(_reactive);
        // Default operations (throw if not configured)
        const getter = () => {
            throw new Error(`Getter not implemented for type '${_name || "unknown"}'`);
        };
        const setter = () => {
            throw new Error(`Setter not implemented for type '${_name || "unknown"}'`);
        };
        // Default reactive implementation
        const reactive = ({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
            const getter = () => typeDefinition.getter({
                view,
                offset: localOffset + baseOffset(),
                littleEndian,
            });
            cacheGetter(getter);
            return getter();
        };
        // Main definition object with getters
        const typeDefinition = {
            isTypeDefinition: TypeDefinitionSymbol,
            get name() {
                return _name ?? "unknown";
            },
            get size() {
                return Math.max(_size ?? 0, 0);
            },
            get align() {
                return Math.max(_align ?? _size ?? 1, 1);
            },
            get getter() {
                return _getter ?? getter;
            },
            get setter() {
                return _setter ?? setter;
            },
            get reactive() {
                return _reactive ?? reactive;
            },
            setName,
            setSize,
            setAlign,
            setGetter,
            setSetter,
            setReactive,
            freeze,
            clone
        };
        return typeDefinition;
    }

    /** Unique symbol identifying property definitions */
    const PropertyDefinitionSymbol = Symbol("PROPERTY_DEFINITION");
    /**
     * Creates a property definition
     * @param type - Property type definition
     * @param options - Configuration options
     * @returns Property definition object
     * @example
     * defineProperty(Uint32, { align: 8, offset: 0x10 })
     */
    function defineProperty(type, options) {
        return {
            isPropertyDefinition: PropertyDefinitionSymbol,
            type,
            align: options?.align,
            offset: options?.offset,
            order: options?.order
        };
    }
    /** Type guard for property definitions */
    function isPropertyDefinition(test) {
        if (typeof test !== "object" || test === null) {
            return false;
        }
        if (test.isPropertyDefinition === PropertyDefinitionSymbol) {
            return true;
        }
        return false;
    }
    /** Unique symbol identifying padding definitions */
    const PaddingDefinitionSymbol = Symbol("STRUCT_DEFINITION");
    /**
     * Creates a padding definition
     * @param typeOrSize - Type definition or byte size
     * @param options - Configuration options
     * @returns Padding definition object
     * @example
     * // 8-byte padding with 4-byte alignment
     * definePadding(8, { align: 4 })
     */
    function definePadding(typeOrSize, options) {
        return typeof typeOrSize === "number" ? {
            isPaddingDefinition: PaddingDefinitionSymbol,
            size: typeOrSize,
            align: options?.align ?? 1,
            offset: options?.offset,
            order: options?.order
        } : {
            isPaddingDefinition: PaddingDefinitionSymbol,
            size: typeOrSize.size,
            align: options?.align ?? typeOrSize.align,
            offset: options?.offset,
            order: options?.order
        };
    }
    /** Type guard for padding definitions */
    function isPaddingDefinition(test) {
        if (typeof test !== "object" || test === null) {
            return false;
        }
        if (test.isPaddingDefinition === PaddingDefinitionSymbol) {
            return true;
        }
        return false;
    }
    /**
     * Struct definition implementation
     * @param param0 - Options object or name
     * @param param1 - Optional name
     * @returns Struct definition instance
     */
    function defineStruct(param0, param1) {
        let _name;
        let _size;
        let _sizeCalc = 0;
        let _align;
        let _alignCalc = 1;
        let _keys = new Array();
        let _properties = new Map();
        let _propertyList = new Array();
        let _recordList = new Array();
        const setName = (name) => {
            _name = name;
            return typeDefinition;
        };
        const setSize = (size) => {
            _size = size;
            return typeDefinition;
        };
        const setAlign = (align) => {
            _align = align;
            return typeDefinition;
        };
        const updateLayout = () => {
            const keys = new Array();
            const properties = new Map();
            const propertyList = new Array();
            let maxAlign = 1;
            let maxOffset = 0;
            let offset = 0;
            for (const record of _recordList) {
                // Get size, align
                let size;
                let align;
                if (record.padding) {
                    size = record.size;
                    align = Math.max(record.align, 1);
                }
                else {
                    size = record.type.size;
                    align = Math.max(record.align ?? record.type.align, 1);
                    // Record to map
                    keys.push(record.key);
                    properties.set(record.key, record);
                    propertyList.push(record);
                }
                // Static offset
                const offsetStatic = record.offsetStatic;
                if (typeof offsetStatic === "number") {
                    record.offset = offsetStatic;
                    offset = offsetStatic + size;
                }
                else {
                    // Padding calculation
                    const padding = (align - (offset % align)) % align;
                    // Update
                    offset += padding;
                    record.offset = offset;
                    offset += size;
                }
                maxAlign = Math.max(maxAlign, align);
                maxOffset = Math.max(maxOffset, offset);
            }
            // End padding
            const endPadding = (maxAlign - (maxOffset % maxAlign)) % maxAlign;
            // Update
            _alignCalc = maxAlign;
            _sizeCalc = maxOffset + endPadding;
            _keys = keys;
            _properties = properties;
            _propertyList = propertyList;
            return typeDefinition;
        };
        const propertyToRecord = (key, definition) => ({
            key,
            type: definition.type,
            align: definition.align,
            offset: 0,
            offsetStatic: definition.offset
        });
        const paddingToRecord = (key, definition) => ({
            key,
            size: definition.size,
            align: definition.align,
            offset: 0,
            offsetStatic: definition.offset,
            padding: true
        });
        const setProperties = (options) => {
            const orderList = [];
            const list = [];
            for (const [key, option] of Object.entries(options)) {
                // Pure type
                if (isTypeDefinition(option)) {
                    list.push({
                        key,
                        type: option,
                        offset: 0
                    });
                    continue;
                }
                let property;
                if (isPropertyDefinition(option)) {
                    property = propertyToRecord(key, option);
                }
                else if (isPaddingDefinition(option)) {
                    property = paddingToRecord(key, option);
                }
                else {
                    throw new Error(`[${typeDefinition.name}] Unknown option type.`);
                }
                if (typeof option.order === "number") {
                    orderList.push({
                        order: option.order,
                        property,
                    });
                }
                else {
                    list.push(property);
                }
            }
            // Sort by order
            orderList.sort((a, b) => a.order - b.order);
            // Update
            _recordList = orderList.map(x => x.property).concat(list);
            return updateLayout();
        };
        const getProperties = () => {
            let order = 0;
            const options = {};
            for (const record of _recordList) {
                let option;
                const definitionOption = {
                    align: record.align,
                    offset: record.offsetStatic,
                    order: order++
                };
                if (record.padding) {
                    option = definePadding(record.size, definitionOption);
                }
                else {
                    option = defineProperty(record.type, definitionOption);
                }
                options[record.key] = option;
            }
            return options;
        };
        const addRecord = (property) => {
            // Duplicate Check
            if (_recordList.find(x => x.key === property.key)) {
                const keyString = typeof property.key === "symbol" ? `Symbol(${property.key.description || ""})` : property.key;
                throw new Error(`[${typeDefinition.name}] Repeat adding records with key: ${keyString}`);
            }
            // Update
            _recordList.push(property);
            return updateLayout();
        };
        const addProperty = (key, type, options) => {
            return addRecord(propertyToRecord(key, defineProperty(type, options)));
        };
        const addPadding = (key, typeOrSize, options) => {
            return addRecord(paddingToRecord(key, definePadding(typeOrSize, options)));
        };
        const updateRecord = (property) => {
            const index = _recordList.findIndex(x => x.key === property.key);
            if (index < 0) {
                const keyString = typeof property.key === "symbol" ? `Symbol(${property.key.description || ""})` : property.key;
                throw new Error(`[${typeDefinition.name}] There is no record with key: ${keyString}`);
            }
            // Update
            _recordList.splice(index, 1, property);
            return updateLayout();
        };
        const updateProperty = (key, type, options) => {
            return updateRecord(propertyToRecord(key, defineProperty(type, options)));
        };
        const updatePadding = (key, typeOrSize, options) => {
            return updateRecord(paddingToRecord(key, definePadding(typeOrSize, options)));
        };
        const remove = (key) => {
            const index = _recordList.findIndex(x => x.key === key);
            if (index < 0) {
                const keyString = typeof key === "symbol" ? `Symbol(${key.description || ""})` : key;
                throw new Error(`[${typeDefinition.name}] There is no record with key: ${keyString}`);
            }
            // Delete
            _recordList.splice(index, 1);
            return updateLayout();
        };
        const freeze = () => {
            const newDefinition = clone();
            return Object.freeze({
                isTypeDefinition: TypeDefinitionSymbol,
                name: newDefinition.name,
                size: newDefinition.size,
                align: newDefinition.align,
                keys: Object.freeze(newDefinition.keys),
                properties: Object.freeze(newDefinition.properties),
                propertyList: Object.freeze(newDefinition.propertyList),
                recordList: Object.freeze(newDefinition.recordList),
                getter: newDefinition.getter,
                setter: newDefinition.setter,
                reactive: newDefinition.reactive,
                clone: newDefinition.clone
            });
        };
        const clone = (name) => defineStruct(getProperties(), name ?? _name)
            .setSize(_size)
            .setAlign(_align);
        const getter = ({ view, offset, littleEndian }) => {
            const structure = {};
            for (const property of _propertyList) {
                structure[property.key] = property.type.getter({
                    view,
                    offset: offset + property.offset,
                    littleEndian: littleEndian,
                });
            }
            return structure;
        };
        const setter = ({ view, offset, littleEndian }, value) => {
            for (const property of _propertyList) {
                property.type.setter({
                    view,
                    offset: offset + property.offset,
                    littleEndian: littleEndian,
                }, value[property.key]);
            }
        };
        const reactive = ({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
            const proxyToRaw = () => typeDefinition.getter({
                view,
                offset: baseOffset() + localOffset,
                littleEndian
            });
            const internal = new Map([
                [OperationRawSymbol, proxyToRaw]
            ]);
            // Prop getter
            const getterMap = new Map();
            const get = (target, key) => {
                let getter = getterMap.get(key);
                if (getter) {
                    return getter();
                }
                const property = _properties.get(key);
                if (property) {
                    const context = {
                        view,
                        littleEndian,
                        localOffset: localOffset + property.offset,
                        baseOffset,
                        cacheGetter: getter => getterMap.set(property.key, getter)
                    };
                    getter = () => property.type.reactive(context);
                    getterMap.set(property.key, getter);
                    return getter();
                }
                else {
                    return internal.get(key);
                }
            };
            // Prop setter
            const set = (target, key, value) => {
                const property = _properties.get(key);
                if (property) {
                    property.type.setter({
                        view,
                        offset: baseOffset() + localOffset + property.offset,
                        littleEndian
                    }, value);
                    return true;
                }
                else {
                    return false;
                }
            };
            const has = (target, key) => {
                return _properties.has(key);
            };
            const ownKeys = () => {
                return _keys;
            };
            const defineProperty = () => false;
            const deleteProperty = () => false;
            const proxy = new Proxy({}, {
                get,
                set,
                has,
                ownKeys,
                defineProperty,
                deleteProperty
            });
            cacheGetter(() => proxy);
            return proxy;
        };
        const typeDefinition = {
            isTypeDefinition: TypeDefinitionSymbol,
            get name() {
                return _name ?? `struct{${_keys.length}}`;
            },
            get size() {
                return Math.max(_size ?? _sizeCalc, 0);
            },
            get align() {
                return Math.max(_align ?? _alignCalc, 1);
            },
            get keys() {
                return _keys;
            },
            get properties() {
                return _properties;
            },
            get propertyList() {
                return _propertyList;
            },
            get recordList() {
                return _recordList;
            },
            getter,
            setter,
            reactive,
            setName,
            setSize,
            setAlign,
            setProperties,
            addProperty,
            addPadding,
            updateProperty,
            updatePadding,
            remove,
            freeze,
            clone
        };
        if (typeof param0 === "object") {
            setProperties(param0);
            setName(param1);
        }
        else {
            setName(param0);
        }
        return typeDefinition;
    }

    const UNKNOWN = definePrimitive("UNKNOWN").freeze();
    ////////// INT //////////
    /**
     * Signed 8-bit integer type descriptor
     *
     * @remarks
     * - Size: 1 byte
     * - Range: -128 to 127
     * - Corresponds to `DataView.getInt8()` and `DataView.setInt8()`
     */
    const INT_8 = definePrimitive("INT_8")
        .setSize(1)
        .setGetter(({ view, offset }) => view.getInt8(offset))
        .setSetter(({ view, offset }, value) => view.setInt8(offset, value))
        .setReactive(({ view, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getInt8(localOffset + baseOffset());
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /**
     * Signed 16-bit integer type descriptor
     *
     * @remarks
     * - Size: 2 bytes
     * - Range: -32,768 to 32,767
     * - Endian-sensitive: Uses littleEndian parameter
     * - Corresponds to `DataView.getInt16()` and `DataView.setInt16()`
     */
    const INT_16 = definePrimitive("INT_16")
        .setSize(2)
        .setGetter(({ view, offset, littleEndian }) => view.getInt16(offset, littleEndian))
        .setSetter(({ view, offset, littleEndian }, value) => view.setInt16(offset, value, littleEndian))
        .setReactive(({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getInt16(localOffset + baseOffset(), littleEndian);
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /** Alias for {@link INT_16} */
    const SHORT = INT_16.clone("SHORT").freeze();
    /**
     * Signed 32-bit integer type descriptor
     *
     * @remarks
     * - Size: 4 bytes
     * - Range: -2,147,483,648 to 2,147,483,647
     * - Endian-sensitive: Uses littleEndian parameter
     * - Corresponds to `DataView.getInt32()` and `DataView.setInt32()`
     */
    const INT_32 = definePrimitive("INT_32")
        .setSize(4)
        .setGetter(({ view, offset, littleEndian }) => view.getInt32(offset, littleEndian))
        .setSetter(({ view, offset, littleEndian }, value) => view.setInt32(offset, value, littleEndian))
        .setReactive(({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getInt32(localOffset + baseOffset(), littleEndian);
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /** Alias for {@link INT_32} */
    const INT = INT_32.clone("INT").freeze();
    /**
     * Signed 64-bit integer type descriptor
     *
     * @remarks
     * - Size: 8 bytes
     * - Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
     * - Uses JavaScript BigInt type
     * - Endian-sensitive: Uses littleEndian parameter
     * - Corresponds to `DataView.getBigInt64()` and `DataView.setBigInt64()`
     */
    const INT_64 = definePrimitive("INT_64")
        .setSize(8)
        .setGetter(({ view, offset, littleEndian }) => view.getBigInt64(offset, littleEndian))
        .setSetter(({ view, offset, littleEndian }, value) => view.setBigInt64(offset, value, littleEndian))
        .setReactive(({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getBigInt64(localOffset + baseOffset(), littleEndian);
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /** Alias for {@link INT_64} */
    const LONG = INT_64.clone("LONG").freeze();
    ////////// UINT //////////
    /**
     * Unsigned 8-bit integer type descriptor
     *
     * @remarks
     * - Size: 1 byte
     * - Range: 0 to 255
     * - Not affected by endianness (single byte)
     * - Corresponds to `DataView.getUint8()` and `DataView.setUint8()`
     */
    const UINT_8 = definePrimitive("UINT_8")
        .setSize(1)
        .setGetter(({ view, offset }) => view.getUint8(offset))
        .setSetter(({ view, offset }, value) => view.setUint8(offset, value))
        .setReactive(({ view, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getUint8(localOffset + baseOffset());
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /** Alias for {@link UINT_8} */
    const BYTE = UINT_8.clone("BYTE").freeze();
    /**
     * Single-byte character type descriptor (optimized)
     *
     * @remarks
     * - Size: 1 byte
     * - Reads/writes a single character from/to a byte
     * - Uses first character of input string only
     * - No input validation!!!
     */
    const CHAR = definePrimitive("CHAR")
        .setSize(1)
        .setGetter(({ view, offset }) => String.fromCharCode(view.getUint8(offset)))
        .setSetter(({ view, offset }, value) => view.setUint8(offset, value.charCodeAt(0)))
        .setReactive(({ view, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => String.fromCharCode(view.getUint8(localOffset + baseOffset()));
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /**
     * Unsigned 16-bit integer type descriptor
     *
     * @remarks
     * - Size: 2 bytes
     * - Range: 0 to 65,535
     * - Endian-sensitive: Uses littleEndian parameter
     * - Corresponds to `DataView.getUint16()` and `DataView.setUint16()`
     */
    const UINT_16 = definePrimitive("UINT_16")
        .setSize(2)
        .setGetter(({ view, offset, littleEndian }) => view.getUint16(offset, littleEndian))
        .setSetter(({ view, offset, littleEndian }, value) => view.setUint16(offset, value, littleEndian))
        .setReactive(({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getUint16(localOffset + baseOffset(), littleEndian);
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /** Alias for {@link UINT_16} */
    const USHORT = UINT_16.clone("USHORT").freeze();
    /** Alias for {@link UINT_16} */
    const WORD = UINT_16.clone("WORD").freeze();
    /**
     * Unsigned 32-bit integer type descriptor
     *
     * @remarks
     * - Size: 4 bytes
     * - Range: 0 to 4,294,967,295
     * - Endian-sensitive: Uses littleEndian parameter
     * - Corresponds to `DataView.getUint32()` and `DataView.setUint32()`
     */
    const UINT_32 = definePrimitive("UINT_32")
        .setSize(4)
        .setGetter(({ view, offset, littleEndian }) => view.getUint32(offset, littleEndian))
        .setSetter(({ view, offset, littleEndian }, value) => view.setUint32(offset, value, littleEndian))
        .setReactive(({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getUint32(localOffset + baseOffset(), littleEndian);
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /** Alias for {@link UINT_32} */
    const UINT = UINT_32.clone("UINT").freeze();
    /** Alias for {@link UINT_32} */
    const DWORD = UINT_32.clone("DWORD").freeze();
    /**
     * Unsigned 64-bit integer type descriptor
     *
     * @remarks
     * - Size: 8 bytes
     * - Range: 0 to 18,446,744,073,709,551,615
     * - Uses JavaScript BigInt type
     * - Endian-sensitive: Uses littleEndian parameter
     * - Corresponds to `DataView.getBigUint64()` and `DataView.setBigUint64()`
     */
    const UINT_64 = definePrimitive("UINT_64")
        .setSize(8)
        .setGetter(({ view, offset, littleEndian }) => view.getBigUint64(offset, littleEndian))
        .setSetter(({ view, offset, littleEndian }, value) => view.setBigUint64(offset, value, littleEndian))
        .setReactive(({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getBigUint64(localOffset + baseOffset(), littleEndian);
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /** Alias for {@link UINT_64} */
    const ULONG = UINT_64.clone("ULONG").freeze();
    ////////// FLOAT //////////
    /**
     * Half-precision (16-bit) floating-point type descriptor
     *
     * @remarks
     * - Size: 2 bytes
     * - Range: ±65504
     * - Precision: ~3-4 decimal digits
     * - Endian-sensitive: Uses littleEndian parameter
     * - Corresponds to `DataView.getFloat16()` and `DataView.setFloat16()`
     */
    const FLOAT_16 = definePrimitive("FLOAT_16")
        .setSize(2)
        .setGetter(({ view, offset, littleEndian }) => view.getFloat16(offset, littleEndian))
        .setSetter(({ view, offset, littleEndian }, value) => view.setFloat16(offset, value, littleEndian))
        .setReactive(({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getFloat16(localOffset + baseOffset(), littleEndian);
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /**
     * Single-precision (32-bit) floating-point type descriptor
     *
     * @remarks
     * - Size: 4 bytes
     * - Range: ±3.4e38
     * - Precision: ~7 decimal digits
     * - Endian-sensitive: Uses littleEndian parameter
     * - Corresponds to `DataView.getFloat32()` and `DataView.setFloat32()`
     */
    const FLOAT_32 = definePrimitive("FLOAT_32")
        .setSize(4)
        .setGetter(({ view, offset, littleEndian }) => view.getFloat32(offset, littleEndian))
        .setSetter(({ view, offset, littleEndian }, value) => view.setFloat32(offset, value, littleEndian))
        .setReactive(({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getFloat32(localOffset + baseOffset(), littleEndian);
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /** Alias for {@link FLOAT_32} */
    const FLOAT = FLOAT_32.clone("FLOAT").freeze();
    /**
     * Double-precision (64-bit) floating-point type descriptor
     *
     * @remarks
     * - Size: 8 bytes
     * - Range: ±1.8e308
     * - Precision: ~15 decimal digits
     * - Endian-sensitive: Uses littleEndian parameter
     * - Corresponds to `DataView.getFloat64()` and `DataView.setFloat64()`
     */
    const FLOAT_64 = definePrimitive("FLOAT_64")
        .setSize(8)
        .setGetter(({ view, offset, littleEndian }) => view.getFloat64(offset, littleEndian))
        .setSetter(({ view, offset, littleEndian }, value) => view.setFloat64(offset, value, littleEndian))
        .setReactive(({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
        const getter = () => view.getFloat64(localOffset + baseOffset(), littleEndian);
        cacheGetter(getter);
        return getter();
    })
        .freeze();
    /** Alias for {@link FLOAT_64} */
    const DOUBLE = FLOAT_64.clone("DOUBLE").freeze();

    var types = /*#__PURE__*/Object.freeze({
        __proto__: null,
        BYTE: BYTE,
        CHAR: CHAR,
        DOUBLE: DOUBLE,
        DWORD: DWORD,
        FLOAT: FLOAT,
        FLOAT_16: FLOAT_16,
        FLOAT_32: FLOAT_32,
        FLOAT_64: FLOAT_64,
        INT: INT,
        INT_16: INT_16,
        INT_32: INT_32,
        INT_64: INT_64,
        INT_8: INT_8,
        LONG: LONG,
        SHORT: SHORT,
        UINT: UINT,
        UINT_16: UINT_16,
        UINT_32: UINT_32,
        UINT_64: UINT_64,
        UINT_8: UINT_8,
        ULONG: ULONG,
        UNKNOWN: UNKNOWN,
        USHORT: USHORT,
        WORD: WORD
    });

    /**
     * Array definition implementation
     * @param param0 - Element type or name
     * @param length - Array length
     * @param name - Array name
     * @param filler - When using an array setter,
     * if the length of the incoming data is less than the length of the array,
     * fill in the remaining positions with values, Default is not filled
     * @returns Array definition instance
     */
    function defineArray(param0, length, filler, name) {
        let _name;
        let _size;
        let _align;
        let _element = UNKNOWN;
        let _filler;
        let _length = 0;
        const setName = (name) => {
            _name = name;
            return typeDefinition;
        };
        const setSize = (size) => {
            _size = size;
            return typeDefinition;
        };
        const setAlign = (align) => {
            _align = align;
            return typeDefinition;
        };
        const setElement = (element, filler) => {
            _element = element ?? UNKNOWN;
            _filler = filler;
            return typeDefinition;
        };
        const setLength = (length) => {
            _length = length ?? 0;
            return typeDefinition;
        };
        const freeze = () => {
            const newDefinition = clone();
            return Object.freeze({
                isTypeDefinition: TypeDefinitionSymbol,
                name: newDefinition.name,
                size: newDefinition.size,
                align: newDefinition.align,
                element: newDefinition.element,
                filler: newDefinition.filler,
                length: newDefinition.length,
                getter: newDefinition.getter,
                setter: newDefinition.setter,
                reactive: newDefinition.reactive,
                clone: newDefinition.clone
            });
        };
        const clone = (name) => defineArray(_element, _length, _filler, name ?? _name)
            .setSize(_size)
            .setAlign(_align);
        const getter = ({ view, offset, littleEndian }) => {
            const array = new Array(_length);
            for (let index = 0; index < _length; index++) {
                array[index] = _element.getter({
                    view,
                    offset: offset + index * _element.size,
                    littleEndian
                });
            }
            return array;
        };
        const setter = ({ view, offset, littleEndian }, value) => {
            const valueLength = value.length;
            const minLength = Math.min(valueLength, _length);
            for (let index = 0; index < minLength; index++) {
                _element.setter({
                    view,
                    offset: offset + index * _element.size,
                    littleEndian
                }, value[index]);
            }
            if (_filler !== void 0 && valueLength < _length) {
                for (let index = valueLength; index < _length; index++) {
                    _element.setter({
                        view,
                        offset: offset + index * _element.size,
                        littleEndian
                    }, _filler);
                }
            }
        };
        const reactive = ({ view, littleEndian, localOffset, baseOffset, cacheGetter }) => {
            const proxyToRaw = () => typeDefinition.getter({
                view,
                offset: baseOffset() + localOffset,
                littleEndian
            });
            // Element getter
            const getterMap = new Map();
            const getElement = (index) => {
                let getter = getterMap.get(index);
                if (getter) {
                    return getter();
                }
                const context = {
                    view,
                    littleEndian,
                    localOffset: localOffset + index * _element.size,
                    baseOffset,
                    cacheGetter: getter => getterMap.set(index, getter)
                };
                getter = () => _element.reactive(context);
                getterMap.set(index, getter);
                return getter();
            };
            // To Array
            let cachedArray;
            const getArray = () => {
                if (cachedArray) {
                    return cachedArray;
                }
                cachedArray = new Array(_length);
                for (let index = 0; index < _length; index++) {
                    cachedArray[index] = getElement(index);
                }
                return cachedArray;
            };
            // Common array func proxy
            const callArray = (key) => {
                const func = Array.prototype[key];
                if (typeof func !== "function") {
                    return void 0;
                }
                const caller = (...param) => {
                    const array = getArray();
                    const copyArray = array.slice();
                    const result = func.call(copyArray, ...param);
                    typeDefinition.setter({
                        view,
                        offset: baseOffset() + localOffset,
                        littleEndian
                    }, copyArray.map(x => toRaw(x)));
                    return result;
                };
                internal.set(key, caller);
                return caller;
            };
            // Symbol.iterator
            const iterator = function* () {
                for (let index = 0; index < _length; index++) {
                    yield getElement(index);
                }
            };
            const forEach = (callback, thisArg) => {
                for (let index = 0; index < _length; index++) {
                    callback.call(thisArg, getElement(index), index, proxy);
                }
            };
            const map = (callback, thisArg) => {
                const result = new Array(_length);
                for (let index = 0; index < _length; index++) {
                    result[index] = callback.call(thisArg, getElement(index), index, proxy);
                }
                return result;
            };
            // Built-in props
            const internal = new Map([
                ["length", _length],
                ["forEach", forEach],
                ["map", map],
                [Symbol.iterator, iterator],
                [OperationRawSymbol, proxyToRaw]
            ]);
            // getter
            const get = (target, key) => {
                if (typeof key === "symbol") {
                    return internal.has(key) ? internal.get(key) : callArray(key);
                }
                const index = Number(key);
                if (isNaN(index)) {
                    return internal.has(key) ? internal.get(key) : callArray(key);
                }
                if (index < 0 || index >= _length) {
                    return void 0;
                }
                return getElement(index);
            };
            // setter
            const set = (target, key, value) => {
                if (typeof key === "symbol") {
                    return false;
                }
                const index = Number(key);
                if (isNaN(index)) {
                    return false;
                }
                if (index < 0 || index >= _length) {
                    return false;
                }
                _element.setter({
                    view,
                    offset: baseOffset() + localOffset + index * _element.size,
                    littleEndian: littleEndian
                }, value);
                return true;
            };
            const has = (target, key) => {
                if (typeof key === "symbol") {
                    return false;
                }
                const index = Number(key);
                if (isNaN(index)) {
                    return false;
                }
                if (index < 0 || index >= _length) {
                    return false;
                }
                return true;
            };
            let keys;
            const ownKeys = () => {
                if (keys) {
                    return keys;
                }
                keys = new Array(_length);
                for (let index = 0; index < _length; index++) {
                    keys[index] = String(index);
                }
                return keys;
            };
            const defineProperty = () => false;
            const deleteProperty = () => false;
            const proxy = new Proxy([], {
                get,
                set,
                has,
                ownKeys,
                defineProperty,
                deleteProperty
            });
            cacheGetter(() => proxy);
            return proxy;
        };
        const typeDefinition = {
            isTypeDefinition: TypeDefinitionSymbol,
            get name() {
                return _name ?? `${_element.name}[${_length}]`;
            },
            get size() {
                return Math.max(_size ?? _element.size * _length, 0);
            },
            get align() {
                return Math.max(_align ?? _element.align, 1);
            },
            get element() {
                return _element;
            },
            get filler() {
                return _filler;
            },
            get length() {
                return _length;
            },
            getter,
            setter,
            reactive,
            setName,
            setSize,
            setAlign,
            setElement,
            setLength,
            freeze,
            clone
        };
        if (typeof param0 === "object") {
            setElement(param0, filler);
            setLength(length);
            setName(name);
        }
        else {
            setName(param0);
        }
        return typeDefinition;
    }

    /** Default UTF-8 encoder/decoder implementation */
    const DefaultStringCoder = (() => {
        const encoder = new TextEncoder();
        const decoder = new TextDecoder("utf-8");
        return {
            encode(string) {
                return encoder.encode(string);
            },
            decode(buffer) {
                return decoder.decode(buffer);
            }
        };
    })();
    /**
     * String definition implementation
     * @param param0 - Size or name
     * @param filler - Padding byte value
     * @param name - Type name
     * @returns String definition instance
     */
    function defineString(param0, filler, name) {
        let _name;
        let _size = 0;
        let _align;
        let _filler;
        let _coder = DefaultStringCoder;
        let _bytes = new Uint8Array(_size);
        const setName = (name) => {
            _name = name;
            return typeDefinition;
        };
        const setSize = (size) => {
            _size = size ?? 0;
            _bytes = new Uint8Array(_size);
            return typeDefinition;
        };
        const setAlign = (align) => {
            _align = align;
            return typeDefinition;
        };
        const setFiller = (filler) => {
            _filler = filler;
            return typeDefinition;
        };
        const setCoder = (coder) => {
            _coder = coder ?? DefaultStringCoder;
            return typeDefinition;
        };
        const freeze = () => {
            const newDefinition = clone();
            return Object.freeze({
                isTypeDefinition: TypeDefinitionSymbol,
                name: newDefinition.name,
                size: newDefinition.size,
                align: newDefinition.align,
                filler: newDefinition.filler,
                coder: newDefinition.coder,
                getter: newDefinition.getter,
                setter: newDefinition.setter,
                reactive: newDefinition.reactive,
                clone: newDefinition.clone
            });
        };
        const clone = (name) => defineString(_size, _filler, name ?? _name)
            .setAlign(_align)
            .setCoder(_coder);
        const getter = ({ view, offset }) => {
            let actualLength = _size;
            for (let index = 0; index < _size; index++) {
                const byte = view.getUint8(offset + index);
                _bytes[index] = byte;
                if (typeof _filler === "number" && byte === _filler) {
                    actualLength = index;
                    break;
                }
            }
            const actualBytes = _bytes.subarray(0, actualLength);
            return _coder.decode(actualBytes);
        };
        const setter = ({ view, offset }, value) => {
            const bytes = _coder.encode(value);
            const writeLength = Math.min(bytes.length, _size);
            for (let index = 0; index < writeLength; index++) {
                view.setUint8(offset + index, bytes[index]);
            }
            if (typeof _filler === "number" && writeLength < _size) {
                for (let index = writeLength; index < _size; index++) {
                    view.setUint8(offset + index, _filler);
                }
            }
        };
        const reactive = ({ view, localOffset, baseOffset, cacheGetter }) => {
            const getter = () => {
                const offset = localOffset + baseOffset();
                let actualLength = _size;
                for (let index = 0; index < _size; index++) {
                    const byte = view.getUint8(offset + index);
                    _bytes[index] = byte;
                    if (typeof _filler === "number" && byte === _filler) {
                        actualLength = index;
                        break;
                    }
                }
                const actualBytes = _bytes.subarray(0, actualLength);
                return _coder.decode(actualBytes);
            };
            cacheGetter(getter);
            return getter();
        };
        const typeDefinition = {
            isTypeDefinition: TypeDefinitionSymbol,
            get name() {
                return _name ?? `string(${_size})`;
            },
            get size() {
                return Math.max(_size, 0);
            },
            get align() {
                return Math.max(_align ?? 1, 1);
            },
            get filler() {
                return _filler;
            },
            get coder() {
                return _coder;
            },
            getter,
            setter,
            reactive,
            setName,
            setSize,
            setAlign,
            setFiller,
            setCoder,
            freeze,
            clone
        };
        if (typeof param0 === "number") {
            setSize(param0);
            setFiller(filler);
            setName(name);
        }
        else {
            setName(param0);
        }
        return typeDefinition;
    }

    exports.BYTE = BYTE;
    exports.CHAR = CHAR;
    exports.DOUBLE = DOUBLE;
    exports.DWORD = DWORD;
    exports.DefaultStringCoder = DefaultStringCoder;
    exports.FLOAT = FLOAT;
    exports.FLOAT_16 = FLOAT_16;
    exports.FLOAT_32 = FLOAT_32;
    exports.FLOAT_64 = FLOAT_64;
    exports.INT = INT;
    exports.INT_16 = INT_16;
    exports.INT_32 = INT_32;
    exports.INT_64 = INT_64;
    exports.INT_8 = INT_8;
    exports.LONG = LONG;
    exports.OperationRawSymbol = OperationRawSymbol;
    exports.PaddingDefinitionSymbol = PaddingDefinitionSymbol;
    exports.PropertyDefinitionSymbol = PropertyDefinitionSymbol;
    exports.SHORT = SHORT;
    exports.TypeDefinitionSymbol = TypeDefinitionSymbol;
    exports.UINT = UINT;
    exports.UINT_16 = UINT_16;
    exports.UINT_32 = UINT_32;
    exports.UINT_64 = UINT_64;
    exports.UINT_8 = UINT_8;
    exports.ULONG = ULONG;
    exports.UNKNOWN = UNKNOWN;
    exports.USHORT = USHORT;
    exports.WORD = WORD;
    exports.defineArray = defineArray;
    exports.definePadding = definePadding;
    exports.definePrimitive = definePrimitive;
    exports.defineProperty = defineProperty;
    exports.defineString = defineString;
    exports.defineStruct = defineStruct;
    exports.get = get;
    exports.getArray = getArray;
    exports.isPaddingDefinition = isPaddingDefinition;
    exports.isPropertyDefinition = isPropertyDefinition;
    exports.isTypeDefinition = isTypeDefinition;
    exports.reactive = reactive;
    exports.ref = ref;
    exports.set = set;
    exports.setArray = setArray;
    exports.toRaw = toRaw;
    exports.toRef = toRef;
    exports.types = types;

}));