From ce760a8d584cbd03450da4eed4b6d7a030f16738 Mon Sep 17 00:00:00 2001 From: phroi <90913182+phroi@users.noreply.github.com> Date: Sat, 10 Jan 2026 22:36:01 +0100 Subject: [PATCH 1/2] feat(core): Add `bytesLen` and `bytesLenUnsafe` utilities --- .changeset/eighty-terms-cry.md | 5 +++ packages/core/src/hex/index.ts | 58 +++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 .changeset/eighty-terms-cry.md diff --git a/.changeset/eighty-terms-cry.md b/.changeset/eighty-terms-cry.md new file mode 100644 index 00000000..28e6c2b8 --- /dev/null +++ b/.changeset/eighty-terms-cry.md @@ -0,0 +1,5 @@ +--- +"@ckb-ccc/core": patch +--- + +Add `bytesLen` and `bytesLenUnsafe` utilities diff --git a/packages/core/src/hex/index.ts b/packages/core/src/hex/index.ts index 88a32d48..e34add49 100644 --- a/packages/core/src/hex/index.ts +++ b/packages/core/src/hex/index.ts @@ -18,7 +18,7 @@ export type HexLike = BytesLike; * A valid hexadecimal string: * - Has at least two characters. * - Starts with "0x". - * - Has an even length. + * - Has an even length (odd-length hex is considered non-standard). * - Contains only characters representing digits (0-9) or lowercase letters (a-f) after the "0x" prefix. * * @param v - The value to validate as a hexadecimal (ccc.Hex) string. @@ -58,3 +58,59 @@ export function hexFrom(hex: HexLike): Hex { return `0x${bytesTo(bytesFrom(hex), "hex")}`; } + +/** + * Return the number of bytes occupied by `hexLike`. + * + * This function efficiently calculates the byte length of hex-like values. + * For valid Hex strings, it uses a fast-path helper. For other types, it + * converts to bytes first. + * + * @param hexLike - Hex-like value (Hex string, Uint8Array, ArrayBuffer, or iterable of numbers). + * @returns Byte length of `hexLike`. + * + * @example + * ```typescript + * bytesLen("0x48656c6c6f") // 5 + * bytesLen(new Uint8Array([1, 2, 3])) // 3 + * bytesLen(new ArrayBuffer(4)) // 4 + * bytesLen([1, 2]) // 2 + * ``` + * + * @throws May throw if `hexLike` contains invalid byte values when passed to `bytesFrom`. + * @see bytesLenUnsafe - Fast version for already-validated Hex strings + * + * @note Prefer direct `.length`/`.byteLength` access on Uint8Array/ArrayBuffer when you already have bytes. + * Use `bytesLen()` only when you need length without performing additional operations. + * @see bytesFrom - Convert values to Bytes (Uint8Array) + */ +export function bytesLen(hexLike: HexLike): number { + if (isHex(hexLike)) { + return bytesLenUnsafe(hexLike); + } + + return bytesFrom(hexLike).length; +} + +/** + * Fast byte length for Hex strings. + * + * This function efficiently calculates the byte length of Hex values: + * - Skips isHex validation (caller must ensure input is valid Hex) + * - Handles odd-digit hex by rounding up, matching bytesFrom's padding behavior. + * + * @param hex - A valid Hex string (with "0x" prefix). + * @returns Byte length of the hex string. + * + * @example + * ```typescript + * bytesLenUnsafe("0x48656c6c6f") // 5 + * bytesLenUnsafe("0x123") // 2 (odd digits round up via padding) + * ``` + * + * @see bytesLen - Validated version for untrusted input + */ +export function bytesLenUnsafe(hex: Hex): number { + // Equivalent to Math.ceil((hex.length - 2) / 2), rounds up for odd-digit hex. + return (hex.length - 1) >> 1; +} From bb381c1b7c6605d8615707eaa5eacc9fc332fa4c Mon Sep 17 00:00:00 2001 From: Phroi <90913182+phroi@users.noreply.github.com> Date: Sun, 11 Jan 2026 13:33:39 +0100 Subject: [PATCH 2/2] feat(core): bump `byteLen` PR to minor --- .changeset/eighty-terms-cry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/eighty-terms-cry.md b/.changeset/eighty-terms-cry.md index 28e6c2b8..ba95dd46 100644 --- a/.changeset/eighty-terms-cry.md +++ b/.changeset/eighty-terms-cry.md @@ -1,5 +1,5 @@ --- -"@ckb-ccc/core": patch +"@ckb-ccc/core": minor --- Add `bytesLen` and `bytesLenUnsafe` utilities