You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
887 lines
22 KiB
887 lines
22 KiB
import { equalBytes } from '@noble/curves/abstract/utils'
|
|
import * as Errors from './Errors.js'
|
|
import * as Hex from './Hex.js'
|
|
import * as internal from './internal/bytes.js'
|
|
import * as internal_hex from './internal/hex.js'
|
|
import * as Json from './Json.js'
|
|
|
|
const decoder = /*#__PURE__*/ new TextDecoder()
|
|
const encoder = /*#__PURE__*/ new TextEncoder()
|
|
|
|
/** Root type for a Bytes array. */
|
|
export type Bytes = Uint8Array
|
|
|
|
/**
|
|
* Asserts if the given value is {@link ox#Bytes.Bytes}.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.assert('abc')
|
|
* // @error: Bytes.InvalidBytesTypeError:
|
|
* // @error: Value `"abc"` of type `string` is an invalid Bytes value.
|
|
* // @error: Bytes values must be of type `Uint8Array`.
|
|
* ```
|
|
*
|
|
* @param value - Value to assert.
|
|
*/
|
|
export function assert(value: unknown): asserts value is Bytes {
|
|
if (value instanceof Uint8Array) return
|
|
if (!value) throw new InvalidBytesTypeError(value)
|
|
if (typeof value !== 'object') throw new InvalidBytesTypeError(value)
|
|
if (!('BYTES_PER_ELEMENT' in value)) throw new InvalidBytesTypeError(value)
|
|
if (value.BYTES_PER_ELEMENT !== 1 || value.constructor.name !== 'Uint8Array')
|
|
throw new InvalidBytesTypeError(value)
|
|
}
|
|
|
|
export declare namespace assert {
|
|
type ErrorType = InvalidBytesTypeError | Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Concatenates two or more {@link ox#Bytes.Bytes}.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const bytes = Bytes.concat(
|
|
* Bytes.from([1]),
|
|
* Bytes.from([69]),
|
|
* Bytes.from([420, 69]),
|
|
* )
|
|
* // @log: Uint8Array [ 1, 69, 420, 69 ]
|
|
* ```
|
|
*
|
|
* @param values - Values to concatenate.
|
|
* @returns Concatenated {@link ox#Bytes.Bytes}.
|
|
*/
|
|
export function concat(...values: readonly Bytes[]): Bytes {
|
|
let length = 0
|
|
for (const arr of values) {
|
|
length += arr.length
|
|
}
|
|
const result = new Uint8Array(length)
|
|
for (let i = 0, index = 0; i < values.length; i++) {
|
|
const arr = values[i]
|
|
result.set(arr!, index)
|
|
index += arr!.length
|
|
}
|
|
return result
|
|
}
|
|
|
|
export declare namespace concat {
|
|
type ErrorType = Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Instantiates a {@link ox#Bytes.Bytes} value from a `Uint8Array`, a hex string, or an array of unsigned 8-bit integers.
|
|
*
|
|
* :::tip
|
|
*
|
|
* To instantiate from a **Boolean**, **String**, or **Number**, use one of the following:
|
|
*
|
|
* - `Bytes.fromBoolean`
|
|
*
|
|
* - `Bytes.fromString`
|
|
*
|
|
* - `Bytes.fromNumber`
|
|
*
|
|
* :::
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* // @noErrors
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.from([255, 124, 5, 4])
|
|
* // @log: Uint8Array([255, 124, 5, 4])
|
|
*
|
|
* const data = Bytes.from('0xdeadbeef')
|
|
* // @log: Uint8Array([222, 173, 190, 239])
|
|
* ```
|
|
*
|
|
* @param value - Value to convert.
|
|
* @returns A {@link ox#Bytes.Bytes} instance.
|
|
*/
|
|
export function from(value: Hex.Hex | Bytes | readonly number[]): Bytes {
|
|
if (value instanceof Uint8Array) return value
|
|
if (typeof value === 'string') return fromHex(value)
|
|
return fromArray(value)
|
|
}
|
|
|
|
export declare namespace from {
|
|
type ErrorType =
|
|
| fromHex.ErrorType
|
|
| fromArray.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Converts an array of unsigned 8-bit integers into {@link ox#Bytes.Bytes}.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.fromArray([255, 124, 5, 4])
|
|
* // @log: Uint8Array([255, 124, 5, 4])
|
|
* ```
|
|
*
|
|
* @param value - Value to convert.
|
|
* @returns A {@link ox#Bytes.Bytes} instance.
|
|
*/
|
|
export function fromArray(value: readonly number[] | Uint8Array): Bytes {
|
|
return value instanceof Uint8Array ? value : new Uint8Array(value)
|
|
}
|
|
|
|
export declare namespace fromArray {
|
|
type ErrorType = Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Encodes a boolean value into {@link ox#Bytes.Bytes}.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.fromBoolean(true)
|
|
* // @log: Uint8Array([1])
|
|
* ```
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.fromBoolean(true, { size: 32 })
|
|
* // @log: Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1])
|
|
* ```
|
|
*
|
|
* @param value - Boolean value to encode.
|
|
* @param options - Encoding options.
|
|
* @returns Encoded {@link ox#Bytes.Bytes}.
|
|
*/
|
|
export function fromBoolean(value: boolean, options: fromBoolean.Options = {}) {
|
|
const { size } = options
|
|
const bytes = new Uint8Array(1)
|
|
bytes[0] = Number(value)
|
|
if (typeof size === 'number') {
|
|
internal.assertSize(bytes, size)
|
|
return padLeft(bytes, size)
|
|
}
|
|
return bytes
|
|
}
|
|
|
|
export declare namespace fromBoolean {
|
|
type Options = {
|
|
/** Size of the output bytes. */
|
|
size?: number | undefined
|
|
}
|
|
|
|
type ErrorType =
|
|
| internal.assertSize.ErrorType
|
|
| padLeft.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Encodes a {@link ox#Hex.Hex} value into {@link ox#Bytes.Bytes}.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.fromHex('0x48656c6c6f20776f726c6421')
|
|
* // @log: Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33])
|
|
* ```
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.fromHex('0x48656c6c6f20776f726c6421', { size: 32 })
|
|
* // @log: Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
|
* ```
|
|
*
|
|
* @param value - {@link ox#Hex.Hex} value to encode.
|
|
* @param options - Encoding options.
|
|
* @returns Encoded {@link ox#Bytes.Bytes}.
|
|
*/
|
|
export function fromHex(value: Hex.Hex, options: fromHex.Options = {}): Bytes {
|
|
const { size } = options
|
|
|
|
let hex = value
|
|
if (size) {
|
|
internal_hex.assertSize(value, size)
|
|
hex = Hex.padRight(value, size)
|
|
}
|
|
|
|
let hexString = hex.slice(2) as string
|
|
if (hexString.length % 2) hexString = `0${hexString}`
|
|
|
|
const length = hexString.length / 2
|
|
const bytes = new Uint8Array(length)
|
|
for (let index = 0, j = 0; index < length; index++) {
|
|
const nibbleLeft = internal.charCodeToBase16(hexString.charCodeAt(j++))
|
|
const nibbleRight = internal.charCodeToBase16(hexString.charCodeAt(j++))
|
|
if (nibbleLeft === undefined || nibbleRight === undefined) {
|
|
throw new Errors.BaseError(
|
|
`Invalid byte sequence ("${hexString[j - 2]}${hexString[j - 1]}" in "${hexString}").`,
|
|
)
|
|
}
|
|
bytes[index] = nibbleLeft * 16 + nibbleRight
|
|
}
|
|
return bytes
|
|
}
|
|
|
|
export declare namespace fromHex {
|
|
type Options = {
|
|
/** Size of the output bytes. */
|
|
size?: number | undefined
|
|
}
|
|
|
|
type ErrorType =
|
|
| internal_hex.assertSize.ErrorType
|
|
| Hex.padRight.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Encodes a number value into {@link ox#Bytes.Bytes}.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.fromNumber(420)
|
|
* // @log: Uint8Array([1, 164])
|
|
* ```
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.fromNumber(420, { size: 4 })
|
|
* // @log: Uint8Array([0, 0, 1, 164])
|
|
* ```
|
|
*
|
|
* @param value - Number value to encode.
|
|
* @param options - Encoding options.
|
|
* @returns Encoded {@link ox#Bytes.Bytes}.
|
|
*/
|
|
export function fromNumber(
|
|
value: bigint | number,
|
|
options?: fromNumber.Options | undefined,
|
|
) {
|
|
const hex = Hex.fromNumber(value, options)
|
|
return fromHex(hex)
|
|
}
|
|
|
|
export declare namespace fromNumber {
|
|
export type Options = Hex.fromNumber.Options
|
|
|
|
export type ErrorType =
|
|
| Hex.fromNumber.ErrorType
|
|
| fromHex.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Encodes a string into {@link ox#Bytes.Bytes}.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.fromString('Hello world!')
|
|
* // @log: Uint8Array([72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33])
|
|
* ```
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.fromString('Hello world!', { size: 32 })
|
|
* // @log: Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
|
|
* ```
|
|
*
|
|
* @param value - String to encode.
|
|
* @param options - Encoding options.
|
|
* @returns Encoded {@link ox#Bytes.Bytes}.
|
|
*/
|
|
export function fromString(
|
|
value: string,
|
|
options: fromString.Options = {},
|
|
): Bytes {
|
|
const { size } = options
|
|
|
|
const bytes = encoder.encode(value)
|
|
if (typeof size === 'number') {
|
|
internal.assertSize(bytes, size)
|
|
return padRight(bytes, size)
|
|
}
|
|
return bytes
|
|
}
|
|
|
|
export declare namespace fromString {
|
|
type Options = {
|
|
/** Size of the output bytes. */
|
|
size?: number | undefined
|
|
}
|
|
|
|
type ErrorType =
|
|
| internal.assertSize.ErrorType
|
|
| padRight.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Checks if two {@link ox#Bytes.Bytes} values are equal.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.isEqual(Bytes.from([1]), Bytes.from([1]))
|
|
* // @log: true
|
|
*
|
|
* Bytes.isEqual(Bytes.from([1]), Bytes.from([2]))
|
|
* // @log: false
|
|
* ```
|
|
*
|
|
* @param bytesA - First {@link ox#Bytes.Bytes} value.
|
|
* @param bytesB - Second {@link ox#Bytes.Bytes} value.
|
|
* @returns `true` if the two values are equal, otherwise `false`.
|
|
*/
|
|
export function isEqual(bytesA: Bytes, bytesB: Bytes) {
|
|
return equalBytes(bytesA, bytesB)
|
|
}
|
|
|
|
export declare namespace isEqual {
|
|
type ErrorType = Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Pads a {@link ox#Bytes.Bytes} value to the left with zero bytes until it reaches the given `size` (default: 32 bytes).
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.padLeft(Bytes.from([1]), 4)
|
|
* // @log: Uint8Array([0, 0, 0, 1])
|
|
* ```
|
|
*
|
|
* @param value - {@link ox#Bytes.Bytes} value to pad.
|
|
* @param size - Size to pad the {@link ox#Bytes.Bytes} value to.
|
|
* @returns Padded {@link ox#Bytes.Bytes} value.
|
|
*/
|
|
export function padLeft(
|
|
value: Bytes,
|
|
size?: number | undefined,
|
|
): padLeft.ReturnType {
|
|
return internal.pad(value, { dir: 'left', size })
|
|
}
|
|
|
|
export declare namespace padLeft {
|
|
type ReturnType = internal.pad.ReturnType
|
|
type ErrorType = internal.pad.ErrorType | Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Pads a {@link ox#Bytes.Bytes} value to the right with zero bytes until it reaches the given `size` (default: 32 bytes).
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.padRight(Bytes.from([1]), 4)
|
|
* // @log: Uint8Array([1, 0, 0, 0])
|
|
* ```
|
|
*
|
|
* @param value - {@link ox#Bytes.Bytes} value to pad.
|
|
* @param size - Size to pad the {@link ox#Bytes.Bytes} value to.
|
|
* @returns Padded {@link ox#Bytes.Bytes} value.
|
|
*/
|
|
export function padRight(
|
|
value: Bytes,
|
|
size?: number | undefined,
|
|
): padRight.ReturnType {
|
|
return internal.pad(value, { dir: 'right', size })
|
|
}
|
|
|
|
export declare namespace padRight {
|
|
type ReturnType = internal.pad.ReturnType
|
|
type ErrorType = internal.pad.ErrorType | Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Generates random {@link ox#Bytes.Bytes} of the specified length.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const bytes = Bytes.random(32)
|
|
* // @log: Uint8Array([... x32])
|
|
* ```
|
|
*
|
|
* @param length - Length of the random {@link ox#Bytes.Bytes} to generate.
|
|
* @returns Random {@link ox#Bytes.Bytes} of the specified length.
|
|
*/
|
|
export function random(length: number): Bytes {
|
|
return crypto.getRandomValues(new Uint8Array(length))
|
|
}
|
|
|
|
export declare namespace random {
|
|
type ErrorType = Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Retrieves the size of a {@link ox#Bytes.Bytes} value.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.size(Bytes.from([1, 2, 3, 4]))
|
|
* // @log: 4
|
|
* ```
|
|
*
|
|
* @param value - {@link ox#Bytes.Bytes} value.
|
|
* @returns Size of the {@link ox#Bytes.Bytes} value.
|
|
*/
|
|
export function size(value: Bytes): number {
|
|
return value.length
|
|
}
|
|
|
|
export declare namespace size {
|
|
export type ErrorType = Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Returns a section of a {@link ox#Bytes.Bytes} value given a start/end bytes offset.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.slice(
|
|
* Bytes.from([1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
* 1,
|
|
* 4,
|
|
* )
|
|
* // @log: Uint8Array([2, 3, 4])
|
|
* ```
|
|
*
|
|
* @param value - The {@link ox#Bytes.Bytes} value.
|
|
* @param start - Start offset.
|
|
* @param end - End offset.
|
|
* @param options - Slice options.
|
|
* @returns Sliced {@link ox#Bytes.Bytes} value.
|
|
*/
|
|
export function slice(
|
|
value: Bytes,
|
|
start?: number | undefined,
|
|
end?: number | undefined,
|
|
options: slice.Options = {},
|
|
): Bytes {
|
|
const { strict } = options
|
|
internal.assertStartOffset(value, start)
|
|
const value_ = value.slice(start, end)
|
|
if (strict) internal.assertEndOffset(value_, start, end)
|
|
return value_
|
|
}
|
|
|
|
export declare namespace slice {
|
|
type Options = {
|
|
/** Asserts that the sliced value is the same size as the given start/end offsets. */
|
|
strict?: boolean | undefined
|
|
}
|
|
|
|
export type ErrorType =
|
|
| internal.assertStartOffset.ErrorType
|
|
| internal.assertEndOffset.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Decodes a {@link ox#Bytes.Bytes} into a bigint.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.toBigInt(Bytes.from([1, 164]))
|
|
* // @log: 420n
|
|
* ```
|
|
*
|
|
* @param bytes - The {@link ox#Bytes.Bytes} to decode.
|
|
* @param options - Decoding options.
|
|
* @returns Decoded bigint.
|
|
*/
|
|
export function toBigInt(bytes: Bytes, options: toBigInt.Options = {}): bigint {
|
|
const { size } = options
|
|
if (typeof size !== 'undefined') internal.assertSize(bytes, size)
|
|
const hex = Hex.fromBytes(bytes, options)
|
|
return Hex.toBigInt(hex, options)
|
|
}
|
|
|
|
export declare namespace toBigInt {
|
|
type Options = {
|
|
/** Whether or not the number of a signed representation. */
|
|
signed?: boolean | undefined
|
|
/** Size of the bytes. */
|
|
size?: number | undefined
|
|
}
|
|
|
|
type ErrorType =
|
|
| Hex.fromBytes.ErrorType
|
|
| Hex.toBigInt.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Decodes a {@link ox#Bytes.Bytes} into a boolean.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.toBoolean(Bytes.from([1]))
|
|
* // @log: true
|
|
* ```
|
|
*
|
|
* @param bytes - The {@link ox#Bytes.Bytes} to decode.
|
|
* @param options - Decoding options.
|
|
* @returns Decoded boolean.
|
|
*/
|
|
export function toBoolean(
|
|
bytes: Bytes,
|
|
options: toBoolean.Options = {},
|
|
): boolean {
|
|
const { size } = options
|
|
let bytes_ = bytes
|
|
if (typeof size !== 'undefined') {
|
|
internal.assertSize(bytes_, size)
|
|
bytes_ = trimLeft(bytes_)
|
|
}
|
|
if (bytes_.length > 1 || bytes_[0]! > 1)
|
|
throw new InvalidBytesBooleanError(bytes_)
|
|
return Boolean(bytes_[0])
|
|
}
|
|
|
|
export declare namespace toBoolean {
|
|
type Options = {
|
|
/** Size of the bytes. */
|
|
size?: number | undefined
|
|
}
|
|
|
|
type ErrorType =
|
|
| internal.assertSize.ErrorType
|
|
| trimLeft.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Encodes a {@link ox#Bytes.Bytes} value into a {@link ox#Hex.Hex} value.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.toHex(Bytes.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]))
|
|
* // '0x48656c6c6f20576f726c6421'
|
|
* ```
|
|
*
|
|
* @param value - The {@link ox#Bytes.Bytes} to decode.
|
|
* @param options - Options.
|
|
* @returns Decoded {@link ox#Hex.Hex} value.
|
|
*/
|
|
export function toHex(value: Bytes, options: toHex.Options = {}): Hex.Hex {
|
|
return Hex.fromBytes(value, options)
|
|
}
|
|
|
|
export declare namespace toHex {
|
|
type Options = {
|
|
/** Size of the bytes. */
|
|
size?: number | undefined
|
|
}
|
|
|
|
type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Decodes a {@link ox#Bytes.Bytes} into a number.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.toNumber(Bytes.from([1, 164]))
|
|
* // @log: 420
|
|
* ```
|
|
*/
|
|
export function toNumber(bytes: Bytes, options: toNumber.Options = {}): number {
|
|
const { size } = options
|
|
if (typeof size !== 'undefined') internal.assertSize(bytes, size)
|
|
const hex = Hex.fromBytes(bytes, options)
|
|
return Hex.toNumber(hex, options)
|
|
}
|
|
|
|
export declare namespace toNumber {
|
|
type Options = {
|
|
/** Whether or not the number of a signed representation. */
|
|
signed?: boolean | undefined
|
|
/** Size of the bytes. */
|
|
size?: number | undefined
|
|
}
|
|
|
|
type ErrorType =
|
|
| Hex.fromBytes.ErrorType
|
|
| Hex.toNumber.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Decodes a {@link ox#Bytes.Bytes} into a string.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* const data = Bytes.toString(Bytes.from([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]))
|
|
* // @log: 'Hello world'
|
|
* ```
|
|
*
|
|
* @param bytes - The {@link ox#Bytes.Bytes} to decode.
|
|
* @param options - Options.
|
|
* @returns Decoded string.
|
|
*/
|
|
export function toString(bytes: Bytes, options: toString.Options = {}): string {
|
|
const { size } = options
|
|
|
|
let bytes_ = bytes
|
|
if (typeof size !== 'undefined') {
|
|
internal.assertSize(bytes_, size)
|
|
bytes_ = trimRight(bytes_)
|
|
}
|
|
return decoder.decode(bytes_)
|
|
}
|
|
|
|
export declare namespace toString {
|
|
export type Options = {
|
|
/** Size of the bytes. */
|
|
size?: number | undefined
|
|
}
|
|
|
|
export type ErrorType =
|
|
| internal.assertSize.ErrorType
|
|
| trimRight.ErrorType
|
|
| Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Trims leading zeros from a {@link ox#Bytes.Bytes} value.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.trimLeft(Bytes.from([0, 0, 0, 0, 1, 2, 3]))
|
|
* // @log: Uint8Array([1, 2, 3])
|
|
* ```
|
|
*
|
|
* @param value - {@link ox#Bytes.Bytes} value.
|
|
* @returns Trimmed {@link ox#Bytes.Bytes} value.
|
|
*/
|
|
export function trimLeft(value: Bytes): Bytes {
|
|
return internal.trim(value, { dir: 'left' })
|
|
}
|
|
|
|
export declare namespace trimLeft {
|
|
type ErrorType = internal.trim.ErrorType | Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Trims trailing zeros from a {@link ox#Bytes.Bytes} value.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.trimRight(Bytes.from([1, 2, 3, 0, 0, 0, 0]))
|
|
* // @log: Uint8Array([1, 2, 3])
|
|
* ```
|
|
*
|
|
* @param value - {@link ox#Bytes.Bytes} value.
|
|
* @returns Trimmed {@link ox#Bytes.Bytes} value.
|
|
*/
|
|
export function trimRight(value: Bytes): Bytes {
|
|
return internal.trim(value, { dir: 'right' })
|
|
}
|
|
|
|
export declare namespace trimRight {
|
|
export type ErrorType = internal.trim.ErrorType | Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Checks if the given value is {@link ox#Bytes.Bytes}.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.validate('0x')
|
|
* // @log: false
|
|
*
|
|
* Bytes.validate(Bytes.from([1, 2, 3]))
|
|
* // @log: true
|
|
* ```
|
|
*
|
|
* @param value - Value to check.
|
|
* @returns `true` if the value is {@link ox#Bytes.Bytes}, otherwise `false`.
|
|
*/
|
|
export function validate(value: unknown): value is Bytes {
|
|
try {
|
|
assert(value)
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
export declare namespace validate {
|
|
export type ErrorType = Errors.GlobalErrorType
|
|
}
|
|
|
|
/**
|
|
* Thrown when the bytes value cannot be represented as a boolean.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.toBoolean(Bytes.from([5]))
|
|
* // @error: Bytes.InvalidBytesBooleanError: Bytes value `[5]` is not a valid boolean.
|
|
* // @error: The bytes array must contain a single byte of either a `0` or `1` value.
|
|
* ```
|
|
*/
|
|
export class InvalidBytesBooleanError extends Errors.BaseError {
|
|
override readonly name = 'Bytes.InvalidBytesBooleanError'
|
|
|
|
constructor(bytes: Bytes) {
|
|
super(`Bytes value \`${bytes}\` is not a valid boolean.`, {
|
|
metaMessages: [
|
|
'The bytes array must contain a single byte of either a `0` or `1` value.',
|
|
],
|
|
})
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Thrown when a value cannot be converted to bytes.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* // @noErrors
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.from('foo')
|
|
* // @error: Bytes.InvalidBytesTypeError: Value `foo` of type `string` is an invalid Bytes value.
|
|
* ```
|
|
*/
|
|
export class InvalidBytesTypeError extends Errors.BaseError {
|
|
override readonly name = 'Bytes.InvalidBytesTypeError'
|
|
|
|
constructor(value: unknown) {
|
|
super(
|
|
`Value \`${typeof value === 'object' ? Json.stringify(value) : value}\` of type \`${typeof value}\` is an invalid Bytes value.`,
|
|
{
|
|
metaMessages: ['Bytes values must be of type `Bytes`.'],
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Thrown when a size exceeds the maximum allowed size.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.fromString('Hello World!', { size: 8 })
|
|
* // @error: Bytes.SizeOverflowError: Size cannot exceed `8` bytes. Given size: `12` bytes.
|
|
* ```
|
|
*/
|
|
export class SizeOverflowError extends Errors.BaseError {
|
|
override readonly name = 'Bytes.SizeOverflowError'
|
|
|
|
constructor({ givenSize, maxSize }: { givenSize: number; maxSize: number }) {
|
|
super(
|
|
`Size cannot exceed \`${maxSize}\` bytes. Given size: \`${givenSize}\` bytes.`,
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Thrown when a slice offset is out-of-bounds.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.slice(Bytes.from([1, 2, 3]), 4)
|
|
* // @error: Bytes.SliceOffsetOutOfBoundsError: Slice starting at offset `4` is out-of-bounds (size: `3`).
|
|
* ```
|
|
*/
|
|
export class SliceOffsetOutOfBoundsError extends Errors.BaseError {
|
|
override readonly name = 'Bytes.SliceOffsetOutOfBoundsError'
|
|
|
|
constructor({
|
|
offset,
|
|
position,
|
|
size,
|
|
}: { offset: number; position: 'start' | 'end'; size: number }) {
|
|
super(
|
|
`Slice ${
|
|
position === 'start' ? 'starting' : 'ending'
|
|
} at offset \`${offset}\` is out-of-bounds (size: \`${size}\`).`,
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Thrown when a the padding size exceeds the maximum allowed size.
|
|
*
|
|
* @example
|
|
* ```ts twoslash
|
|
* import { Bytes } from 'ox'
|
|
*
|
|
* Bytes.padLeft(Bytes.fromString('Hello World!'), 8)
|
|
* // @error: [Bytes.SizeExceedsPaddingSizeError: Bytes size (`12`) exceeds padding size (`8`).
|
|
* ```
|
|
*/
|
|
export class SizeExceedsPaddingSizeError extends Errors.BaseError {
|
|
override readonly name = 'Bytes.SizeExceedsPaddingSizeError'
|
|
|
|
constructor({
|
|
size,
|
|
targetSize,
|
|
type,
|
|
}: {
|
|
size: number
|
|
targetSize: number
|
|
type: 'Hex' | 'Bytes'
|
|
}) {
|
|
super(
|
|
`${type.charAt(0).toUpperCase()}${type
|
|
.slice(1)
|
|
.toLowerCase()} size (\`${size}\`) exceeds padding size (\`${targetSize}\`).`,
|
|
)
|
|
}
|
|
}
|