"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: all[name]
    });
}
_export(exports, {
    isBytes: function() {
        return isBytes;
    },
    assertIsBytes: function() {
        return assertIsBytes;
    },
    bytesToHex: function() {
        return bytesToHex;
    },
    bytesToBigInt: function() {
        return bytesToBigInt;
    },
    bytesToSignedBigInt: function() {
        return bytesToSignedBigInt;
    },
    bytesToNumber: function() {
        return bytesToNumber;
    },
    bytesToString: function() {
        return bytesToString;
    },
    hexToBytes: function() {
        return hexToBytes;
    },
    bigIntToBytes: function() {
        return bigIntToBytes;
    },
    signedBigIntToBytes: function() {
        return signedBigIntToBytes;
    },
    numberToBytes: function() {
        return numberToBytes;
    },
    stringToBytes: function() {
        return stringToBytes;
    },
    valueToBytes: function() {
        return valueToBytes;
    },
    concatBytes: function() {
        return concatBytes;
    },
    createDataView: function() {
        return createDataView;
    }
});
const _assert = require("./assert");
const _hex = require("./hex");
// '0'.charCodeAt(0) === 48
const HEX_MINIMUM_NUMBER_CHARACTER = 48;
// '9'.charCodeAt(0) === 57
const HEX_MAXIMUM_NUMBER_CHARACTER = 58;
const HEX_CHARACTER_OFFSET = 87;
/**
 * Memoized function that returns an array to be used as a lookup table for
 * converting bytes to hexadecimal values.
 *
 * The array is created lazily and then cached for future use. The benefit of
 * this approach is that the performance of converting bytes to hex is much
 * better than if we were to call `toString(16)` on each byte.
 *
 * The downside is that the array is created once and then never garbage
 * collected. This is not a problem in practice because the array is only 256
 * elements long.
 *
 * @returns A function that returns the lookup table.
 */ function getPrecomputedHexValuesBuilder() {
    // To avoid issues with tree shaking, we need to use a function to return the
    // array. This is because the array is only used in the `bytesToHex` function
    // and if we were to use a global variable, the array might be removed by the
    // tree shaker.
    const lookupTable = [];
    return ()=>{
        if (lookupTable.length === 0) {
            for(let i = 0; i < 256; i++){
                lookupTable.push(i.toString(16).padStart(2, '0'));
            }
        }
        return lookupTable;
    };
}
/**
 * Function implementation of the {@link getPrecomputedHexValuesBuilder}
 * function.
 */ const getPrecomputedHexValues = getPrecomputedHexValuesBuilder();
