@pid7/ashwa 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,4 @@
1
1
  [![npm](https://img.shields.io/npm/v/@pid7/ashwa?style=flat-square&logo=npm)](https://www.npmjs.com/package/@pid7/ashwa)
2
- [![Crates.io](https://img.shields.io/crates/v/ashwa?style=flat-square&logo=rust)](https://crates.io/crates/ashwa)
3
2
  [![Tests](https://img.shields.io/github/actions/workflow/status/pid7-org/ashwa/tests.yaml?style=flat-square&logo=github&label=tests)](https://github.com/pid7-org/ashwa/actions/workflows/tests.yaml)
4
3
  [![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue?style=flat-square)](../LICENSE-MIT)
5
4
 
@@ -7,99 +6,196 @@
7
6
 
8
7
  Hardware accelerated routines for single substring search
9
8
 
10
- > [!TIP]
11
- > Package is supported in both Node.js and browser environments.
9
+ > 💡 TIP: `@pid7/ashwa` runs seamlessly across Node.js, Bun, Deno, and modern browser / WebWorker environments.
12
10
 
13
- > [!NOTE]
14
- > The optimal backend (native SIMD bindings for Node / Bun / Deno or WebAssembly SIMD for browsers) is
15
- > automatically selected at runtime.
11
+ > ℹ️ NOTE: The optimal execution backend (native N-API SIMD bindings for Node / Bun / Deno or WebAssembly
12
+ > SIMD for browsers) is automatically detected and selected at runtime with zero manual configuration.
13
+
14
+ ## Index
15
+
16
+ - [Supported Platforms](#supported-platforms)
17
+ - [Installation](#installation)
18
+ - [Usage](#usage)
19
+ - [Node](#node)
20
+ - [Browser](#browser)
21
+ - [API Reference](#api-reference)
22
+ - [`searchOne`](#searchone)
23
+ - [`searchTwo`](#searchtwo)
24
+ - [`init`](#init)
25
+ - [`initSync`](#initsync)
26
+ - [`isNative`](#isnative)
27
+ - [Benchmarks](#benchmarks)
28
+ - [`searchOne`](#searchone-1)
29
+ - [`searchTwo`](#searchtwo-1)
16
30
 
17
31
  ## Supported Platforms
18
32
 
19
- | Architecture | Target Platform | Hardware Acceleration | Fallback |
20
- |:----------------|:---------------------------------------------|:-------------------------------------|:------------|
21
- | x86_64 | Linux, macOS, Windows | AVX-512BW, AVX2, SSE4.2, SSSE3, SSE2 | 64-bit SWAR |
22
- | AArch64 (ARM64) | Apple Silicon, Linux ARM64 | 128-bit ARM NEON | 64-bit SWAR |
23
- | WebAssembly | Browsers, Node.js (`wasm32`) | WASM SIMD128 (`simd128`) | 32-bit SWAR |
33
+ | Architecture | Target Platform | Target ISA | Fallback |
34
+ |:----------------|:---------------------------------------|:-------------------------------------|:------------|
35
+ | x86_64 | Linux, macOS, Windows | AVX-512BW, AVX2, SSE4.2, SSSE3, SSE2 | 64-bit SWAR |
36
+ | AArch64 (ARM64) | Apple Silicon, Linux ARM64 | 128-bit ARM NEON | 64-bit SWAR |
37
+ | WebAssembly | Browsers, WebWorkers, Node.js (wasm32) | WASM SIMD128 (`simd128`) | 32-bit SWAR |
24
38
 
25
- ## Usage
39
+ ## Installation
26
40
 
27
- Install `@pid7/ashwa` via npm:
41
+ Install `@pid7/ashwa` using your preferred package manager:
28
42
 
29
43
  ```bash
30
44
  npm install @pid7/ashwa
31
45
  ```
32
46
 
33
- ## Example
47
+ ## Usage
34
48
 
35
- ### ESM & CommonJS (Node.js, Bun, Deno)
49
+ ### Node
36
50
 
37
- ```javascript
38
- import { searchOne } from '@pid7/ashwa';
51
+ Native N-API bindings execute _synchronously_ with zero overhead and full hardware SIMD acceleration,
39
52
 
40
- const haystack = new TextEncoder().encode("Hello, World! Fast SIMD Search.");
41
- const needle = "W".charCodeAt(0);
53
+ ```js
54
+ import { searchOne, searchTwo } from '@pid7/ashwa';
42
55
 
43
- const index = searchOne(haystack, needle);
44
- console.log(`Found 'W' at byte index: ${index}`);
56
+ const haystack = new TextEncoder().encode("The quick brown fox jumps over the lazy dog");
57
+ const indexOne = searchOne(haystack, "f".charCodeAt(0));
58
+ console.log(`Found 'f' at byte index: ${indexOne}`); // 16
45
59
  ```
46
60
 
47
- ### WASM (Browser / WebWorker)
61
+ ### Browser
48
62
 
49
- > **INFO:**
50
- > In browser/WebWorker environments, WASM automatically initializes on the first call.
63
+ In browser and WebWorker runtimes, WebAssembly SIMD (`simd128`) is used. The WASM module automatically initializes asynchronously on the first search call, or can be pre-warmed during application startup:
51
64
 
52
- ```javascript
53
- import { init, searchOne } from '@pid7/ashwa';
65
+ ```js
66
+ import { init, searchOne, searchTwo } from '@pid7/ashwa';
54
67
 
55
- // Optional pre-initialization of WASM module during app startup
68
+ // Optional pre-init
56
69
  await init();
57
70
 
58
- const index = searchOne(haystack, needle);
71
+ const haystack = new TextEncoder().encode("The quick brown fox jumps over the lazy dog");
72
+ const index = await searchOne(haystack, "f".charCodeAt(0));
73
+ console.log(`Found 'f' at byte index: ${index}`); // 16
59
74
  ```
60
75
 
76
+ ## API Reference
77
+
78
+ ### `searchOne(haystack, needle)`
79
+
80
+ ```ts
81
+ function searchOne(
82
+ haystack: Uint8Array,
83
+ needle: number,
84
+ ): number | null | Promise<number | null>;
85
+ ```
86
+
87
+ Searches for the first occurrence of `needle` (byte value `0`–`255`) within `haystack`.
88
+
89
+ - Parameters:
90
+ - `haystack`: `Uint8Array` / `Buffer` — The byte sequence to search.
91
+ - `needle`: `number` — The target byte value (`0`–`255`) to locate.
92
+ - Returns:
93
+ - In Node.js / Bun / Deno: `number | null` (synchronous 0-based byte index, or `null` if not found).
94
+ - In Browser / WebWorker: `Promise<number | null>` (resolves to 0-based byte index, or `null` if not found).
95
+
96
+ ### `searchTwo(haystack, needle)`
97
+
98
+ ```ts
99
+ function searchTwo(
100
+ haystack: Uint8Array,
101
+ needle: Uint8Array | [number, number] | number[],
102
+ ): number | null | Promise<number | null>;
103
+ ```
104
+
105
+ Searches for the first occurrence of a two-byte `needle` within `haystack`.
106
+
107
+ - Parameters:
108
+ - `haystack`: `Uint8Array` / `Buffer` — The byte sequence to search.
109
+ - `needle`: `Uint8Array | [number, number] | number[]` — A 2-byte sequence to locate.
110
+ - Returns:
111
+ - In Node.js / Bun / Deno: `number | null` (synchronous 0-based byte index, or `null` if not found).
112
+ - In Browser / WebWorker: `Promise<number | null>` (resolves to 0-based byte index, or `null` if not found).
113
+
114
+ ### `init(moduleOrPath?)`
115
+
116
+ ```typescript
117
+ function init(moduleOrPath?: any): Promise<void>;
118
+ ```
119
+
120
+ Asynchronously pre-initializes the WebAssembly module backend for Browser / WebWorker environments. In native Node.js environments (`isNative === true`), this is a no-op that resolves immediately.
121
+
122
+ - Parameters:
123
+ - `moduleOrPath` *(optional)*: `WebAssembly.Module | Response | ArrayBuffer | string` — Custom WASM source or URL.
124
+
125
+ ### `initSync(bytesOrModule?)`
126
+
127
+ ```ts
128
+ function initSync(bytesOrModule?: any): void;
129
+ ```
130
+
131
+ Synchronously initializes the WebAssembly module backend with pre-compiled bytes or a `WebAssembly.Module`. In native Node.js environments, this is a no-op.
132
+
133
+ - Parameters:
134
+ - `bytesOrModule` *(optional)*: `ArrayBuffer | Uint8Array | WebAssembly.Module` — Pre-loaded WASM binary or module.
135
+
136
+ ### `isNative`
137
+
138
+ ```typescript
139
+ const isNative: boolean;
140
+ ```
141
+
142
+ Boolean flag indicating whether `@pid7/ashwa` is executing via native N-API bindings (`true`) or WebAssembly SIMD (`false`).
143
+
61
144
  ## Benchmarks
62
145
 
63
- - [`searchOne`](#searchone)
146
+ - [`searchOne`](#searchone-1)
147
+ - [`searchTwo`](#searchtwo-1)
148
+
149
+ > Benchmarks are evaluated across dedicated AWS EC2 hardware environments on Node.js `v22.23.2`,
150
+ >
151
+ > * x86_64 (_x64_)
152
+ > * Instance: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz (8C/16T)
153
+ > * ISA: _AVX-512BW_ (`+nightly`) · _WASM SIMD128_ (stable)
154
+ > * Cache: L1d: 384 KiB · L1i: 256 KiB · L2: 10 MiB · L3: 54 MiB
155
+ > * STREAM Triad: 20.94 GiB/s
156
+ >
157
+ > * AArch64 (_arm64_)
158
+ > * Instance: AWS Graviton3 ARM Neoverse-V1 (16C/16T)
159
+ > * ISA: _NEON_ (stable)
160
+ > * Cache: L1d: 1 MiB · L1i: 1 MiB · L2: 16 MiB · L3: 32 MiB
161
+ > * STREAM Triad: 75.12 GiB/s
64
162
 
65
163
  ### `searchOne`
66
164
 
67
165
  #### Native Node.js (V8 N-API)
68
166
 
69
- For _x86_64_ machine targeting _AVX-512BW_ SIMD ISA,
167
+ | Level | Payload | Latency (x64) | Latency (arm64) | Throughput (x64) | Throughput (arm64) |
168
+ |:-----------|:----------|:--------------|:----------------|:-----------------|:-------------------|
169
+ | L1 Cache | 32 KiB | 346.28 ns | 743.33 ns | 88.13 GiB/s | 41.06 GiB/s |
170
+ | L2 Cache | 512 KiB | 10.17 µs | 11.25 µs | 47.99 GiB/s | 43.42 GiB/s |
171
+ | L3 Cache | 16 MiB | 552.74 µs | 381.99 µs | 28.27 GiB/s | 40.90 GiB/s |
172
+ | RAM | 256 MiB | 20.22 ms | 9.96 ms | 12.36 GiB/s | 25.10 GiB/s |
70
173
 
71
- | Level | Payload | Latency | Throughput |
72
- |:-----------|:----------|:----------|:-------------|
73
- | L1 Cache | 32 KiB | 640.15 ns | 47.67 GiB/s |
74
- | L2 Cache | 512 KiB | 10.07 µs | 48.51 GiB/s |
75
- | L3 Cache | 16 MiB | 540.35 µs | 28.92 GiB/s |
76
- | RAM | 256 MiB | 23.88 ms | 10.47 GiB/s |
174
+ #### WebAssembly (WASM SIMD128)
77
175
 
78
- Benchmarked using Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz (8C/16T) · L1d: 384 KiB, L1i: 256 KiB, L2: 10 MiB, L3: 54 MiB ·
79
- STREAM Triad: 20.63 GB/s · Node.js v22.23.2
176
+ | Level | Payload | Latency (x64) | Throughput (x64) |
177
+ |:-----------|:----------|:--------------|:-----------------|
178
+ | L1 Cache | 32 KiB | 1.62 µs | 18.82 GiB/s |
179
+ | L2 Cache | 512 KiB | 27.88 µs | 17.51 GiB/s |
180
+ | L3 Cache | 16 MiB | 1.86 ms | 8.38 GiB/s |
181
+ | RAM | 256 MiB | 44.56 ms | 5.61 GiB/s |
80
182
 
81
- For _aarch64_ machine targeting _NEON_ SIMD ISA,
183
+ ### `searchTwo`
82
184
 
83
- | Level | Payload | Latency | Throughput |
84
- |:-----------|:----------|:----------|:-------------|
85
- | L1 Cache | 32 KiB | 743.33 ns | 41.06 GiB/s |
86
- | L2 Cache | 512 KiB | 11.25 µs | 43.42 GiB/s |
87
- | L3 Cache | 16 MiB | 381.99 µs | 40.90 GiB/s |
88
- | RAM | 256 MiB | 9.96 ms | 25.10 GiB/s |
185
+ #### Native Node.js (V8 N-API)
89
186
 
90
- Benchmarked using ARM Neoverse-V1 (16C/16T) · L1d: 1 MiB, L1i: 1 MiB, L2: 16 MiB, L3: 32 MiB ·
91
- STREAM Triad: 75.12 GB/s · Node.js v22.23.2
187
+ | Level | Payload | Latency (x64) | Latency (arm64) | Throughput (x64) | Throughput (arm64) |
188
+ |:-----------|:----------|:--------------|:----------------|:-----------------|:-------------------|
189
+ | L1 Cache | 32 KiB | 647.01 ns | 1.57 µs | 47.17 GiB/s | 19.44 GiB/s |
190
+ | L2 Cache | 512 KiB | 17.41 µs | 24.37 µs | 28.04 GiB/s | 20.03 GiB/s |
191
+ | L3 Cache | 16 MiB | 657.09 µs | 788.85 µs | 23.78 GiB/s | 19.81 GiB/s |
192
+ | RAM | 256 MiB | 22.50 ms | 13.13 ms | 11.11 GiB/s | 19.04 GiB/s |
92
193
 
93
194
  #### WebAssembly (WASM SIMD128)
94
195
 
95
- For _x86_64_ machine targeting _WASM SIMD128_ ISA,
96
-
97
- | Level | Payload | Latency | Throughput |
98
- |:-----------|:----------|:----------|:-------------|
99
- | L1 Cache | 32 KiB | 1.62 µs | 18.79 GiB/s |
100
- | L2 Cache | 512 KiB | 26.81 µs | 18.21 GiB/s |
101
- | L3 Cache | 16 MiB | 1.81 ms | 8.63 GiB/s |
102
- | RAM | 256 MiB | 44.63 ms | 5.60 GiB/s |
103
-
104
- Benchmarked using Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz (8C/16T) ·
105
- L1d: 384 KiB, L1i: 256 KiB, L2: 10 MiB, L3: 54 MiB · STREAM Triad: 20.63 GB/s · Node.js v22.23.2
196
+ | Level | Payload | Latency (x64) | Throughput (x64) |
197
+ |:-----------|:----------|:--------------|:-----------------|
198
+ | L1 Cache | 32 KiB | 2.17 µs | 14.06 GiB/s |
199
+ | L2 Cache | 512 KiB | 35.10 µs | 13.91 GiB/s |
200
+ | L3 Cache | 16 MiB | 3.69 ms | 4.23 GiB/s |
201
+ | RAM | 256 MiB | 51.67 ms | 4.84 GiB/s |
package/browser.js CHANGED
@@ -4,8 +4,8 @@
4
4
  * @module @pid7/ashwa/browser
5
5
  */
6
6
 
7
- const fs = require("fs");
8
- const path = require("path");
7
+ const { readFileSync } = require("fs");
8
+ const { join } = require("path");
9
9
 
10
10
  let wasmModule = null;
11
11
  let initPromise = null;
@@ -27,8 +27,8 @@ async function init(moduleOrPath) {
27
27
  process.versions != null &&
28
28
  process.versions.node != null
29
29
  ) {
30
- const wasmPath = path.join(__dirname, "./wasm/pkg/ashwa_wasm_bg.wasm");
31
- input = fs.readFileSync(wasmPath);
30
+ const wasmPath = join(__dirname, "./wasm/pkg/ashwa_wasm_bg.wasm");
31
+ input = readFileSync(wasmPath);
32
32
  }
33
33
  const initOptions = input ? { module_or_path: input } : undefined;
34
34
  initPromise = Promise.resolve(wasm.default(initOptions)).then(() => {
@@ -54,8 +54,8 @@ function initSync(bytesOrModule) {
54
54
  process.versions != null &&
55
55
  process.versions.node != null
56
56
  ) {
57
- const wasmPath = path.join(__dirname, "./wasm/pkg/ashwa_wasm_bg.wasm");
58
- input = fs.readFileSync(wasmPath);
57
+ const wasmPath = join(__dirname, "./wasm/pkg/ashwa_wasm_bg.wasm");
58
+ input = readFileSync(wasmPath);
59
59
  }
60
60
  wasm.initSync(input);
61
61
  wasmModule = wasm;
@@ -77,6 +77,26 @@ async function searchOne(haystack, needle) {
77
77
  return res !== undefined && res !== null ? Number(res) : null;
78
78
  }
79
79
 
80
+ /**
81
+ * Searches for the first occurrence of a two-byte `needle` in `haystack` via WebAssembly SIMD.
82
+ * Automatically initializes WASM if not already loaded.
83
+ *
84
+ * @param {Uint8Array} haystack - Byte array to search.
85
+ * @param {Uint8Array|number[]} needle - 2-byte sequence to locate.
86
+ * @returns {Promise<number|null>} Resolves to 0-based matching index or null if not found.
87
+ */
88
+ async function searchTwo(haystack, needle) {
89
+ const n = Array.isArray(needle) ? new Uint8Array(needle) : needle;
90
+ if (n == null || n.length !== 2) {
91
+ throw new TypeError("needle must be a 2-byte sequence");
92
+ }
93
+ if (!wasmModule) {
94
+ await init();
95
+ }
96
+ const res = wasmModule.searchTwo(haystack, n);
97
+ return res !== undefined && res !== null ? Number(res) : null;
98
+ }
99
+
80
100
  module.exports = {
81
101
  /**
82
102
  * `false` indicating WebAssembly execution mode.
@@ -85,4 +105,5 @@ module.exports = {
85
105
  init,
86
106
  initSync,
87
107
  searchOne,
108
+ searchTwo,
88
109
  };
package/browser.mjs CHANGED
@@ -9,6 +9,7 @@ import { fileURLToPath } from "node:url";
9
9
  import initWasm, {
10
10
  initSync as wasmInitSync,
11
11
  searchOne as wasmSearchOne,
12
+ searchTwo as wasmSearchTwo,
12
13
  } from "./wasm/pkg/ashwa_wasm.js";
13
14
 
14
15
  let isInitialized = false;
@@ -36,15 +37,17 @@ export async function init(moduleOrPath) {
36
37
  process.versions.node != null
37
38
  ) {
38
39
  const wasmPath = fileURLToPath(
39
- new URL("./wasm/pkg/ashwa_wasm_bg.wasm", import.meta.url)
40
+ new URL("./wasm/pkg/ashwa_wasm_bg.wasm", import.meta.url),
40
41
  );
41
42
  input = fs.readFileSync(wasmPath);
42
43
  }
44
+
43
45
  const options = input ? { module_or_path: input } : undefined;
44
46
  initPromise = initWasm(options).then(() => {
45
47
  isInitialized = true;
46
48
  });
47
49
  }
50
+
48
51
  await initPromise;
49
52
  }
50
53
 
@@ -62,10 +65,12 @@ export function initSync(bytesOrModule) {
62
65
  process.versions.node != null
63
66
  ) {
64
67
  const wasmPath = fileURLToPath(
65
- new URL("./wasm/pkg/ashwa_wasm_bg.wasm", import.meta.url)
68
+ new URL("./wasm/pkg/ashwa_wasm_bg.wasm", import.meta.url),
66
69
  );
70
+
67
71
  input = fs.readFileSync(wasmPath);
68
72
  }
73
+
69
74
  wasmInitSync(input);
70
75
  isInitialized = true;
71
76
  }
@@ -82,6 +87,29 @@ export async function searchOne(haystack, needle) {
82
87
  if (!isInitialized) {
83
88
  await init();
84
89
  }
90
+
85
91
  const res = wasmSearchOne(haystack, needle);
86
92
  return res !== undefined && res !== null ? Number(res) : null;
87
93
  }
94
+
95
+ /**
96
+ * Searches for the first occurrence of a two-byte `needle` in `haystack` via WebAssembly SIMD.
97
+ * Automatically initializes WASM if not already loaded.
98
+ *
99
+ * @param {Uint8Array} haystack - Byte array to search.
100
+ * @param {Uint8Array|number[]} needle - 2-byte sequence to locate.
101
+ * @returns {Promise<number|null>} Resolves to 0-based matching index or null if not found.
102
+ */
103
+ export async function searchTwo(haystack, needle) {
104
+ const n = Array.isArray(needle) ? new Uint8Array(needle) : needle;
105
+ if (n == null || n.length !== 2) {
106
+ throw new TypeError("needle must be a 2-byte sequence");
107
+ }
108
+
109
+ if (!isInitialized) {
110
+ await init();
111
+ }
112
+
113
+ const res = wasmSearchTwo(haystack, n);
114
+ return res !== undefined && res !== null ? Number(res) : null;
115
+ }
package/index.d.ts CHANGED
@@ -26,7 +26,33 @@
26
26
  */
27
27
  export function searchOne(
28
28
  haystack: Uint8Array,
29
- needle: number
29
+ needle: number,
30
+ ): number | null | Promise<number | null>;
31
+
32
+ /**
33
+ * Searches for the first occurrence of a two-byte `needle` within `haystack` (Uint8Array / Buffer).
34
+ *
35
+ * Execution backend:
36
+ * - **Node.js / Bun / Deno**: Executes synchronously via N-API native bindings with SIMD vectorization (AVX-512BW, AVX2, SSE4.2, SSSE3, SSE2, ARM NEON).
37
+ * - **Browser / WebWorker**: Executes via WebAssembly SIMD (`simd128`), automatically initializing the WASM module on first invocation if not already loaded.
38
+ *
39
+ * @param haystack - The byte array/buffer to search.
40
+ * @param needle - A 2-byte sequence (`Uint8Array`, `Buffer`, or `[number, number]` / `number[]`) to locate.
41
+ * @returns The 0-based byte index of the first occurrence of `needle`, or `null` if not found.
42
+ *
43
+ * @example
44
+ * ```javascript
45
+ * import { searchTwo } from '@pid7/ashwa';
46
+ *
47
+ * const haystack = new TextEncoder().encode("Hello, World!");
48
+ * const needle = new Uint8Array(["W".charCodeAt(0), "o".charCodeAt(0)]);
49
+ * const index = await searchTwo(haystack, needle);
50
+ * console.log(index); // 7
51
+ * ```
52
+ */
53
+ export function searchTwo(
54
+ haystack: Uint8Array,
55
+ needle: Uint8Array | [number, number] | number[],
30
56
  ): number | null | Promise<number | null>;
31
57
 
32
58
  /**
package/index.js CHANGED
@@ -41,6 +41,23 @@ if (isNode) {
41
41
  const res = native.searchOne(haystack, needle);
42
42
  return res !== undefined && res !== null ? Number(res) : null;
43
43
  },
44
+
45
+ /**
46
+ * Searches for the first occurrence of a two-byte `needle` in `haystack`.
47
+ *
48
+ * @param {Uint8Array} haystack - Byte array to search.
49
+ * @param {Uint8Array|number[]} needle - 2-byte sequence to locate.
50
+ * @returns {number|null} 0-based index or null if not found.
51
+ */
52
+ searchTwo(haystack, needle) {
53
+ const n = Array.isArray(needle) ? new Uint8Array(needle) : needle;
54
+ if (n == null || n.length !== 2) {
55
+ throw new TypeError("needle must be a 2-byte sequence");
56
+ }
57
+
58
+ const res = native.searchTwo(haystack, n);
59
+ return res !== undefined && res !== null ? Number(res) : null;
60
+ },
44
61
  };
45
62
  } else {
46
63
  module.exports = require("./browser.js");
package/index.mjs CHANGED
@@ -36,3 +36,20 @@ export function searchOne(haystack, needle) {
36
36
  const res = native.searchOne(haystack, needle);
37
37
  return res !== undefined && res !== null ? Number(res) : null;
38
38
  }
39
+
40
+ /**
41
+ * Searches for the first occurrence of a two-byte `needle` in `haystack`.
42
+ *
43
+ * @param {Uint8Array} haystack - Byte array to search.
44
+ * @param {Uint8Array|number[]} needle - 2-byte sequence to locate.
45
+ * @returns {number|null} 0-based index or null if not found.
46
+ */
47
+ export function searchTwo(haystack, needle) {
48
+ const n = Array.isArray(needle) ? new Uint8Array(needle) : needle;
49
+ if (n == null || n.length !== 2) {
50
+ throw new TypeError("needle must be a 2-byte sequence");
51
+ }
52
+
53
+ const res = native.searchTwo(haystack, n);
54
+ return res !== undefined && res !== null ? Number(res) : null;
55
+ }
package/native/index.d.ts CHANGED
@@ -1,3 +1,33 @@
1
1
  /* auto-generated by NAPI-RS */
2
2
  /* eslint-disable */
3
- export declare function searchOne(haystack: Uint8Array, needle: number): number | null
3
+ /**
4
+ * Searches for the first occurrence of `needle` in `haystack`.
5
+ *
6
+ * # Arguments
7
+ * * `haystack` - A byte slice (`&[u8]`) to search within.
8
+ * * `needle` - The byte (`u8`) to find.
9
+ *
10
+ * # Returns
11
+ * * `Some(index)` - The 0-based byte index of the first match.
12
+ * * `None` - If `needle` is not found.
13
+ */
14
+ export declare function searchOne(
15
+ haystack: Uint8Array,
16
+ needle: number,
17
+ ): number | null;
18
+
19
+ /**
20
+ * Searches for the first occurrence of a two-byte `needle` in `haystack`.
21
+ *
22
+ * # Arguments
23
+ * * `haystack` - A byte slice (`&[u8]`) to search within.
24
+ * * `needle` - A 2-byte slice (`&[u8]`) to locate.
25
+ *
26
+ * # Returns
27
+ * * `Some(index)` - The 0-based byte index of the first match.
28
+ * * `None` - If `needle` is not found.
29
+ */
30
+ export declare function searchTwo(
31
+ haystack: Uint8Array,
32
+ needle: Uint8Array,
33
+ ): number | null;
Binary file