@bcts/envelope-pattern 1.0.0-alpha.12

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.
Files changed (53) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +13 -0
  3. package/dist/index.cjs +6781 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +2628 -0
  6. package/dist/index.d.cts.map +1 -0
  7. package/dist/index.d.mts +2628 -0
  8. package/dist/index.d.mts.map +1 -0
  9. package/dist/index.iife.js +6781 -0
  10. package/dist/index.iife.js.map +1 -0
  11. package/dist/index.mjs +6545 -0
  12. package/dist/index.mjs.map +1 -0
  13. package/package.json +77 -0
  14. package/src/error.ts +262 -0
  15. package/src/format.ts +375 -0
  16. package/src/index.ts +27 -0
  17. package/src/parse/index.ts +923 -0
  18. package/src/parse/token.ts +906 -0
  19. package/src/parse/utils.ts +339 -0
  20. package/src/pattern/index.ts +719 -0
  21. package/src/pattern/leaf/array-pattern.ts +273 -0
  22. package/src/pattern/leaf/bool-pattern.ts +140 -0
  23. package/src/pattern/leaf/byte-string-pattern.ts +172 -0
  24. package/src/pattern/leaf/cbor-pattern.ts +355 -0
  25. package/src/pattern/leaf/date-pattern.ts +178 -0
  26. package/src/pattern/leaf/index.ts +280 -0
  27. package/src/pattern/leaf/known-value-pattern.ts +192 -0
  28. package/src/pattern/leaf/map-pattern.ts +152 -0
  29. package/src/pattern/leaf/null-pattern.ts +110 -0
  30. package/src/pattern/leaf/number-pattern.ts +248 -0
  31. package/src/pattern/leaf/tagged-pattern.ts +228 -0
  32. package/src/pattern/leaf/text-pattern.ts +165 -0
  33. package/src/pattern/matcher.ts +88 -0
  34. package/src/pattern/meta/and-pattern.ts +109 -0
  35. package/src/pattern/meta/any-pattern.ts +81 -0
  36. package/src/pattern/meta/capture-pattern.ts +111 -0
  37. package/src/pattern/meta/group-pattern.ts +110 -0
  38. package/src/pattern/meta/index.ts +269 -0
  39. package/src/pattern/meta/not-pattern.ts +91 -0
  40. package/src/pattern/meta/or-pattern.ts +146 -0
  41. package/src/pattern/meta/search-pattern.ts +201 -0
  42. package/src/pattern/meta/traverse-pattern.ts +146 -0
  43. package/src/pattern/structure/assertions-pattern.ts +244 -0
  44. package/src/pattern/structure/digest-pattern.ts +225 -0
  45. package/src/pattern/structure/index.ts +272 -0
  46. package/src/pattern/structure/leaf-structure-pattern.ts +85 -0
  47. package/src/pattern/structure/node-pattern.ts +188 -0
  48. package/src/pattern/structure/object-pattern.ts +149 -0
  49. package/src/pattern/structure/obscured-pattern.ts +159 -0
  50. package/src/pattern/structure/predicate-pattern.ts +151 -0
  51. package/src/pattern/structure/subject-pattern.ts +152 -0
  52. package/src/pattern/structure/wrapped-pattern.ts +195 -0
  53. package/src/pattern/vm.ts +1021 -0