function isBytes(value) {
    return value instanceof Uint8Array;
}
function assertIsBytes(value) {
    (0, _assert.assert)(isBytes(value), 'Value must be a Uint8Array.');
}
function bytesToHex(bytes) {
    assertIsBytes(bytes);
    if (bytes.length === 0) {
        return '0x';
    }
    const lookupTable = getPrecomputedHexValues();
    const hexadecimal = new Array(bytes.length);
    for(let i = 0; i < bytes.length; i++){
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        hexadecimal[i] = lookupTable[bytes[i]];
    }
    return (0, _hex.add0x)(hexadecimal.join(''));
}
function bytesToBigInt(bytes) {
    assertIsBytes(bytes);
    const hexadecimal = bytesToHex(bytes);
    return BigInt(hexadecimal);
}
function bytesToSignedBigInt(bytes) {
    assertIsBytes(bytes);
    let value = BigInt(0);
    for (const byte of bytes){
        // eslint-disable-next-line no-bitwise
        value = (value << BigInt(8)) + BigInt(byte);
    }
    return BigInt.asIntN(bytes.length * 8, value);
}
function bytesToNumber(bytes) {
    assertIsBytes(bytes);
    const bigint = bytesToBigInt(bytes);
    (0, _assert.assert)(bigint <= BigInt(Number.MAX_SAFE_INTEGER), 'Number is not a safe integer. Use `bytesToBigInt` instead.');
    return Number(bigint);
}
function bytesToString(bytes) {
    assertIsBytes(bytes);
    return new TextDecoder().decode(bytes);
}
function hexToBytes(value) {
    // "0x" is often used as empty byte array.
    if (value?.toLowerCase?.() === '0x') {
        return new Uint8Array();
    }
    (0, _hex.assertIsHexString)(value);
    // Remove the `0x` prefix if it exists, and pad the string to have an even
    // number of characters.
    const strippedValue = (0, _hex.remove0x)(value).toLowerCase();
    const normalizedValue = strippedValue.length % 2 === 0 ? strippedValue : `0${strippedValue}`;
    const bytes = new Uint8Array(normalizedValue.length / 2);
    for(let i = 0; i < bytes.length; i++){
        // While this is not the prettiest way to convert a hexadecimal string to a
        // `Uint8Array`, it is a lot faster than using `parseInt` to convert each
        // character.
        const c1 = normalizedValue.charCodeAt(i * 2);
        const c2 = normalizedValue.charCodeAt(i * 2 + 1);
        const n1 = c1 - (c1 < HEX_MAXIMUM_NUMBER_CHARACTER ? HEX_MINIMUM_NUMBER_CHARACTER : HEX_CHARACTER_OFFSET);
        const n2 = c2 - (c2 < HEX_MAXIMUM_NUMBER_CHARACTER ? HEX_MINIMUM_NUMBER_CHARACTER : HEX_CHARACTER_OFFSET);
        bytes[i] = n1 * 16 + n2;
    }
    return bytes;
}
function bigIntToBytes(value) {
    (0, _assert.assert)(typeof value === 'bigint', 'Value must be a bigint.');
    (0, _assert.assert)(value >= BigInt(0), 'Value must be a non-negative bigint.');
    const hexadecimal = value.toString(16);
    return hexToBytes(hexadecimal);
}
/**
 * Check if a `bigint` fits in a certain number of bytes.
 *
 * @param value - The `bigint` to check.
 * @param bytes - The number of bytes.
 * @returns Whether the `bigint` fits in the number of bytes.
 */ function bigIntFits(value, bytes) {
    (0, _assert.assert)(bytes > 0);
    /* eslint-disable no-bitwise */ const mask = value >> BigInt(31);
    return !((~value & mask) + (value & ~mask) >> BigInt(bytes * 8 + ~0));
/* eslint-enable no-bitwise */ }
function signedBigIntToBytes(value, byteLength) {
    (0, _assert.assert)(typeof value === 'bigint', 'Value must be a bigint.');
    (0, _assert.assert)(typeof byteLength === 'number', 'Byte length must be a number.');
    (0, _assert.assert)(byteLength > 0, 'Byte length must be greater than 0.');
    (0, _assert.assert)(bigIntFits(value, byteLength), 'Byte length is too small to represent the given value.');
    // ESLint doesn't like mutating function parameters, so to avoid having to
    // disable the rule, we create a new variable.
    let numberValue = value;
    const bytes = new Uint8Array(byteLength);
    for(let i = 0; i < bytes.length; i++){
        bytes[i] = Number(BigInt.asUintN(8, numberValue));
        // eslint-disable-next-line no-bitwise
        numberValue >>= BigInt(8);
    }
    return bytes.reverse();
}
function numberToBytes(value) {
    (0, _assert.assert)(typeof value === 'number', 'Value must be a number.');
    (0, _assert.assert)(value >= 0, 'Value must be a non-negative number.');
    (0, _assert.assert)(Number.isSafeInteger(value), 'Value is not a safe integer. Use `bigIntToBytes` instead.');
    const hexadecimal = value.toString(16);
    return hexToBytes(hexadecimal);
}
function stringToBytes(value) {
    (0, _assert.assert)(typeof value === 'string', 'Value must be a string.');
    return new TextEncoder().encode(value);
}
function valueToBytes(value) {
    if (typeof value === 'bigint') {
        return bigIntToBytes(value);
    }
    if (typeof value === 'number') {
        return numberToBytes(value);
    }
    if (typeof value === 'string') {
        if (value.startsWith('0x')) {
            return hexToBytes(value);
        }
        return stringToBytes(value);
    }
    if (isBytes(value)) {
        return value;
    }
    throw new TypeError(`Unsupported value type: "${typeof value}".`);
}
function concatBytes(values) {
    const normalizedValues = new Array(values.length);
    let byteLength = 0;
    for(let i = 0; i < values.length; i++){
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        const value = valueToBytes(values[i]);
        normalizedValues[i] = value;
        byteLength += value.length;
    }
    const bytes = new Uint8Array(byteLength);
    for(let i = 0, offset = 0; i < normalizedValues.length; i++){
        // While we could simply spread the values into an array and use
        // `Uint8Array.from`, that is a lot slower than using `Uint8Array.set`.
        bytes.set(normalizedValues[i], offset);
        offset += normalizedValues[i].length;
    }
    return bytes;
}
function createDataView(bytes) {
    // To maintain compatibility with Node.js, we need to check if the bytes are
    // a Buffer. If so, we need to slice the buffer to get the underlying
    // ArrayBuffer.
    // eslint-disable-next-line no-restricted-globals
    if (typeof Buffer !== 'undefined' && bytes instanceof Buffer) {
        const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
        return new DataView(buffer);
    }
    return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
}

//# sourceMappingURL=bytes.js.map