---
title: "@unikvs/hex"
description: "バイト列を 16 進文字列として表すバイト列へ透過的に変換する Transformer プラグインの使い方を説明します。"
---

## 概要 [#overview]

`@unikvs/hex` は、バイト列を 16 進文字列 (hex) として表すバイト列へ変換する Transformer プラグインです。Transformer

書き込み時は `encode` で hex 化し、読み取り時は `decode` で元のバイト列に戻すため、変換の詳細を意識せずに読み書きできます。ハッシュ値やバイナリー内容の確認、デバッグ出力、テキストしか保存できない保存先への格納に使います。

入出力はどちらも `Uint8Array<ArrayBuffer>` です。出力は常に小文字 (`0-9`・`a-f`) で、入力は大文字・小文字のどちらも受け付けます。変換後のサイズは元のサイズのちょうど 2 倍になります。

常にオープン状態です。`open`・`close` は不要で、`isOpen` は常に `true`、`name` は常に `"Hex"` を返します。

インストールは次のとおりです。

```package-install
npm install @unikvs/hex
```

:::tip
小さく保存したい場合は [`@unikvs/compression`](/unikvs/ja/packages/compression) を、破損や改ざんを検知したい場合は [`@unikvs/checksum`](/unikvs/ja/packages/checksum) を検討してください。このパッケージに圧縮や検証の機能はありません。
:::

## 使い方 [#usage]

通常は引数なしで生成します。UTF-8 変換に使うインスタンスを差し替えたい場合にだけ `HexOptions` を指定します。

```ts
import { Hex } from "@unikvs/hex";

const hex = new Hex();
```

```ts
import { Hex, type HexOptions } from "@unikvs/hex";
import { FastUtf8 } from "fast-utf8";

const options: HexOptions = {
  encoder: new FastUtf8(),
  decoder: new FastUtf8({ strict: true }),
};

const hex = new Hex(options);
```