@@ -0,0 +1,273 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Array pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust array_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/leaf/array-pattern
7
+ */
8
+
9
+ import { Envelope } from "@bcts/envelope";
10
+ import { asCborArray, type Cbor } from "@bcts/dcbor";
11
+ import {
12
+ type Pattern as DCBORPattern,
13
+ Interval,
14
+ patternPathsWithCaptures as dcborPatternPathsWithCaptures,
15
+ patternDisplay as dcborPatternDisplay,
16
+ } from "@bcts/dcbor-pattern";
17
+ import type { Path } from "../../format";
18
+ import type { Matcher } from "../matcher";
19
+ import { compileAsAtomic } from "../matcher";
20
+ import type { Instr } from "../vm";
21
+ import type { Pattern } from "../index";
22
+
23
+ // Forward declaration for Pattern factory
24
+ let createLeafArrayPattern: ((pattern: ArrayPattern) => Pattern) | undefined;
25
+
26
+ export function registerArrayPatternFactory(factory: (pattern: ArrayPattern) => Pattern): void {
27
+ createLeafArrayPattern = factory;
28
+ }
29
+
30
+ /**
31
+ * Pattern for matching array values.
32
+ *
33
+ * Corresponds to the Rust `ArrayPattern` enum in array_pattern.rs
34
+ */
35
+ export type ArrayPatternType =
36
+ | { readonly type: "Any" }
37
+ | { readonly type: "Interval"; readonly interval: Interval }
38
+ | { readonly type: "DCBORPattern"; readonly pattern: DCBORPattern }
39
+ | { readonly type: "WithPatterns"; readonly patterns: Pattern[] };
40
+
41
+ /**
42
+ * Pattern for matching array values in envelope leaf nodes.
43
+ *
44
+ * Corresponds to the Rust `ArrayPattern` struct in array_pattern.rs
45
+ */
46
+ export class ArrayPattern implements Matcher {
47
+ readonly #pattern: ArrayPatternType;
48
+
49
+ private constructor(pattern: ArrayPatternType) {
50
+ this.#pattern = pattern;
51
+ }
52
+
53
+ /**
54
+ * Creates a new ArrayPattern that matches any array.
55
+ */
56
+ static any(): ArrayPattern {
57
+ return new ArrayPattern({ type: "Any" });
58
+ }
59
+
60
+ /**
61
+ * Creates a new ArrayPattern that matches arrays with a specific length.
62
+ */
63
+ static count(count: number): ArrayPattern {
64
+ return new ArrayPattern({
65
+ type: "Interval",
66
+ interval: Interval.exactly(count),
67
+ });
68
+ }
69
+
70
+ /**
71
+ * Creates a new ArrayPattern that matches arrays within a length range.
72
+ */
73
+ static interval(min: number, max?: number): ArrayPattern {
74
+ const interval = max !== undefined ? Interval.from(min, max) : Interval.atLeast(min);
75
+ return new ArrayPattern({ type: "Interval", interval });
76
+ }
77
+
78
+ /**
79
+ * Creates a new ArrayPattern from a dcbor-pattern.
80
+ */
81
+ static fromDcborPattern(dcborPattern: DCBORPattern): ArrayPattern {
82
+ return new ArrayPattern({ type: "DCBORPattern", pattern: dcborPattern });
83
+ }
84
+
85
+ /**
86
+ * Creates a new ArrayPattern with envelope patterns for element matching.
87
+ */
88
+ static withPatterns(patterns: Pattern[]): ArrayPattern {
89
+ return new ArrayPattern({ type: "WithPatterns", patterns });
90
+ }
91
+
92
+ /**
93
+ * Gets the pattern type.
94
+ */
95
+ get pattern(): ArrayPatternType {
96
+ return this.#pattern;
97
+ }
98
+
99
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
100
+ // Try to extract CBOR from the envelope
101
+ const cbor = haystack.asLeaf();
102
+ if (cbor === undefined) {
103
+ return [[], new Map<string, Path[]>()];
104
+ }
105
+
106
+ // Check if it's an array
107
+ const array = asCborArray(cbor);
108
+ if (array === undefined) {
109
+ return [[], new Map<string, Path[]>()];
110
+ }
111
+
112
+ switch (this.#pattern.type) {
113
+ case "Any":
114
+ return [[[haystack]], new Map<string, Path[]>()];
115
+
116
+ case "Interval": {
117
+ const length = array.length;
118
+ if (this.#pattern.interval.contains(length)) {
119
+ return [[[haystack]], new Map<string, Path[]>()];
120
+ }
121
+ return [[], new Map<string, Path[]>()];
122
+ }
123
+
124
+ case "DCBORPattern": {
125
+ // Delegate to dcbor-pattern for matching
126
+ const { paths: dcborPaths, captures: dcborCaptures } = dcborPatternPathsWithCaptures(
127
+ this.#pattern.pattern,
128
+ cbor,
129
+ );
130
+
131
+ if (dcborPaths.length > 0) {
132
+ // Convert dcbor paths to envelope paths
133
+ const envelopePaths: Path[] = dcborPaths.map((dcborPath: Cbor[]) => {
134
+ const envPath: Path = [haystack];
135
+ // Skip the first element (root) and convert rest to envelopes
136
+ for (let i = 1; i < dcborPath.length; i++) {
137
+ const elem = dcborPath[i];
138
+ if (elem !== undefined) {
139
+ envPath.push(Envelope.newLeaf(elem));
140
+ }
141
+ }
142
+ return envPath;
143
+ });
144
+
145
+ // Convert dcbor captures to envelope captures
146
+ const envelopeCaptures = new Map<string, Path[]>();
147
+ for (const [name, capturePaths] of dcborCaptures) {
148
+ const envCapturePaths: Path[] = capturePaths.map((dcborPath: Cbor[]) => {
149
+ const envPath: Path = [haystack];
150
+ for (let i = 1; i < dcborPath.length; i++) {
151
+ const elem = dcborPath[i];
152
+ if (elem !== undefined) {
153
+ envPath.push(Envelope.newLeaf(elem));
154
+ }
155
+ }
156
+ return envPath;
157
+ });
158
+ envelopeCaptures.set(name, envCapturePaths);
159
+ }
160
+
161
+ return [envelopePaths, envelopeCaptures];
162
+ }
163
+
164
+ return [[], new Map<string, Path[]>()];
165
+ }
166
+
167
+ case "WithPatterns":
168
+ // For envelope patterns, match if array length equals patterns count
169
+ // Full element-by-element matching would require additional implementation
170
+ if (array.length === this.#pattern.patterns.length) {
171
+ return [[[haystack]], new Map<string, Path[]>()];
172
+ }
173
+ return [[], new Map<string, Path[]>()];
174
+ }
175
+ }
176
+
177
+ paths(haystack: Envelope): Path[] {
178
+ return this.pathsWithCaptures(haystack)[0];
179
+ }
180
+
181
+ matches(haystack: Envelope): boolean {
182
+ return this.paths(haystack).length > 0;
183
+ }
184
+
185
+ compile(code: Instr[], literals: Pattern[], captures: string[]): void {
186
+ if (createLeafArrayPattern === undefined) {
187
+ throw new Error("ArrayPattern factory not registered");
188
+ }
189
+ compileAsAtomic(createLeafArrayPattern(this), code, literals, captures);
190
+ }
191
+
192
+ isComplex(): boolean {
193
+ return false;
194
+ }
195
+
196
+ toString(): string {
197
+ switch (this.#pattern.type) {
198
+ case "Any":
199
+ return "[*]";
200
+ case "Interval":
201
+ return `[{${this.#pattern.interval.toString()}}]`;
202
+ case "DCBORPattern":
203
+ return dcborPatternDisplay(this.#pattern.pattern);
204
+ case "WithPatterns":
205
+ return `[${this.#pattern.patterns.map(String).join(", ")}]`;
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Equality comparison.
211
+ */
212
+ equals(other: ArrayPattern): boolean {
213
+ if (this.#pattern.type !== other.#pattern.type) {
214
+ return false;
215
+ }
216
+ switch (this.#pattern.type) {
217
+ case "Any":
218
+ return true;
219
+ case "Interval":
220
+ return this.#pattern.interval.equals(
221
+ (other.#pattern as { type: "Interval"; interval: Interval }).interval,
222
+ );
223
+ case "DCBORPattern":
224
+ // Compare using display representation
225
+ return (
226
+ dcborPatternDisplay(this.#pattern.pattern) ===
227
+ dcborPatternDisplay(
228
+ (other.#pattern as { type: "DCBORPattern"; pattern: DCBORPattern }).pattern,
229
+ )
230
+ );
231
+ case "WithPatterns": {
232
+ const otherPatterns = (other.#pattern as { type: "WithPatterns"; patterns: Pattern[] })
233
+ .patterns;
234
+ if (this.#pattern.patterns.length !== otherPatterns.length) return false;
235
+ for (let i = 0; i < this.#pattern.patterns.length; i++) {
236
+ if (this.#pattern.patterns[i] !== otherPatterns[i]) return false;
237
+ }
238
+ return true;
239
+ }
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Hash code for use in Maps/Sets.
245
+ */
246
+ hashCode(): number {
247
+ switch (this.#pattern.type) {
248
+ case "Any":
249
+ return 0;
250
+ case "Interval":
251
+ // Simple hash based on min/max
252
+ return this.#pattern.interval.min() * 31 + (this.#pattern.interval.max() ?? 0);
253
+ case "DCBORPattern":
254
+ // Simple hash based on display string
255
+ return simpleStringHash(dcborPatternDisplay(this.#pattern.pattern));
256
+ case "WithPatterns":
257
+ return this.#pattern.patterns.length;
258
+ }
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Simple string hash function for hashCode implementations.
264
+ */
265
+ function simpleStringHash(str: string): number {
266
+ let hash = 0;
267
+ for (let i = 0; i < str.length; i++) {
268
+ const char = str.charCodeAt(i);
269
+ hash = (hash << 5) - hash + char;
270
+ hash = hash & hash; // Convert to 32-bit integer
271
+ }
272
+ return hash;
273
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Boolean pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust bool_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/leaf/bool-pattern
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import {
11
+ type BoolPattern as DCBORBoolPattern,
12
+ boolPatternAny,
13
+ boolPatternValue,
14
+ boolPatternPaths as dcborBoolPatternPaths,
15
+ boolPatternDisplay,
16
+ } from "@bcts/dcbor-pattern";
17
+ import type { Path } from "../../format";
18
+ import type { Matcher } from "../matcher";
19
+ import { compileAsAtomic } from "../matcher";
20
+ import type { Instr } from "../vm";
21
+ import type { Pattern } from "../index";
22
+
23
+ // Forward declaration for Pattern factory
24
+ let createLeafBoolPattern: ((pattern: BoolPattern) => Pattern) | undefined;
25
+
26
+ export function registerBoolPatternFactory(factory: (pattern: BoolPattern) => Pattern): void {
27
+ createLeafBoolPattern = factory;
28
+ }
29
+
30
+ /**
31
+ * Pattern for matching boolean values.
32
+ *
33
+ * This is a wrapper around dcbor_pattern::BoolPattern that provides
34
+ * envelope-specific integration.
35
+ *
36
+ * Corresponds to the Rust `BoolPattern` struct in bool_pattern.rs
37
+ */
38
+ export class BoolPattern implements Matcher {
39
+ readonly #inner: DCBORBoolPattern;
40
+
41
+ private constructor(inner: DCBORBoolPattern) {
42
+ this.#inner = inner;
43
+ }
44
+
45
+ /**
46
+ * Creates a new BoolPattern that matches any boolean value.
47
+ */
48
+ static any(): BoolPattern {
49
+ return new BoolPattern(boolPatternAny());
50
+ }
51
+
52
+ /**
53
+ * Creates a new BoolPattern that matches the specific boolean value.
54
+ */
55
+ static value(value: boolean): BoolPattern {
56
+ return new BoolPattern(boolPatternValue(value));
57
+ }
58
+
59
+ /**
60
+ * Creates a new BoolPattern from a dcbor-pattern BoolPattern.
61
+ */
62
+ static fromDcborPattern(dcborPattern: DCBORBoolPattern): BoolPattern {
63
+ return new BoolPattern(dcborPattern);
64
+ }
65
+
66
+ /**
67
+ * Gets the underlying dcbor-pattern BoolPattern.
68
+ */
69
+ get inner(): DCBORBoolPattern {
70
+ return this.#inner;
71
+ }
72
+
73
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
74
+ // For leaf envelopes, extract the CBOR and delegate to dcbor-pattern
75
+ const cbor = haystack.asLeaf();
76
+ if (cbor !== undefined) {
77
+ // Delegate to dcbor-pattern for CBOR matching
78
+ const dcborPaths = dcborBoolPatternPaths(this.#inner, cbor);
79
+
80
+ // For simple leaf patterns, if dcbor-pattern found matches, return the envelope
81
+ if (dcborPaths.length > 0) {
82
+ const envelopePaths: Path[] = [[haystack]];
83
+ const envelopeCaptures = new Map<string, Path[]>();
84
+ return [envelopePaths, envelopeCaptures];
85
+ }
86
+ }
87
+
88
+ // Not a leaf envelope or no match
89
+ return [[], new Map<string, Path[]>()];
90
+ }
91
+
92
+ paths(haystack: Envelope): Path[] {
93
+ return this.pathsWithCaptures(haystack)[0];
94
+ }
95
+
96
+ matches(haystack: Envelope): boolean {
97
+ return this.paths(haystack).length > 0;
98
+ }
99
+
100
+ compile(code: Instr[], literals: Pattern[], captures: string[]): void {
101
+ if (createLeafBoolPattern === undefined) {
102
+ throw new Error("BoolPattern factory not registered");
103
+ }
104
+ compileAsAtomic(createLeafBoolPattern(this), code, literals, captures);
105
+ }
106
+
107
+ isComplex(): boolean {
108
+ return false;
109
+ }
110
+
111
+ toString(): string {
112
+ return boolPatternDisplay(this.#inner);
113
+ }
114
+
115
+ /**
116
+ * Equality comparison.
117
+ */
118
+ equals(other: BoolPattern): boolean {
119
+ // Compare by variant and value
120
+ if (this.#inner.variant !== other.#inner.variant) {
121
+ return false;
122
+ }
123
+ if (this.#inner.variant === "Value" && other.#inner.variant === "Value") {
124
+ return this.#inner.value === other.#inner.value;
125
+ }
126
+ return true;
127
+ }
128
+
129
+ /**
130
+ * Hash code for use in Maps/Sets.
131
+ */
132
+ hashCode(): number {
133
+ // Simple hash based on variant and value
134
+ let hash = this.#inner.variant === "Any" ? 0 : 1;
135
+ if (this.#inner.variant === "Value") {
136
+ hash = hash * 31 + (this.#inner.value ? 1 : 0);
137
+ }
138
+ return hash;
139
+ }
140
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * @bcts/envelope-pattern - Byte string pattern matching
3
+ *
4
+ * This is a 1:1 TypeScript port of bc-envelope-pattern-rust byte_string_pattern.rs
5
+ *
6
+ * @module envelope-pattern/pattern/leaf/byte-string-pattern
7
+ */
8
+
9
+ import type { Envelope } from "@bcts/envelope";
10
+ import {
11
+ type ByteStringPattern as DCBORByteStringPattern,
12
+ byteStringPatternAny,
13
+ byteStringPatternValue,
14
+ byteStringPatternBinaryRegex,
15
+ byteStringPatternPaths as dcborByteStringPatternPaths,
16
+ byteStringPatternDisplay,
17
+ } from "@bcts/dcbor-pattern";
18
+ import type { Path } from "../../format";
19
+ import type { Matcher } from "../matcher";
20
+ import { compileAsAtomic } from "../matcher";
21
+ import type { Instr } from "../vm";
22
+ import type { Pattern } from "../index";
23
+
24
+ // Forward declaration for Pattern factory
25
+ let createLeafByteStringPattern: ((pattern: ByteStringPattern) => Pattern) | undefined;
26
+
27
+ export function registerByteStringPatternFactory(
28
+ factory: (pattern: ByteStringPattern) => Pattern,
29
+ ): void {
30
+ createLeafByteStringPattern = factory;
31
+ }
32
+
33
+ /**
34
+ * Pattern for matching byte string values.
35
+ *
36
+ * This is a wrapper around dcbor_pattern::ByteStringPattern that provides
37
+ * envelope-specific integration.
38
+ *
39
+ * Corresponds to the Rust `ByteStringPattern` struct in byte_string_pattern.rs
40
+ */
41
+ export class ByteStringPattern implements Matcher {
42
+ readonly #inner: DCBORByteStringPattern;
43
+
44
+ private constructor(inner: DCBORByteStringPattern) {
45
+ this.#inner = inner;
46
+ }
47
+
48
+ /**
49
+ * Creates a new ByteStringPattern that matches any byte string.
50
+ */
51
+ static any(): ByteStringPattern {
52
+ return new ByteStringPattern(byteStringPatternAny());
53
+ }
54
+
55
+ /**
56
+ * Creates a new ByteStringPattern that matches the specific byte string.
57
+ */
58
+ static value(value: Uint8Array): ByteStringPattern {
59
+ return new ByteStringPattern(byteStringPatternValue(value));
60
+ }
61
+
62
+ /**
63
+ * Creates a new ByteStringPattern that matches byte strings matching the binary regex.
64
+ */
65
+ static regex(pattern: RegExp): ByteStringPattern {
66
+ return new ByteStringPattern(byteStringPatternBinaryRegex(pattern));
67
+ }
68
+
69
+ /**
70
+ * Creates a new ByteStringPattern from a dcbor-pattern ByteStringPattern.
71
+ */
72
+ static fromDcborPattern(dcborPattern: DCBORByteStringPattern): ByteStringPattern {
73
+ return new ByteStringPattern(dcborPattern);
74
+ }
75
+
76
+ /**
77
+ * Gets the underlying dcbor-pattern ByteStringPattern.
78
+ */
79
+ get inner(): DCBORByteStringPattern {
80
+ return this.#inner;
81
+ }
82
+
83
+ pathsWithCaptures(haystack: Envelope): [Path[], Map<string, Path[]>] {
84
+ // For leaf envelopes, extract the CBOR and delegate to dcbor-pattern
85
+ const cbor = haystack.asLeaf();
86
+ if (cbor !== undefined) {
87
+ // Delegate to dcbor-pattern for CBOR matching
88
+ const dcborPaths = dcborByteStringPatternPaths(this.#inner, cbor);
89
+
90
+ // For simple leaf patterns, if dcbor-pattern found matches, return the envelope
91
+ if (dcborPaths.length > 0) {
92
+ const envelopePaths: Path[] = [[haystack]];
93
+ return [envelopePaths, new Map<string, Path[]>()];
94
+ }
95
+ }
96
+
97
+ return [[], new Map<string, Path[]>()];
98
+ }
99
+
100
+ paths(haystack: Envelope): Path[] {
101
+ return this.pathsWithCaptures(haystack)[0];
102
+ }
103
+
104
+ matches(haystack: Envelope): boolean {
105
+ return this.paths(haystack).length > 0;
106
+ }
107
+
108
+ compile(code: Instr[], literals: Pattern[], captures: string[]): void {
109
+ if (createLeafByteStringPattern === undefined) {
110
+ throw new Error("ByteStringPattern factory not registered");
111
+ }
112
+ compileAsAtomic(createLeafByteStringPattern(this), code, literals, captures);
113
+ }
114
+
115
+ isComplex(): boolean {
116
+ return false;
117
+ }
118
+
119
+ toString(): string {
120
+ return byteStringPatternDisplay(this.#inner);
121
+ }
122
+
123
+ /**
124
+ * Equality comparison.
125
+ */
126
+ equals(other: ByteStringPattern): boolean {
127
+ if (this.#inner.variant !== other.#inner.variant) {
128
+ return false;
129
+ }
130
+ switch (this.#inner.variant) {
131
+ case "Any":
132
+ return true;
133
+ case "Value": {
134
+ const a = (this.#inner as { value: Uint8Array }).value;
135
+ const b = (other.#inner as { value: Uint8Array }).value;
136
+ if (a.length !== b.length) return false;
137
+ for (let i = 0; i < a.length; i++) {
138
+ if (a[i] !== b[i]) return false;
139
+ }
140
+ return true;
141
+ }
142
+ case "BinaryRegex":
143
+ return (
144
+ (this.#inner as { pattern: RegExp }).pattern.source ===
145
+ (other.#inner as { pattern: RegExp }).pattern.source
146
+ );
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Hash code for use in Maps/Sets.
152
+ */
153
+ hashCode(): number {
154
+ let hash = 0;
155
+ switch (this.#inner.variant) {
156
+ case "Any":
157
+ hash = 1;
158
+ break;
159
+ case "Value": {
160
+ const val = (this.#inner as { value: Uint8Array }).value;
161
+ for (const byte of val) {
162
+ hash = hash * 31 + byte;
163
+ }
164
+ break;
165
+ }
166
+ case "BinaryRegex":
167
+ hash = 3 * 31 + (this.#inner as { pattern: RegExp }).pattern.source.length;
168
+ break;
169
+ }
170
+ return hash;
171
+ }
172
+ }