viem
Version:
228 lines (209 loc) • 5.78 kB
text/typescript
import { InvalidBytesBooleanError } from '../../errors/encoding.js'
import type { ErrorType } from '../../errors/utils.js'
import type { ByteArray, Hex } from '../../types/misc.js'
import { type TrimErrorType, trim } from '../data/trim.js'
import {
type AssertSizeErrorType,
type HexToBigIntErrorType,
type HexToNumberErrorType,
assertSize,
hexToBigInt,
hexToNumber,
} from './fromHex.js'
import { type BytesToHexErrorType, bytesToHex } from './toHex.js'
export type FromBytesParameters<
to extends 'string' | 'hex' | 'bigint' | 'number' | 'boolean',
> =
| to
| {
/** Size of the bytes. */
size?: number | undefined
/** Type to convert to. */
to: to
}
export type FromBytesReturnType<to> = to extends 'string'
? string
: to extends 'hex'
? Hex
: to extends 'bigint'
? bigint
: to extends 'number'
? number
: to extends 'boolean'
? boolean
: never
export type FromBytesErrorType =
| BytesToHexErrorType
| BytesToBigIntErrorType
| BytesToBoolErrorType
| BytesToNumberErrorType
| BytesToStringErrorType
| ErrorType
/**
* Decodes a byte array into a UTF-8 string, hex value, number, bigint or boolean.
*
* - Docs: https://viem.sh/docs/utilities/fromBytes
* - Example: https://viem.sh/docs/utilities/fromBytes#usage
*
* @param bytes Byte array to decode.
* @param toOrOpts Type to convert to or options.
* @returns Decoded value.
*
* @example
* import { fromBytes } from 'viem'
* const data = fromBytes(new Uint8Array([1, 164]), 'number')
* // 420
*
* @example
* import { fromBytes } from 'viem'
* const data = fromBytes(
* new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]),
* 'string'
* )
* // 'Hello world'
*/
export function fromBytes<
to extends 'string' | 'hex' | 'bigint' | 'number' | 'boolean',
>(
bytes: ByteArray,
toOrOpts: FromBytesParameters<to>,
): FromBytesReturnType<to> {
const opts = typeof toOrOpts === 'string' ? { to: toOrOpts } : toOrOpts
const to = opts.to
if (to === 'number')
return bytesToNumber(bytes, opts) as FromBytesReturnType<to>
if (to === 'bigint')
return bytesToBigInt(bytes, opts) as FromBytesReturnType<to>
if (to === 'boolean')
return bytesToBool(bytes, opts) as FromBytesReturnType<to>
if (to === 'string')
return bytesToString(bytes, opts) as FromBytesReturnType<to>
return bytesToHex(bytes, opts) as FromBytesReturnType<to>
}
export type BytesToBigIntOpts = {
/** Whether or not the number of a signed representation. */
signed?: boolean | undefined
/** Size of the bytes. */
size?: number | undefined
}
export type BytesToBigIntErrorType =
| BytesToHexErrorType
| HexToBigIntErrorType
| ErrorType
/**
* Decodes a byte array into a bigint.
*
* - Docs: https://viem.sh/docs/utilities/fromBytes#bytestobigint
*
* @param bytes Byte array to decode.
* @param opts Options.
* @returns BigInt value.
*
* @example
* import { bytesToBigInt } from 'viem'
* const data = bytesToBigInt(new Uint8Array([1, 164]))
* // 420n
*/
export function bytesToBigInt(
bytes: ByteArray,
opts: BytesToBigIntOpts = {},
): bigint {
if (typeof opts.size !== 'undefined') assertSize(bytes, { size: opts.size })
const hex = bytesToHex(bytes, opts)
return hexToBigInt(hex, opts)
}
export type BytesToBoolOpts = {
/** Size of the bytes. */
size?: number | undefined
}
export type BytesToBoolErrorType =
| AssertSizeErrorType
| TrimErrorType
| ErrorType
/**
* Decodes a byte array into a boolean.
*
* - Docs: https://viem.sh/docs/utilities/fromBytes#bytestobool
*
* @param bytes Byte array to decode.
* @param opts Options.
* @returns Boolean value.
*
* @example
* import { bytesToBool } from 'viem'
* const data = bytesToBool(new Uint8Array([1]))
* // true
*/
export function bytesToBool(
bytes_: ByteArray,
opts: BytesToBoolOpts = {},
): boolean {
let bytes = bytes_
if (typeof opts.size !== 'undefined') {
assertSize(bytes, { size: opts.size })
bytes = trim(bytes)
}
if (bytes.length > 1 || bytes[0] > 1)
throw new InvalidBytesBooleanError(bytes)
return Boolean(bytes[0])
}
export type BytesToNumberOpts = BytesToBigIntOpts
export type BytesToNumberErrorType =
| BytesToHexErrorType
| HexToNumberErrorType
| ErrorType
/**
* Decodes a byte array into a number.
*
* - Docs: https://viem.sh/docs/utilities/fromBytes#bytestonumber
*
* @param bytes Byte array to decode.
* @param opts Options.
* @returns Number value.
*
* @example
* import { bytesToNumber } from 'viem'
* const data = bytesToNumber(new Uint8Array([1, 164]))
* // 420
*/
export function bytesToNumber(
bytes: ByteArray,
opts: BytesToNumberOpts = {},
): number {
if (typeof opts.size !== 'undefined') assertSize(bytes, { size: opts.size })
const hex = bytesToHex(bytes, opts)
return hexToNumber(hex, opts)
}
export type BytesToStringOpts = {
/** Size of the bytes. */
size?: number | undefined
}
export type BytesToStringErrorType =
| AssertSizeErrorType
| TrimErrorType
| ErrorType
/**
* Decodes a byte array into a UTF-8 string.
*
* - Docs: https://viem.sh/docs/utilities/fromBytes#bytestostring
*
* @param bytes Byte array to decode.
* @param opts Options.
* @returns String value.
*
* @example
* import { bytesToString } from 'viem'
* const data = bytesToString(new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]))
* // 'Hello world'
*/
export function bytesToString(
bytes_: ByteArray,
opts: BytesToStringOpts = {},
): string {
let bytes = bytes_
if (typeof opts.size !== 'undefined') {
assertSize(bytes, { size: opts.size })
bytes = trim(bytes, { dir: 'right' })
}
return new TextDecoder().decode(bytes)
}