`HexOptions` の内容は次のとおりです。通常は省略し、既定のまま使います。`decoder` に `strict: false` のインスタンスを指定した場合は、不正な UTF-8 は `HexDecodeError` として投げられます。詳しくは[エラー](#errors)を参照してください。

```ts
type HexOptions = {
  readonly encoder?: FastUtf8 | undefined;
  readonly decoder?: FastUtf8 | undefined;
};
```

主なメンバーは次のとおりです。

| メンバー | 概要 |
| --- | --- |
| `new Hex(options?)` | オプションなしで初期化します。差し替えが必要な場合だけ `HexOptions` を渡します。 |
| `name` | 常に `"Hex"` を返します。 |
| `isOpen` | 常に `true` を返します。 |
| `encode({ data })` | `Uint8Array<ArrayBuffer>` を小文字 hex の `Uint8Array<ArrayBuffer>` に変換します。 |
| `decode({ data })` | 小文字・大文字の hex の `Uint8Array<ArrayBuffer>` を元のバイト列に戻します。 |
| `getEncodable()` | hex 化用の `TransformStream` を返します。 |
| `getDecodable()` | hex 復元用の `TransformStream` を返します。 |

一括変換の例です。`encode` の結果を UTF-8 文字列として解釈すると小文字の hex になります。

```ts
import { Hex } from "@unikvs/hex";

const hex = new Hex();

const encoded = hex.encode({ data: Uint8Array.from([0xde, 0xad, 0xbe, 0xef]) });
console.log(new TextDecoder().decode(encoded)); // "deadbeef"

const decoded = hex.decode({ data: new TextEncoder().encode("DEADBEEF") });
console.log(decoded); // Uint8Array(4) [ 222, 173, 190, 239 ]
```

`UniKvs` には `appendTransformer` で登録します。以降に登録するストレージの前段になります。

```ts
import { Hex } from "@unikvs/hex";
import UniKvs from "unikvs";

const kvs = UniKvs.config()
  .appendTransformer(new Hex())
  .appendStorage(storage)
  .create();

await kvs.open();

await kvs.set("data", input);

const output = await kvs.get("data");
```

`set` で hex 化して保存し、`get` で自動的に元のバイト列へ戻します。

## ストリーム [#streams]

単体値とストリームの両方に対応しています。

- 単体値は `encode`・`decode` で変換します。
- ストリーム値は `getEncodable`・`getDecodable` の `TransformStream` で変換します。

`getEncodable` は、入力チャンクをそれぞれ独立に hex 化して順に送出します。

`getDecodable` は、チャンク境界で分割された hex も正しく復元します。

- 空のストリームと長さ 0 のチャンクは値を 1 つも生成せず、エラーにもなりません。
- 終了時に半端な 1 文字が残っている場合は `HexDecodeError` を投げます。
- hex として不正な文字が含まれている場合は、その時点で `HexDecodeError` を投げます。
- 既定では、不正な UTF-8 や途中で切れたマルチバイト文字が含まれている場合は `TypeError` を投げます。詳しくは[エラー](#errors)を参照してください。

```ts
import { Hex } from "@unikvs/hex";

const hex = new Hex();

const source = new ReadableStream({
  start(controller) {
    controller.enqueue(Uint8Array.from([0xde, 0xad]));
    controller.enqueue(Uint8Array.from([0xbe, 0xef]));
    controller.close();
  },
});

const decoded = source.pipeThrough(hex.getEncodable()).pipeThrough(hex.getDecodable());
```

## 注意点 [#notes]

形式の扱いは次のとおりです。

- `0x` の接頭辞は付加も除去もしません。`"0x..."` を渡すと `x` が不正文字として拒否されます。必要な場合は呼び出し側で付け外ししてください。
- 空白・改行・コロンなどの区切りは読み飛ばしません。不正文字として拒否されます。
- 空入力は空出力です。`new Uint8Array(0)` を渡してもエラーになりません。

サイズ（バイト長）は元のサイズのちょうど 2 倍になります。圧縮や暗号化、改ざん検知の目的には使えません。

:::warning
複数の Transformer を組み合わせると、登録順序で結果が変わります。Checksum などと併用する場合は、hex 化と検証のどちらを先に行うか意識して順序を決め、小さいデータで往復を確認してから本番データに適用してください。
:::

## エラー [#errors]

このパッケージが投げるエラーは次のとおりです。

| エラー | 意味 | 対処 |
| --- | --- | --- |
| `HexDecodeError` | hex として解釈できません。奇数長、不正な文字が原因です。 | 入力が偶数長の hex (`0-9`・`a-f`・`A-F` の連続) か確認してください。 |

既定では（一括・ストリームいずれも）、UTF-8 として不正なバイト列は `HexDecodeError` ではなくネイティブの `TypeError` として伝わります。`HexOptions` で `strict: false` の `decoder` を注入した場合は `HexDecodeError` として投げられます。

```ts
import { Hex, HexDecodeError } from "@unikvs/hex";

const hex = new Hex();

try {
  hex.decode({ data: new TextEncoder().encode("abc") });
} catch (error) {
  if (error instanceof HexDecodeError) {
    console.log("hex として解釈できません。");
  } else {
    throw error;
  }
}
```

## 使用例 [#examples]

`Memory` と組み合わせた最小例です。書き込んだ値は hex 化して保存し、読み取り時に自動的に元のバイト列に戻します。

```ts
import { Hex } from "@unikvs/hex";
import { Memory } from "@unikvs/memory";
import UniKvs, { type PlainValue } from "unikvs";

const kvs = UniKvs.config<{ data: PlainValue<Uint8Array<ArrayBuffer>> }>()
  .appendTransformer(new Hex())
  .appendStorage(new Memory())
  .create();

await kvs.open();

const input = Uint8Array.from([0xde, 0xad, 0xbe, 0xef]);
await kvs.set("data", input);

const output = await kvs.get("data");
console.log(output.length === input.length);

await kvs.close();
```
