happy-rusty 1.9.0 → 1.9.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/dist/main.cjs CHANGED
@@ -1,1507 +1,2308 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/core/option/symbols.ts
3
+ /**
4
+ * @module
5
+ * Internal symbol used to identify `Option` type variants.
6
+ *
7
+ * This symbol is used as a property key to distinguish between `Some` and `None` variants.
8
+ * It provides a reliable way to identify the variant of an `Option` instance without
9
+ * relying on method calls or duck typing.
10
+ *
11
+ * Note: This symbol is an internal implementation detail and is not exported as part of the public API.
12
+ * Use the `isOption` utility function for type checking instead.
13
+ */
14
+ /**
15
+ * A unique symbol used as a property key to identify the variant of an `Option` instance.
16
+ *
17
+ * When accessed on an `Option`, returns `'Some'` if the Option contains a value,
18
+ * or `'None'` if it represents the absence of a value.
19
+ *
20
+ * This symbol is used internally by the `isOption` utility function to verify
21
+ * that an object is a valid `Option` instance.
22
+ *
23
+ * @internal
24
+ */
5
25
  const OptionKindSymbol = /* @__PURE__ */ Symbol("Option kind");
6
-
26
+ //#endregion
27
+ //#region src/core/option/guards.ts
28
+ /**
29
+ * Checks if a value is an `Option`.
30
+ *
31
+ * @typeParam T - The expected type of the value contained within the `Option`.
32
+ * @param o - The value to be checked as an `Option`.
33
+ * @returns `true` if the value is an `Option`, otherwise `false`.
34
+ * @since 1.2.0
35
+ * @example
36
+ * ```ts
37
+ * const x = Some(5);
38
+ * console.log(isOption(x)); // true
39
+ * console.log(isOption(null)); // false
40
+ * console.log(isOption({ value: 5 })); // false
41
+ * ```
42
+ */
7
43
  function isOption(o) {
8
- return o != null && typeof o === "object" && OptionKindSymbol in o;
44
+ return o != null && typeof o === "object" && OptionKindSymbol in o;
9
45
  }
10
-
46
+ //#endregion
47
+ //#region src/core/result/symbols.ts
48
+ /**
49
+ * @module
50
+ * Internal symbol used to identify `Result` type variants.
51
+ *
52
+ * This symbol is used as a property key to distinguish between `Ok` and `Err` variants.
53
+ * It provides a reliable way to identify the variant of a `Result` instance without
54
+ * relying on method calls or duck typing.
55
+ *
56
+ * Note: This symbol is an internal implementation detail and is not exported as part of the public API.
57
+ * Use the `isResult` utility function for type checking instead.
58
+ */
59
+ /**
60
+ * A unique symbol used as a property key to identify the variant of a `Result` instance.
61
+ *
62
+ * When accessed on a `Result`, returns `'Ok'` if the Result represents success,
63
+ * or `'Err'` if it represents failure.
64
+ *
65
+ * This symbol is used internally by the `isResult` utility function to verify
66
+ * that an object is a valid `Result` instance.
67
+ *
68
+ * @internal
69
+ */
11
70
  const ResultKindSymbol = /* @__PURE__ */ Symbol("Result kind");
12
-
71
+ //#endregion
72
+ //#region src/core/result/guards.ts
73
+ /**
74
+ * Checks if a value is a `Result`.
75
+ *
76
+ * @typeParam T - The expected type of the success value contained within the `Result`.
77
+ * @typeParam E - The expected type of the error value contained within the `Result`.
78
+ * @param r - The value to be checked as a `Result`.
79
+ * @returns `true` if the value is a `Result`, otherwise `false`.
80
+ * @since 1.2.0
81
+ * @example
82
+ * ```ts
83
+ * const x = Ok(5);
84
+ * console.log(isResult(x)); // true
85
+ * console.log(isResult(null)); // false
86
+ * console.log(isResult({ value: 5 })); // false
87
+ * ```
88
+ */
13
89
  function isResult(r) {
14
- return r != null && typeof r === "object" && ResultKindSymbol in r;
90
+ return r != null && typeof r === "object" && ResultKindSymbol in r;
15
91
  }
16
-
17
- const ASYNC_TRUE$1 = Promise.resolve(true);
18
- const ASYNC_FALSE$1 = Promise.resolve(false);
92
+ //#endregion
93
+ //#region src/core/prelude.ts
94
+ /**
95
+ * @module
96
+ * Constructors and factory functions for creating `Option` and `Result` types.
97
+ *
98
+ * This module exports:
99
+ * - `Some<T>(value)` - Creates an Option containing a value
100
+ * - `None` - Constant representing absence of value
101
+ * - `Ok<T, E>(value)` - Creates a successful Result
102
+ * - `Err<T, E>(error)` - Creates a failed Result
103
+ * - `None` interface - Type overrides for better type inference
104
+ */
105
+ const ASYNC_TRUE$1 = /* @__PURE__ */ Promise.resolve(true);
106
+ const ASYNC_FALSE$1 = /* @__PURE__ */ Promise.resolve(false);
107
+ /**
108
+ * Creates an `Option<T>` representing the presence of a value.
109
+ * This function is typically used to construct an `Option` that contains a value, indicating that the operation yielding the value was successful.
110
+ *
111
+ * @typeParam T - The type of the value to be wrapped in a `Some`.
112
+ * @param value - The value to wrap as a `Some` option.
113
+ * @returns An `Option<T>` that contains the provided value, representing the `Some` case.
114
+ * @since 1.0.0
115
+ * @example
116
+ * ```ts
117
+ * const maybeValue = Some(1); // Option<number> with a value
118
+ * if (maybeValue.isSome()) {
119
+ * console.log(maybeValue.unwrap()); // Outputs: 1
120
+ * }
121
+ * ```
122
+ */
19
123
  function Some(value) {
20
- const some = Object.freeze({
21
- [Symbol.toStringTag]: "Option",
22
- [OptionKindSymbol]: "Some",
23
- *[Symbol.iterator]() {
24
- yield value;
25
- },
26
- toString() {
27
- return `Some(${value})`;
28
- },
29
- isSome() {
30
- return true;
31
- },
32
- isNone() {
33
- return false;
34
- },
35
- isSomeAnd(predicate) {
36
- return predicate(value);
37
- },
38
- isSomeAndAsync(predicate) {
39
- return Promise.resolve(predicate(value));
40
- },
41
- isNoneOr(predicate) {
42
- return predicate(value);
43
- },
44
- isNoneOrAsync(predicate) {
45
- return Promise.resolve(predicate(value));
46
- },
47
- expect(_msg) {
48
- return value;
49
- },
50
- unwrap() {
51
- return value;
52
- },
53
- unwrapOr(_defaultValue) {
54
- return value;
55
- },
56
- unwrapOrElse(_fn) {
57
- return value;
58
- },
59
- unwrapOrElseAsync(_fn) {
60
- return Promise.resolve(value);
61
- },
62
- okOr(_error) {
63
- return Ok(value);
64
- },
65
- okOrElse(_err) {
66
- return Ok(value);
67
- },
68
- transpose() {
69
- assertResult(value);
70
- return value.isOk() ? Ok(Some(value.unwrap())) : Err(value.unwrapErr());
71
- },
72
- filter(predicate) {
73
- return predicate(value) ? some : None;
74
- },
75
- flatten() {
76
- assertOption(value);
77
- return value;
78
- },
79
- map(fn) {
80
- return Some(fn(value));
81
- },
82
- mapOr(_defaultValue, fn) {
83
- return fn(value);
84
- },
85
- mapOrElse(_defaultFn, fn) {
86
- return fn(value);
87
- },
88
- zip(other) {
89
- assertOption(other);
90
- return other.isSome() ? Some([value, other.unwrap()]) : None;
91
- },
92
- zipWith(other, fn) {
93
- assertOption(other);
94
- return other.isSome() ? Some(fn(value, other.unwrap())) : None;
95
- },
96
- unzip() {
97
- const tuple = value;
98
- if (!Array.isArray(tuple) || tuple.length !== 2) {
99
- throw new TypeError(`Option::unzip() requires a 2-element tuple, received ${Array.isArray(tuple) ? `array with ${tuple.length} elements` : typeof tuple}`);
100
- }
101
- const [a, b] = tuple;
102
- return [Some(a), Some(b)];
103
- },
104
- reduce(other, fn) {
105
- assertOption(other);
106
- return other.isSome() ? Some(fn(value, other.unwrap())) : some;
107
- },
108
- and(other) {
109
- assertOption(other);
110
- return other;
111
- },
112
- andThen(fn) {
113
- return fn(value);
114
- },
115
- andThenAsync(fn) {
116
- return Promise.resolve(fn(value));
117
- },
118
- or(_other) {
119
- return some;
120
- },
121
- orElse(_fn) {
122
- return some;
123
- },
124
- orElseAsync(_fn) {
125
- return Promise.resolve(some);
126
- },
127
- xor(other) {
128
- assertOption(other);
129
- return other.isSome() ? None : some;
130
- },
131
- inspect(fn) {
132
- fn(value);
133
- return some;
134
- },
135
- eq(other) {
136
- assertOption(other);
137
- return other.isSome() && other.unwrap() === value;
138
- }
139
- });
140
- return some;
124
+ const some = Object.freeze({
125
+ [Symbol.toStringTag]: "Option",
126
+ [OptionKindSymbol]: "Some",
127
+ *[Symbol.iterator]() {
128
+ yield value;
129
+ },
130
+ toString() {
131
+ return `Some(${value})`;
132
+ },
133
+ isSome() {
134
+ return true;
135
+ },
136
+ isNone() {
137
+ return false;
138
+ },
139
+ isSomeAnd(predicate) {
140
+ return predicate(value);
141
+ },
142
+ isSomeAndAsync(predicate) {
143
+ return Promise.resolve(predicate(value));
144
+ },
145
+ isNoneOr(predicate) {
146
+ return predicate(value);
147
+ },
148
+ isNoneOrAsync(predicate) {
149
+ return Promise.resolve(predicate(value));
150
+ },
151
+ expect(_msg) {
152
+ return value;
153
+ },
154
+ unwrap() {
155
+ return value;
156
+ },
157
+ unwrapOr(_defaultValue) {
158
+ return value;
159
+ },
160
+ unwrapOrElse(_fn) {
161
+ return value;
162
+ },
163
+ unwrapOrElseAsync(_fn) {
164
+ return Promise.resolve(value);
165
+ },
166
+ okOr(_error) {
167
+ return Ok(value);
168
+ },
169
+ okOrElse(_err) {
170
+ return Ok(value);
171
+ },
172
+ transpose() {
173
+ assertResult(value);
174
+ return value.isOk() ? Ok(Some(value.unwrap())) : Err(value.unwrapErr());
175
+ },
176
+ filter(predicate) {
177
+ return predicate(value) ? some : None;
178
+ },
179
+ flatten() {
180
+ assertOption(value);
181
+ return value;
182
+ },
183
+ map(fn) {
184
+ return Some(fn(value));
185
+ },
186
+ mapOr(_defaultValue, fn) {
187
+ return fn(value);
188
+ },
189
+ mapOrElse(_defaultFn, fn) {
190
+ return fn(value);
191
+ },
192
+ zip(other) {
193
+ assertOption(other);
194
+ return other.isSome() ? Some([value, other.unwrap()]) : None;
195
+ },
196
+ zipWith(other, fn) {
197
+ assertOption(other);
198
+ return other.isSome() ? Some(fn(value, other.unwrap())) : None;
199
+ },
200
+ unzip() {
201
+ const tuple = value;
202
+ if (!Array.isArray(tuple) || tuple.length !== 2) throw new TypeError(`Option::unzip() requires a 2-element tuple, received ${Array.isArray(tuple) ? `array with ${tuple.length} elements` : typeof tuple}`);
203
+ const [a, b] = tuple;
204
+ return [Some(a), Some(b)];
205
+ },
206
+ reduce(other, fn) {
207
+ assertOption(other);
208
+ return other.isSome() ? Some(fn(value, other.unwrap())) : some;
209
+ },
210
+ and(other) {
211
+ assertOption(other);
212
+ return other;
213
+ },
214
+ andThen(fn) {
215
+ return fn(value);
216
+ },
217
+ andThenAsync(fn) {
218
+ return Promise.resolve(fn(value));
219
+ },
220
+ or(_other) {
221
+ return some;
222
+ },
223
+ orElse(_fn) {
224
+ return some;
225
+ },
226
+ orElseAsync(_fn) {
227
+ return Promise.resolve(some);
228
+ },
229
+ xor(other) {
230
+ assertOption(other);
231
+ return other.isSome() ? None : some;
232
+ },
233
+ inspect(fn) {
234
+ fn(value);
235
+ return some;
236
+ },
237
+ eq(other) {
238
+ assertOption(other);
239
+ return other.isSome() && other.unwrap() === value;
240
+ }
241
+ });
242
+ return some;
141
243
  }
142
- const None = Object.freeze({
143
- [Symbol.toStringTag]: "Option",
144
- [OptionKindSymbol]: "None",
145
- *[Symbol.iterator]() {
146
- },
147
- toString() {
148
- return "None";
149
- },
150
- isSome() {
151
- return false;
152
- },
153
- isNone() {
154
- return true;
155
- },
156
- isSomeAnd(_predicate) {
157
- return false;
158
- },
159
- isSomeAndAsync(_predicate) {
160
- return ASYNC_FALSE$1;
161
- },
162
- isNoneOr(_predicate) {
163
- return true;
164
- },
165
- isNoneOrAsync(_predicate) {
166
- return ASYNC_TRUE$1;
167
- },
168
- expect(msg) {
169
- throw new TypeError(msg);
170
- },
171
- unwrap() {
172
- throw new TypeError("Option::unwrap() called on a `None` value");
173
- },
174
- unwrapOr(defaultValue) {
175
- return defaultValue;
176
- },
177
- unwrapOrElse(fn) {
178
- return fn();
179
- },
180
- unwrapOrElseAsync(fn) {
181
- return Promise.resolve(fn());
182
- },
183
- okOr(error) {
184
- return Err(error);
185
- },
186
- okOrElse(err) {
187
- return Err(err());
188
- },
189
- transpose() {
190
- return Ok(None);
191
- },
192
- filter(_predicate) {
193
- return None;
194
- },
195
- flatten() {
196
- return None;
197
- },
198
- map(_fn) {
199
- return None;
200
- },
201
- mapOr(defaultValue, _fn) {
202
- return defaultValue;
203
- },
204
- mapOrElse(defaultFn, _fn) {
205
- return defaultFn();
206
- },
207
- zip(_other) {
208
- return None;
209
- },
210
- zipWith(_other, _fn) {
211
- return None;
212
- },
213
- unzip() {
214
- return [None, None];
215
- },
216
- reduce(other, _fn) {
217
- assertOption(other);
218
- return other;
219
- },
220
- and(_other) {
221
- return None;
222
- },
223
- andThen(_fn) {
224
- return None;
225
- },
226
- andThenAsync(_fn) {
227
- return ASYNC_NONE;
228
- },
229
- or(other) {
230
- assertOption(other);
231
- return other;
232
- },
233
- orElse(fn) {
234
- return fn();
235
- },
236
- orElseAsync(fn) {
237
- return Promise.resolve(fn());
238
- },
239
- xor(other) {
240
- assertOption(other);
241
- return other.isSome() ? other : None;
242
- },
243
- inspect(_fn) {
244
- return None;
245
- },
246
- eq(other) {
247
- assertOption(other);
248
- return other === None;
249
- }
244
+ /**
245
+ * A constant representing the `None` case of an `Option`, indicating the absence of a value.
246
+ * This constant is frozen to ensure it is immutable and cannot be altered, preserving the integrity of `None` throughout the application.
247
+ *
248
+ * @since 1.0.0
249
+ * @example
250
+ * ```ts
251
+ * // Use None to represent absence of a value
252
+ * function findUser(id: number): Option<User> {
253
+ * const user = users.find(u => u.id === id);
254
+ * return user ? Some(user) : None;
255
+ * }
256
+ *
257
+ * // None is a singleton, so you can compare by reference
258
+ * const result = findUser(999);
259
+ * if (result === None) {
260
+ * console.log('User not found');
261
+ * }
262
+ *
263
+ * // Use with Option methods
264
+ * const name = None.unwrapOr('Anonymous'); // 'Anonymous'
265
+ * ```
266
+ */
267
+ const None = /* @__PURE__ */ Object.freeze({
268
+ [Symbol.toStringTag]: "Option",
269
+ [OptionKindSymbol]: "None",
270
+ *[Symbol.iterator]() {},
271
+ toString() {
272
+ return "None";
273
+ },
274
+ isSome() {
275
+ return false;
276
+ },
277
+ isNone() {
278
+ return true;
279
+ },
280
+ isSomeAnd(_predicate) {
281
+ return false;
282
+ },
283
+ isSomeAndAsync(_predicate) {
284
+ return ASYNC_FALSE$1;
285
+ },
286
+ isNoneOr(_predicate) {
287
+ return true;
288
+ },
289
+ isNoneOrAsync(_predicate) {
290
+ return ASYNC_TRUE$1;
291
+ },
292
+ expect(msg) {
293
+ throw new TypeError(msg);
294
+ },
295
+ unwrap() {
296
+ throw new TypeError("Option::unwrap() called on a `None` value");
297
+ },
298
+ unwrapOr(defaultValue) {
299
+ return defaultValue;
300
+ },
301
+ unwrapOrElse(fn) {
302
+ return fn();
303
+ },
304
+ unwrapOrElseAsync(fn) {
305
+ return Promise.resolve(fn());
306
+ },
307
+ okOr(error) {
308
+ return Err(error);
309
+ },
310
+ okOrElse(err) {
311
+ return Err(err());
312
+ },
313
+ transpose() {
314
+ return Ok(None);
315
+ },
316
+ filter(_predicate) {
317
+ return None;
318
+ },
319
+ flatten() {
320
+ return None;
321
+ },
322
+ map(_fn) {
323
+ return None;
324
+ },
325
+ mapOr(defaultValue, _fn) {
326
+ return defaultValue;
327
+ },
328
+ mapOrElse(defaultFn, _fn) {
329
+ return defaultFn();
330
+ },
331
+ zip(_other) {
332
+ return None;
333
+ },
334
+ zipWith(_other, _fn) {
335
+ return None;
336
+ },
337
+ unzip() {
338
+ return [None, None];
339
+ },
340
+ reduce(other, _fn) {
341
+ assertOption(other);
342
+ return other;
343
+ },
344
+ and(_other) {
345
+ return None;
346
+ },
347
+ andThen(_fn) {
348
+ return None;
349
+ },
350
+ andThenAsync(_fn) {
351
+ return ASYNC_NONE;
352
+ },
353
+ or(other) {
354
+ assertOption(other);
355
+ return other;
356
+ },
357
+ orElse(fn) {
358
+ return fn();
359
+ },
360
+ orElseAsync(fn) {
361
+ return Promise.resolve(fn());
362
+ },
363
+ xor(other) {
364
+ assertOption(other);
365
+ return other.isSome() ? other : None;
366
+ },
367
+ inspect(_fn) {
368
+ return None;
369
+ },
370
+ eq(other) {
371
+ assertOption(other);
372
+ return other === None;
373
+ }
250
374
  });
251
- const ASYNC_NONE = Promise.resolve(None);
375
+ /**
376
+ * Async Option constant for `None`.
377
+ * A pre-resolved `Promise<None>` that can be reused to avoid creating
378
+ * new Promise instances when returning `None` from async functions.
379
+ *
380
+ * Since `None extends Option<never>`, this constant can be assigned to any
381
+ * `AsyncOption<T>` (i.e., `Promise<Option<T>>`) due to TypeScript's covariance.
382
+ *
383
+ * @since 1.8.0
384
+ * @example
385
+ * ```ts
386
+ * async function findUser(id: number): AsyncOption<User> {
387
+ * if (id < 0) {
388
+ * return ASYNC_NONE;
389
+ * }
390
+ * const user = await db.findUser(id);
391
+ * return user ? Some(user) : ASYNC_NONE;
392
+ * }
393
+ * ```
394
+ *
395
+ * @example
396
+ * ```ts
397
+ * // Useful in conditional async returns
398
+ * function maybeLoadAsync(shouldLoad: boolean): AsyncOption<Data> {
399
+ * if (!shouldLoad) {
400
+ * return ASYNC_NONE;
401
+ * }
402
+ * return loadDataAsync();
403
+ * }
404
+ * ```
405
+ */
406
+ const ASYNC_NONE = /* @__PURE__ */ Promise.resolve(None);
252
407
  function Ok(value) {
253
- const ok = Object.freeze({
254
- [Symbol.toStringTag]: "Result",
255
- [ResultKindSymbol]: "Ok",
256
- *[Symbol.iterator]() {
257
- yield value;
258
- },
259
- toString() {
260
- return `Ok(${value})`;
261
- },
262
- isOk() {
263
- return true;
264
- },
265
- isErr() {
266
- return false;
267
- },
268
- isOkAnd(predicate) {
269
- return predicate(value);
270
- },
271
- isOkAndAsync(predicate) {
272
- return Promise.resolve(predicate(value));
273
- },
274
- isErrAnd(_predicate) {
275
- return false;
276
- },
277
- isErrAndAsync(_predicate) {
278
- return ASYNC_FALSE$1;
279
- },
280
- expect(_msg) {
281
- return value;
282
- },
283
- unwrap() {
284
- return value;
285
- },
286
- unwrapOr(_defaultValue) {
287
- return value;
288
- },
289
- unwrapOrElse(_fn) {
290
- return value;
291
- },
292
- unwrapOrElseAsync(_fn) {
293
- return Promise.resolve(value);
294
- },
295
- expectErr(msg) {
296
- throw new TypeError(`${msg}: ${value}`);
297
- },
298
- unwrapErr() {
299
- throw new TypeError("Result::unwrapErr() called on an `Ok` value");
300
- },
301
- intoOk() {
302
- return value;
303
- },
304
- intoErr() {
305
- throw new TypeError("Result::intoErr() called on an `Ok` value");
306
- },
307
- ok() {
308
- return Some(value);
309
- },
310
- err() {
311
- return None;
312
- },
313
- transpose() {
314
- assertOption(value);
315
- return value.isSome() ? Some(Ok(value.unwrap())) : None;
316
- },
317
- map(fn) {
318
- return Ok(fn(value));
319
- },
320
- mapErr(_fn) {
321
- return ok;
322
- },
323
- mapOr(_defaultValue, fn) {
324
- return fn(value);
325
- },
326
- mapOrElse(_defaultFn, fn) {
327
- return fn(value);
328
- },
329
- flatten() {
330
- assertResult(value);
331
- return value;
332
- },
333
- and(other) {
334
- assertResult(other);
335
- return other;
336
- },
337
- or(_other) {
338
- return ok;
339
- },
340
- andThen(fn) {
341
- return fn(value);
342
- },
343
- andThenAsync(fn) {
344
- return Promise.resolve(fn(value));
345
- },
346
- orElse(_fn) {
347
- return ok;
348
- },
349
- orElseAsync(_fn) {
350
- return Promise.resolve(ok);
351
- },
352
- inspect(fn) {
353
- fn(value);
354
- return ok;
355
- },
356
- inspectErr(_fn) {
357
- return ok;
358
- },
359
- eq(other) {
360
- assertResult(other);
361
- return other.isOk() && other.unwrap() === value;
362
- },
363
- asOk() {
364
- return ok;
365
- },
366
- asErr() {
367
- throw new TypeError("Result::asErr() called on an `Ok` value");
368
- },
369
- andTryAsync(fn) {
370
- try {
371
- const result = fn(value);
372
- return Promise.resolve(result).then(
373
- Ok,
374
- Err
375
- );
376
- } catch (e) {
377
- return Promise.resolve(Err(e));
378
- }
379
- },
380
- orTryAsync(_fn) {
381
- return Promise.resolve(ok);
382
- }
383
- });
384
- return ok;
408
+ const ok = Object.freeze({
409
+ [Symbol.toStringTag]: "Result",
410
+ [ResultKindSymbol]: "Ok",
411
+ *[Symbol.iterator]() {
412
+ yield value;
413
+ },
414
+ toString() {
415
+ return `Ok(${value})`;
416
+ },
417
+ isOk() {
418
+ return true;
419
+ },
420
+ isErr() {
421
+ return false;
422
+ },
423
+ isOkAnd(predicate) {
424
+ return predicate(value);
425
+ },
426
+ isOkAndAsync(predicate) {
427
+ return Promise.resolve(predicate(value));
428
+ },
429
+ isErrAnd(_predicate) {
430
+ return false;
431
+ },
432
+ isErrAndAsync(_predicate) {
433
+ return ASYNC_FALSE$1;
434
+ },
435
+ expect(_msg) {
436
+ return value;
437
+ },
438
+ unwrap() {
439
+ return value;
440
+ },
441
+ unwrapOr(_defaultValue) {
442
+ return value;
443
+ },
444
+ unwrapOrElse(_fn) {
445
+ return value;
446
+ },
447
+ unwrapOrElseAsync(_fn) {
448
+ return Promise.resolve(value);
449
+ },
450
+ expectErr(msg) {
451
+ throw new TypeError(`${msg}: ${value}`);
452
+ },
453
+ unwrapErr() {
454
+ throw new TypeError("Result::unwrapErr() called on an `Ok` value");
455
+ },
456
+ intoOk() {
457
+ return value;
458
+ },
459
+ intoErr() {
460
+ throw new TypeError("Result::intoErr() called on an `Ok` value");
461
+ },
462
+ ok() {
463
+ return Some(value);
464
+ },
465
+ err() {
466
+ return None;
467
+ },
468
+ transpose() {
469
+ assertOption(value);
470
+ return value.isSome() ? Some(Ok(value.unwrap())) : None;
471
+ },
472
+ map(fn) {
473
+ return Ok(fn(value));
474
+ },
475
+ mapErr(_fn) {
476
+ return ok;
477
+ },
478
+ mapOr(_defaultValue, fn) {
479
+ return fn(value);
480
+ },
481
+ mapOrElse(_defaultFn, fn) {
482
+ return fn(value);
483
+ },
484
+ flatten() {
485
+ assertResult(value);
486
+ return value;
487
+ },
488
+ and(other) {
489
+ assertResult(other);
490
+ return other;
491
+ },
492
+ or(_other) {
493
+ return ok;
494
+ },
495
+ andThen(fn) {
496
+ return fn(value);
497
+ },
498
+ andThenAsync(fn) {
499
+ return Promise.resolve(fn(value));
500
+ },
501
+ orElse(_fn) {
502
+ return ok;
503
+ },
504
+ orElseAsync(_fn) {
505
+ return Promise.resolve(ok);
506
+ },
507
+ inspect(fn) {
508
+ fn(value);
509
+ return ok;
510
+ },
511
+ inspectErr(_fn) {
512
+ return ok;
513
+ },
514
+ eq(other) {
515
+ assertResult(other);
516
+ return other.isOk() && other.unwrap() === value;
517
+ },
518
+ asOk() {
519
+ return ok;
520
+ },
521
+ asErr() {
522
+ throw new TypeError("Result::asErr() called on an `Ok` value");
523
+ },
524
+ andTryAsync(fn) {
525
+ try {
526
+ const result = fn(value);
527
+ return Promise.resolve(result).then(Ok, Err);
528
+ } catch (e) {
529
+ return Promise.resolve(Err(e));
530
+ }
531
+ },
532
+ orTryAsync(_fn) {
533
+ return Promise.resolve(ok);
534
+ }
535
+ });
536
+ return ok;
385
537
  }
538
+ /**
539
+ * Creates a `Result<T, E>` representing a failed outcome containing an error.
540
+ * This function is used to construct a `Result` that signifies the operation failed by containing the error `E`.
541
+ *
542
+ * @typeParam T - The type of the value that the result could potentially contain (not used in this case).
543
+ * @typeParam E - The type of the error to be wrapped in the `Err` result.
544
+ * @param error - The error to wrap as an `Err` result.
545
+ * @returns A `Result<T, E>` that contains the provided error, representing the `Err` case.
546
+ * @since 1.0.0
547
+ * @example
548
+ * ```ts
549
+ * const badResult = Err<number, Error>(new Error('Something went wrong'));
550
+ * if (badResult.isErr()) {
551
+ * console.error(badResult.unwrapErr()); // Outputs: Error: Something went wrong
552
+ * }
553
+ * ```
554
+ */
386
555
  function Err(error) {
387
- const err = Object.freeze({
388
- [Symbol.toStringTag]: "Result",
389
- [ResultKindSymbol]: "Err",
390
- *[Symbol.iterator]() {
391
- },
392
- toString() {
393
- return `Err(${error})`;
394
- },
395
- isOk() {
396
- return false;
397
- },
398
- isErr() {
399
- return true;
400
- },
401
- isOkAnd(_predicate) {
402
- return false;
403
- },
404
- isOkAndAsync(_predicate) {
405
- return ASYNC_FALSE$1;
406
- },
407
- isErrAnd(predicate) {
408
- return predicate(error);
409
- },
410
- isErrAndAsync(predicate) {
411
- return Promise.resolve(predicate(error));
412
- },
413
- expect(msg) {
414
- throw new TypeError(`${msg}: ${error}`);
415
- },
416
- unwrap() {
417
- throw new TypeError("Result::unwrap() called on an `Err` value");
418
- },
419
- unwrapOr(defaultValue) {
420
- return defaultValue;
421
- },
422
- unwrapOrElse(fn) {
423
- return fn(error);
424
- },
425
- unwrapOrElseAsync(fn) {
426
- return Promise.resolve(fn(error));
427
- },
428
- expectErr(_msg) {
429
- return error;
430
- },
431
- unwrapErr() {
432
- return error;
433
- },
434
- intoOk() {
435
- throw new TypeError("Result::intoOk() called on an `Err` value");
436
- },
437
- intoErr() {
438
- return error;
439
- },
440
- ok() {
441
- return None;
442
- },
443
- err() {
444
- return Some(error);
445
- },
446
- transpose() {
447
- return Some(err);
448
- },
449
- map(_fn) {
450
- return err;
451
- },
452
- mapErr(fn) {
453
- return Err(fn(error));
454
- },
455
- mapOr(defaultValue, _fn) {
456
- return defaultValue;
457
- },
458
- mapOrElse(defaultFn, _fn) {
459
- return defaultFn(error);
460
- },
461
- flatten() {
462
- return err;
463
- },
464
- and(_other) {
465
- return err;
466
- },
467
- or(other) {
468
- assertResult(other);
469
- return other;
470
- },
471
- andThen(_fn) {
472
- return err;
473
- },
474
- andThenAsync(_fn) {
475
- return Promise.resolve(err);
476
- },
477
- orElse(fn) {
478
- return fn(error);
479
- },
480
- orElseAsync(fn) {
481
- return Promise.resolve(fn(error));
482
- },
483
- inspect(_fn) {
484
- return err;
485
- },
486
- inspectErr(fn) {
487
- fn(error);
488
- return err;
489
- },
490
- eq(other) {
491
- assertResult(other);
492
- return other.isErr() && other.unwrapErr() === error;
493
- },
494
- asOk() {
495
- throw new TypeError("Result::asOk() called on an `Err` value");
496
- },
497
- asErr() {
498
- return err;
499
- },
500
- andTryAsync(_fn) {
501
- return Promise.resolve(err);
502
- },
503
- orTryAsync(fn) {
504
- try {
505
- const result = fn(error);
506
- return Promise.resolve(result).then(
507
- Ok,
508
- Err
509
- );
510
- } catch (e) {
511
- return Promise.resolve(Err(e));
512
- }
513
- }
514
- });
515
- return err;
556
+ const err = Object.freeze({
557
+ [Symbol.toStringTag]: "Result",
558
+ [ResultKindSymbol]: "Err",
559
+ *[Symbol.iterator]() {},
560
+ toString() {
561
+ return `Err(${error})`;
562
+ },
563
+ isOk() {
564
+ return false;
565
+ },
566
+ isErr() {
567
+ return true;
568
+ },
569
+ isOkAnd(_predicate) {
570
+ return false;
571
+ },
572
+ isOkAndAsync(_predicate) {
573
+ return ASYNC_FALSE$1;
574
+ },
575
+ isErrAnd(predicate) {
576
+ return predicate(error);
577
+ },
578
+ isErrAndAsync(predicate) {
579
+ return Promise.resolve(predicate(error));
580
+ },
581
+ expect(msg) {
582
+ throw new TypeError(`${msg}: ${error}`);
583
+ },
584
+ unwrap() {
585
+ throw new TypeError("Result::unwrap() called on an `Err` value");
586
+ },
587
+ unwrapOr(defaultValue) {
588
+ return defaultValue;
589
+ },
590
+ unwrapOrElse(fn) {
591
+ return fn(error);
592
+ },
593
+ unwrapOrElseAsync(fn) {
594
+ return Promise.resolve(fn(error));
595
+ },
596
+ expectErr(_msg) {
597
+ return error;
598
+ },
599
+ unwrapErr() {
600
+ return error;
601
+ },
602
+ intoOk() {
603
+ throw new TypeError("Result::intoOk() called on an `Err` value");
604
+ },
605
+ intoErr() {
606
+ return error;
607
+ },
608
+ ok() {
609
+ return None;
610
+ },
611
+ err() {
612
+ return Some(error);
613
+ },
614
+ transpose() {
615
+ return Some(err);
616
+ },
617
+ map(_fn) {
618
+ return err;
619
+ },
620
+ mapErr(fn) {
621
+ return Err(fn(error));
622
+ },
623
+ mapOr(defaultValue, _fn) {
624
+ return defaultValue;
625
+ },
626
+ mapOrElse(defaultFn, _fn) {
627
+ return defaultFn(error);
628
+ },
629
+ flatten() {
630
+ return err;
631
+ },
632
+ and(_other) {
633
+ return err;
634
+ },
635
+ or(other) {
636
+ assertResult(other);
637
+ return other;
638
+ },
639
+ andThen(_fn) {
640
+ return err;
641
+ },
642
+ andThenAsync(_fn) {
643
+ return Promise.resolve(err);
644
+ },
645
+ orElse(fn) {
646
+ return fn(error);
647
+ },
648
+ orElseAsync(fn) {
649
+ return Promise.resolve(fn(error));
650
+ },
651
+ inspect(_fn) {
652
+ return err;
653
+ },
654
+ inspectErr(fn) {
655
+ fn(error);
656
+ return err;
657
+ },
658
+ eq(other) {
659
+ assertResult(other);
660
+ return other.isErr() && other.unwrapErr() === error;
661
+ },
662
+ asOk() {
663
+ throw new TypeError("Result::asOk() called on an `Err` value");
664
+ },
665
+ asErr() {
666
+ return err;
667
+ },
668
+ andTryAsync(_fn) {
669
+ return Promise.resolve(err);
670
+ },
671
+ orTryAsync(fn) {
672
+ try {
673
+ const result = fn(error);
674
+ return Promise.resolve(result).then(Ok, Err);
675
+ } catch (e) {
676
+ return Promise.resolve(Err(e));
677
+ }
678
+ }
679
+ });
680
+ return err;
516
681
  }
682
+ /**
683
+ * Safely converts a value to a string representation for error messages.
684
+ * Handles cases where `toString()` might throw or values are null/undefined.
685
+ *
686
+ * @param value - The value to stringify.
687
+ * @returns A safe string representation of the value.
688
+ */
517
689
  function safeStringify(value) {
518
- try {
519
- if (value === null) {
520
- return "null";
521
- }
522
- if (value === void 0) {
523
- return "undefined";
524
- }
525
- if (typeof value === "object") {
526
- return Object.prototype.toString.call(value);
527
- }
528
- return String(value);
529
- } catch {
530
- return "[unable to stringify]";
531
- }
690
+ try {
691
+ if (value === null) return "null";
692
+ if (value === void 0) return "undefined";
693
+ if (typeof value === "object") return Object.prototype.toString.call(value);
694
+ return String(value);
695
+ } catch {
696
+ return "[unable to stringify]";
697
+ }
532
698
  }
699
+ /**
700
+ * Asserts that a given value is an `Option`.
701
+ *
702
+ * @typeParam T - The expected type of the value contained within the `Option`.
703
+ * @param o - The value to be checked as an `Option`.
704
+ * @throws {TypeError} If the value is not an `Option`.
705
+ * @see isOption
706
+ */
533
707
  function assertOption(o) {
534
- if (!isOption(o)) {
535
- throw new TypeError(`Expected an Option, but received: ${safeStringify(o)}`);
536
- }
708
+ if (!isOption(o)) throw new TypeError(`Expected an Option, but received: ${safeStringify(o)}`);
537
709
  }
710
+ /**
711
+ * Asserts that a given value is a `Result`.
712
+ *
713
+ * @typeParam T - The expected type of the success value contained within the `Result`.
714
+ * @typeParam E - The expected type of the error value contained within the `Result`.
715
+ * @param r - The value to be checked as a `Result`.
716
+ * @throws {TypeError} If the value is not a `Result`.
717
+ * @see isResult
718
+ */
538
719
  function assertResult(r) {
539
- if (!isResult(r)) {
540
- throw new TypeError(`Expected a Result, but received: ${safeStringify(r)}`);
541
- }
720
+ if (!isResult(r)) throw new TypeError(`Expected a Result, but received: ${safeStringify(r)}`);
542
721
  }
543
-
722
+ //#endregion
723
+ //#region src/core/option/extensions.ts
724
+ /**
725
+ * @module
726
+ * Extension functions for bridging standard JavaScript patterns with Option types.
727
+ *
728
+ * This module provides utilities for:
729
+ * - Converting try-catch patterns to Option-based handling
730
+ * - Integrating async/await patterns with Option types
731
+ */
732
+ /**
733
+ * Executes a function and returns `Some` with the result if successful, or `None` if it throws.
734
+ *
735
+ * This converts try-catch patterns to Option-based handling, where you only care
736
+ * about success/failure, not the error details.
737
+ *
738
+ * Similar to `Promise.try`, this function accepts optional arguments that are passed to the function.
739
+ *
740
+ * @typeParam T - The type of the value returned by the function.
741
+ * @typeParam Args - The types of the arguments to pass to the function.
742
+ * @param fn - A function that may throw an exception.
743
+ * @param args - Arguments to pass to the function.
744
+ * @returns `Some<T>` if the function succeeds, or `None` if it throws.
745
+ * @since 1.7.0
746
+ * @example
747
+ * ```ts
748
+ * // Parse JSON, ignore error details
749
+ * const data = tryOption(JSON.parse, jsonString);
750
+ * console.log(data.unwrapOr(defaultData));
751
+ * ```
752
+ *
753
+ * @example
754
+ * ```ts
755
+ * // Validate URL - using closure form
756
+ * const url = tryOption(() => new URL(input));
757
+ * url.inspect(u => console.log('Valid URL:', u.href));
758
+ * ```
759
+ *
760
+ * @example
761
+ * ```ts
762
+ * // Decode URI component with arguments
763
+ * const decoded = tryOption(decodeURIComponent, str);
764
+ * ```
765
+ */
544
766
  function tryOption(fn, ...args) {
545
- try {
546
- return Some(fn(...args));
547
- } catch {
548
- return None;
549
- }
767
+ try {
768
+ return Some(fn(...args));
769
+ } catch {
770
+ return None;
771
+ }
550
772
  }
551
773
  async function tryAsyncOption(task, ...args) {
552
- try {
553
- const result = typeof task === "function" ? task(...args) : task;
554
- return Some(await result);
555
- } catch {
556
- return None;
557
- }
774
+ try {
775
+ return Some(await (typeof task === "function" ? task(...args) : task));
776
+ } catch {
777
+ return None;
778
+ }
558
779
  }
559
-
560
- const RESULT_TRUE = Ok(true);
561
- const RESULT_FALSE = Ok(false);
562
- const RESULT_ZERO = Ok(0);
563
- const RESULT_VOID = Ok();
564
-
780
+ //#endregion
781
+ //#region src/core/result/constants.ts
782
+ /**
783
+ * @module
784
+ * Pre-defined Result constants for common return values.
785
+ *
786
+ * These immutable constants can be reused throughout the application to avoid
787
+ * creating new Result instances for common values like `true`, `false`, `0`, and `void`.
788
+ *
789
+ * The error type is `never` because these are always `Ok` values that can never
790
+ * contain an error. This allows them to be assigned to any `Result<T, E>` type.
791
+ */
792
+ /**
793
+ * Result constant for `true`.
794
+ * Can be used anywhere due to immutability.
795
+ * @since 1.3.0
796
+ * @example
797
+ * ```ts
798
+ * function validate(): Result<boolean, Error> {
799
+ * return RESULT_TRUE;
800
+ * }
801
+ *
802
+ * const result: Result<boolean, string> = RESULT_TRUE;
803
+ * const value: boolean = RESULT_TRUE.intoOk(); // Safe extraction
804
+ * ```
805
+ */
806
+ const RESULT_TRUE = /* @__PURE__ */ Ok(true);
807
+ /**
808
+ * Result constant for `false`.
809
+ * Can be used anywhere due to immutability.
810
+ * @since 1.3.0
811
+ * @example
812
+ * ```ts
813
+ * function validate(): Result<boolean, Error> {
814
+ * return RESULT_FALSE;
815
+ * }
816
+ *
817
+ * const result: Result<boolean, string> = RESULT_FALSE;
818
+ * const value: boolean = RESULT_FALSE.intoOk(); // Safe extraction
819
+ * ```
820
+ */
821
+ const RESULT_FALSE = /* @__PURE__ */ Ok(false);
822
+ /**
823
+ * Result constant for `0`.
824
+ * Can be used anywhere due to immutability.
825
+ * @since 1.3.0
826
+ * @example
827
+ * ```ts
828
+ * function count(): Result<number, Error> {
829
+ * return RESULT_ZERO;
830
+ * }
831
+ *
832
+ * const result: Result<number, string> = RESULT_ZERO;
833
+ * const value: number = RESULT_ZERO.intoOk(); // Safe extraction
834
+ * ```
835
+ */
836
+ const RESULT_ZERO = /* @__PURE__ */ Ok(0);
837
+ /**
838
+ * Result constant for `void` or `()`.
839
+ * Can be used anywhere due to immutability.
840
+ * @since 1.4.0
841
+ * @example
842
+ * ```ts
843
+ * function doSomething(): Result<void, Error> {
844
+ * return RESULT_VOID;
845
+ * }
846
+ *
847
+ * const result: Result<void, string> = RESULT_VOID;
848
+ * RESULT_VOID.intoOk(); // Safe extraction (returns undefined)
849
+ * ```
850
+ */
851
+ const RESULT_VOID = /* @__PURE__ */ Ok();
852
+ //#endregion
853
+ //#region src/core/result/extensions.ts
854
+ /**
855
+ * @module
856
+ * Extension functions for bridging standard JavaScript patterns with Result types.
857
+ *
858
+ * This module provides utilities for:
859
+ * - Converting try-catch patterns to Result-based error handling
860
+ * - Integrating async/await patterns with Result types
861
+ */
862
+ /**
863
+ * Executes a function and captures any thrown exception as an `Err`.
864
+ * If the function executes successfully, returns `Ok` with the result.
865
+ *
866
+ * Use this to convert traditional try-catch error handling to Result-based handling.
867
+ *
868
+ * Similar to `Promise.try`, this function accepts optional arguments that are passed to the function.
869
+ *
870
+ * @typeParam T - The type of the value returned by the function.
871
+ * @typeParam E - The type of the error that may be thrown, defaults to `Error`.
872
+ * @typeParam Args - The types of the arguments to pass to the function.
873
+ * @param fn - A function that may throw an exception.
874
+ * @param args - Arguments to pass to the function.
875
+ * @returns `Ok<T>` if the function succeeds, or `Err<E>` if it throws.
876
+ * @since 1.7.0
877
+ * @example
878
+ * ```ts
879
+ * // Parse JSON safely with arguments
880
+ * const result = tryResult(JSON.parse, jsonString);
881
+ * result.inspect(data => console.log('Parsed:', data))
882
+ * .inspectErr(err => console.error('Invalid JSON:', err));
883
+ * ```
884
+ *
885
+ * @example
886
+ * ```ts
887
+ * // Validate URL - using closure form
888
+ * const result = tryResult(() => new URL(input));
889
+ * if (result.isOk()) {
890
+ * console.log('Valid URL:', result.unwrap().href);
891
+ * }
892
+ * ```
893
+ *
894
+ * @example
895
+ * ```ts
896
+ * // With custom error type
897
+ * const result = tryResult<Config, ConfigError, [string]>(parseConfig, raw);
898
+ * ```
899
+ */
565
900
  function tryResult(fn, ...args) {
566
- try {
567
- return Ok(fn(...args));
568
- } catch (err) {
569
- return Err(err);
570
- }
901
+ try {
902
+ return Ok(fn(...args));
903
+ } catch (err) {
904
+ return Err(err);
905
+ }
571
906
  }
572
907
  async function tryAsyncResult(task, ...args) {
573
- try {
574
- const result = typeof task === "function" ? task(...args) : task;
575
- return Ok(await result);
576
- } catch (err) {
577
- return Err(err);
578
- }
908
+ try {
909
+ return Ok(await (typeof task === "function" ? task(...args) : task));
910
+ } catch (err) {
911
+ return Err(err);
912
+ }
579
913
  }
580
-
914
+ //#endregion
915
+ //#region src/std/ops/symbols.ts
916
+ /**
917
+ * @module
918
+ * Internal symbols used to identify `ControlFlow` type variants.
919
+ *
920
+ * These symbols are used as property keys to distinguish between `Break` and `Continue` variants.
921
+ * They provide a reliable way to identify the variant of a `ControlFlow` instance without
922
+ * relying on method calls or duck typing.
923
+ *
924
+ * Note: These symbols are internal implementation details and are not exported as part of the public API.
925
+ * Use the `isControlFlow` utility function for type checking instead.
926
+ */
927
+ /**
928
+ * A unique symbol used as a property key to identify the variant of a `ControlFlow` instance.
929
+ *
930
+ * When accessed on a `ControlFlow`, returns `'Break'` if the ControlFlow signals early exit,
931
+ * or `'Continue'` if it signals to proceed as normal.
932
+ *
933
+ * This symbol is used internally by the `isControlFlow` utility function to verify
934
+ * that an object is a valid `ControlFlow` instance.
935
+ *
936
+ * @internal
937
+ */
581
938
  const ControlFlowKindSymbol = /* @__PURE__ */ Symbol("ControlFlow kind");
582
-
939
+ //#endregion
940
+ //#region src/std/ops/control_flow.ts
941
+ /**
942
+ * @module
943
+ * Rust-inspired [ControlFlow](https://doc.rust-lang.org/std/ops/enum.ControlFlow.html) for control flow handling.
944
+ */
583
945
  function Break(value) {
584
- const brk = Object.freeze({
585
- [Symbol.toStringTag]: "ControlFlow",
586
- [ControlFlowKindSymbol]: "Break",
587
- toString() {
588
- return `Break(${value})`;
589
- },
590
- isBreak() {
591
- return true;
592
- },
593
- isContinue() {
594
- return false;
595
- },
596
- breakValue() {
597
- return Some(value);
598
- },
599
- continueValue() {
600
- return None;
601
- },
602
- mapBreak(fn) {
603
- return Break(fn(value));
604
- },
605
- mapContinue(_fn) {
606
- return brk;
607
- },
608
- breakOk() {
609
- return Ok(value);
610
- },
611
- continueOk() {
612
- return Err(value);
613
- },
614
- intoValue() {
615
- return value;
616
- }
617
- });
618
- return brk;
946
+ const brk = Object.freeze({
947
+ [Symbol.toStringTag]: "ControlFlow",
948
+ [ControlFlowKindSymbol]: "Break",
949
+ toString() {
950
+ return `Break(${value})`;
951
+ },
952
+ isBreak() {
953
+ return true;
954
+ },
955
+ isContinue() {
956
+ return false;
957
+ },
958
+ breakValue() {
959
+ return Some(value);
960
+ },
961
+ continueValue() {
962
+ return None;
963
+ },
964
+ mapBreak(fn) {
965
+ return Break(fn(value));
966
+ },
967
+ mapContinue(_fn) {
968
+ return brk;
969
+ },
970
+ breakOk() {
971
+ return Ok(value);
972
+ },
973
+ continueOk() {
974
+ return Err(value);
975
+ },
976
+ intoValue() {
977
+ return value;
978
+ }
979
+ });
980
+ return brk;
619
981
  }
620
982
  function Continue(value) {
621
- const cont = Object.freeze({
622
- [Symbol.toStringTag]: "ControlFlow",
623
- [ControlFlowKindSymbol]: "Continue",
624
- toString() {
625
- return `Continue(${value})`;
626
- },
627
- isBreak() {
628
- return false;
629
- },
630
- isContinue() {
631
- return true;
632
- },
633
- breakValue() {
634
- return None;
635
- },
636
- continueValue() {
637
- return Some(value);
638
- },
639
- mapBreak(_fn) {
640
- return cont;
641
- },
642
- mapContinue(fn) {
643
- return Continue(fn(value));
644
- },
645
- breakOk() {
646
- return Err(value);
647
- },
648
- continueOk() {
649
- return Ok(value);
650
- },
651
- intoValue() {
652
- return value;
653
- }
654
- });
655
- return cont;
983
+ const cont = Object.freeze({
984
+ [Symbol.toStringTag]: "ControlFlow",
985
+ [ControlFlowKindSymbol]: "Continue",
986
+ toString() {
987
+ return `Continue(${value})`;
988
+ },
989
+ isBreak() {
990
+ return false;
991
+ },
992
+ isContinue() {
993
+ return true;
994
+ },
995
+ breakValue() {
996
+ return None;
997
+ },
998
+ continueValue() {
999
+ return Some(value);
1000
+ },
1001
+ mapBreak(_fn) {
1002
+ return cont;
1003
+ },
1004
+ mapContinue(fn) {
1005
+ return Continue(fn(value));
1006
+ },
1007
+ breakOk() {
1008
+ return Err(value);
1009
+ },
1010
+ continueOk() {
1011
+ return Ok(value);
1012
+ },
1013
+ intoValue() {
1014
+ return value;
1015
+ }
1016
+ });
1017
+ return cont;
656
1018
  }
657
-
1019
+ //#endregion
1020
+ //#region src/std/ops/fn_once.ts
1021
+ /**
1022
+ * @module
1023
+ * Rust-inspired [FnOnce](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) for one-time callable functions.
1024
+ *
1025
+ * **When to use `FnOnce` vs `FnOnceAsync`:**
1026
+ * - Use `FnOnce` for sync functions
1027
+ * - Use `FnOnceAsync` for async functions
1028
+ */
1029
+ /**
1030
+ * Creates a `FnOnce` wrapper around a function, making it callable only once.
1031
+ *
1032
+ * @typeParam A - Tuple type of the function arguments.
1033
+ * @typeParam R - Return type of the function.
1034
+ * @param fn - The function to wrap.
1035
+ * @returns A `FnOnce` instance that wraps the function.
1036
+ * @example
1037
+ * ```ts
1038
+ * const initialize = FnOnce(() => {
1039
+ * console.log('Initializing...');
1040
+ * return { ready: true };
1041
+ * });
1042
+ *
1043
+ * const result = initialize.call(); // Logs 'Initializing...', returns { ready: true }
1044
+ * // initialize.call(); // Throws Error: FnOnce has already been consumed
1045
+ * ```
1046
+ */
658
1047
  function FnOnce(fn) {
659
- let consumed = false;
660
- return Object.freeze({
661
- [Symbol.toStringTag]: "FnOnce",
662
- toString() {
663
- return `FnOnce(${consumed ? "consumed" : "pending"})`;
664
- },
665
- call(...args) {
666
- if (consumed) {
667
- throw new Error("FnOnce has already been consumed");
668
- }
669
- consumed = true;
670
- return fn(...args);
671
- },
672
- tryCall(...args) {
673
- if (consumed) {
674
- return None;
675
- }
676
- consumed = true;
677
- return Some(fn(...args));
678
- },
679
- isConsumed() {
680
- return consumed;
681
- }
682
- });
1048
+ let consumed = false;
1049
+ return Object.freeze({
1050
+ [Symbol.toStringTag]: "FnOnce",
1051
+ toString() {
1052
+ return `FnOnce(${consumed ? "consumed" : "pending"})`;
1053
+ },
1054
+ call(...args) {
1055
+ if (consumed) throw new Error("FnOnce has already been consumed");
1056
+ consumed = true;
1057
+ return fn(...args);
1058
+ },
1059
+ tryCall(...args) {
1060
+ if (consumed) return None;
1061
+ consumed = true;
1062
+ return Some(fn(...args));
1063
+ },
1064
+ isConsumed() {
1065
+ return consumed;
1066
+ }
1067
+ });
683
1068
  }
684
-
1069
+ //#endregion
1070
+ //#region src/std/ops/fn_once_async.ts
1071
+ /**
1072
+ * @module
1073
+ * Rust-inspired [AsyncFnOnce](https://doc.rust-lang.org/std/ops/trait.AsyncFnOnce.html) for one-time callable async functions.
1074
+ *
1075
+ * **When to use `FnOnce` vs `FnOnceAsync`:**
1076
+ * - Use `FnOnce` for sync functions
1077
+ * - Use `FnOnceAsync` for async functions
1078
+ */
1079
+ /**
1080
+ * Creates a `FnOnceAsync` wrapper around an async function, making it callable only once.
1081
+ *
1082
+ * @typeParam A - Tuple type of the function arguments.
1083
+ * @typeParam R - The resolved type of the Promise returned by the async function.
1084
+ * @param fn - A function that returns `PromiseLike<R>` or `R`.
1085
+ * @returns A `FnOnceAsync` instance that wraps the function.
1086
+ * @example
1087
+ * ```ts
1088
+ * const initialize = FnOnceAsync(async () => {
1089
+ * console.log('Initializing...');
1090
+ * await loadResources();
1091
+ * return { ready: true };
1092
+ * });
1093
+ *
1094
+ * const result = await initialize.call(); // Logs 'Initializing...', returns { ready: true }
1095
+ * // await initialize.call(); // Throws Error: FnOnceAsync has already been consumed
1096
+ * ```
1097
+ */
685
1098
  function FnOnceAsync(fn) {
686
- let consumed = false;
687
- return Object.freeze({
688
- [Symbol.toStringTag]: "FnOnceAsync",
689
- toString() {
690
- return `FnOnceAsync(${consumed ? "consumed" : "pending"})`;
691
- },
692
- call(...args) {
693
- if (consumed) {
694
- throw new Error("FnOnceAsync has already been consumed");
695
- }
696
- consumed = true;
697
- return Promise.resolve(fn(...args));
698
- },
699
- // Use `Promise.resolve(fn())` instead of `async` to preserve sync error behavior:
700
- // sync throws propagate directly, async errors become rejected Promises.
701
- tryCall(...args) {
702
- if (consumed) {
703
- return ASYNC_NONE;
704
- }
705
- consumed = true;
706
- return Promise.resolve(fn(...args)).then(Some);
707
- },
708
- isConsumed() {
709
- return consumed;
710
- }
711
- });
1099
+ let consumed = false;
1100
+ return Object.freeze({
1101
+ [Symbol.toStringTag]: "FnOnceAsync",
1102
+ toString() {
1103
+ return `FnOnceAsync(${consumed ? "consumed" : "pending"})`;
1104
+ },
1105
+ call(...args) {
1106
+ if (consumed) throw new Error("FnOnceAsync has already been consumed");
1107
+ consumed = true;
1108
+ return Promise.resolve(fn(...args));
1109
+ },
1110
+ tryCall(...args) {
1111
+ if (consumed) return ASYNC_NONE;
1112
+ consumed = true;
1113
+ return Promise.resolve(fn(...args)).then(Some);
1114
+ },
1115
+ isConsumed() {
1116
+ return consumed;
1117
+ }
1118
+ });
712
1119
  }
713
-
1120
+ //#endregion
1121
+ //#region src/std/ops/guards.ts
1122
+ /**
1123
+ * Checks if a value is a `ControlFlow`.
1124
+ *
1125
+ * @typeParam B - The expected type of the break value contained within the `ControlFlow`.
1126
+ * @typeParam C - The expected type of the continue value contained within the `ControlFlow`.
1127
+ * @param cf - The value to be checked as a `ControlFlow`.
1128
+ * @returns `true` if the value is a `ControlFlow`, otherwise `false`.
1129
+ * @since 1.6.0
1130
+ * @example
1131
+ * ```ts
1132
+ * const x = Break(5);
1133
+ * console.log(isControlFlow(x)); // true
1134
+ * console.log(isControlFlow(null)); // false
1135
+ * console.log(isControlFlow({ isBreak: () => true })); // false
1136
+ * ```
1137
+ */
714
1138
  function isControlFlow(cf) {
715
- return cf != null && typeof cf === "object" && ControlFlowKindSymbol in cf;
1139
+ return cf != null && typeof cf === "object" && ControlFlowKindSymbol in cf;
716
1140
  }
717
-
718
- const ASYNC_TRUE = Promise.resolve(true);
719
- const ASYNC_FALSE = Promise.resolve(false);
1141
+ //#endregion
1142
+ //#region src/std/sync/channel.ts
1143
+ /**
1144
+ * @module
1145
+ * Rust-inspired MPMC (multi-producer multi-consumer) channel for async message passing.
1146
+ *
1147
+ * Provides a type-safe channel with optional bounded capacity and backpressure support.
1148
+ * Supports rendezvous (capacity=0) for synchronous handoff between sender and receiver.
1149
+ *
1150
+ */
1151
+ const ASYNC_TRUE = /* @__PURE__ */ Promise.resolve(true);
1152
+ const ASYNC_FALSE = /* @__PURE__ */ Promise.resolve(false);
1153
+ /**
1154
+ * Creates a new MPMC channel with the specified capacity.
1155
+ *
1156
+ * @typeParam T - The type of values that can be sent through the channel.
1157
+ * @param capacity - Maximum buffer size. Defaults to `Infinity` (unbounded).
1158
+ * Use `0` for a rendezvous channel (direct handoff).
1159
+ * @returns A new `Channel<T>` instance.
1160
+ * @throws {RangeError} If capacity is negative or not an integer (except Infinity).
1161
+ * @example
1162
+ * ```ts
1163
+ * // Unbounded channel (default)
1164
+ * const unbounded = Channel<string>();
1165
+ *
1166
+ * // Bounded channel with backpressure
1167
+ * const bounded = Channel<string>(100);
1168
+ *
1169
+ * // Rendezvous channel (synchronous handoff)
1170
+ * const rendezvous = Channel<string>(0);
1171
+ * ```
1172
+ *
1173
+ * @example
1174
+ * ```ts
1175
+ * // Task queue with backpressure
1176
+ * const taskQueue = Channel<() => Promise<void>>(10);
1177
+ *
1178
+ * // Worker
1179
+ * (async () => {
1180
+ * for await (const task of taskQueue) {
1181
+ * await task();
1182
+ * }
1183
+ * })();
1184
+ *
1185
+ * // Producer - will wait if queue is full
1186
+ * await taskQueue.send(async () => {
1187
+ * console.log('Processing...');
1188
+ * });
1189
+ * ```
1190
+ *
1191
+ * @example
1192
+ * ```ts
1193
+ * // Log aggregation with multiple producers
1194
+ * const logs = Channel<string>(1000);
1195
+ *
1196
+ * // Multiple producers
1197
+ * async function logFromService(name: string) {
1198
+ * const sender = logs.sender();
1199
+ * await sender.send(`[${name}] Started`);
1200
+ * // ... do work ...
1201
+ * await sender.send(`[${name}] Finished`);
1202
+ * }
1203
+ *
1204
+ * // Single consumer writing to file
1205
+ * async function writeLogsToFile() {
1206
+ * const receiver = logs.receiver();
1207
+ * for await (const log of receiver) {
1208
+ * await fs.appendFile('app.log', log + '\n');
1209
+ * }
1210
+ * }
1211
+ * ```
1212
+ */
720
1213
  function Channel(capacity = Infinity) {
721
- if (capacity < 0 || !Number.isInteger(capacity) && capacity !== Infinity) {
722
- throw new RangeError("Channel capacity must be a non-negative integer or Infinity");
723
- }
724
- const buffer = [];
725
- let closed = false;
726
- const sendWaitQueue = [];
727
- const receiveWaitQueue = [];
728
- let cachedSender;
729
- let cachedReceiver;
730
- function send(value) {
731
- if (closed) {
732
- return ASYNC_FALSE;
733
- }
734
- if (trySend(value)) {
735
- return ASYNC_TRUE;
736
- }
737
- return new Promise((resolve) => {
738
- sendWaitQueue.push({ value, resolve });
739
- });
740
- }
741
- function trySend(value) {
742
- if (closed) {
743
- return false;
744
- }
745
- if (receiveWaitQueue.length > 0) {
746
- const receiver = receiveWaitQueue.shift();
747
- receiver(Some(value));
748
- return true;
749
- }
750
- if (buffer.length < capacity) {
751
- buffer.push(value);
752
- return true;
753
- }
754
- return false;
755
- }
756
- function receive() {
757
- const result = tryReceive();
758
- if (result.isSome()) {
759
- return Promise.resolve(result);
760
- }
761
- if (closed) {
762
- return ASYNC_NONE;
763
- }
764
- return new Promise((resolve) => {
765
- receiveWaitQueue.push(resolve);
766
- });
767
- }
768
- function tryReceive() {
769
- if (buffer.length > 0) {
770
- const value = buffer.shift();
771
- if (sendWaitQueue.length > 0) {
772
- const sender = sendWaitQueue.shift();
773
- buffer.push(sender.value);
774
- sender.resolve(true);
775
- }
776
- return Some(value);
777
- }
778
- if (sendWaitQueue.length > 0) {
779
- const sender = sendWaitQueue.shift();
780
- sender.resolve(true);
781
- return Some(sender.value);
782
- }
783
- return None;
784
- }
785
- function close() {
786
- if (closed) {
787
- return;
788
- }
789
- closed = true;
790
- while (sendWaitQueue.length > 0) {
791
- const sender = sendWaitQueue.shift();
792
- sender.resolve(false);
793
- }
794
- while (receiveWaitQueue.length > 0) {
795
- const receiver = receiveWaitQueue.shift();
796
- receiver(None);
797
- }
798
- }
799
- function sendTimeout(value, ms) {
800
- if (closed) {
801
- return ASYNC_FALSE;
802
- }
803
- if (trySend(value)) {
804
- return ASYNC_TRUE;
805
- }
806
- return new Promise((resolve) => {
807
- const waiter = { value, resolve };
808
- sendWaitQueue.push(waiter);
809
- const timeoutId = setTimeout(() => {
810
- const index = sendWaitQueue.indexOf(waiter);
811
- sendWaitQueue.splice(index, 1);
812
- resolve(false);
813
- }, ms);
814
- const originalResolve = waiter.resolve;
815
- waiter.resolve = (success) => {
816
- clearTimeout(timeoutId);
817
- originalResolve(success);
818
- };
819
- });
820
- }
821
- function receiveTimeout(ms) {
822
- const result = tryReceive();
823
- if (result.isSome()) {
824
- return Promise.resolve(result);
825
- }
826
- if (closed) {
827
- return ASYNC_NONE;
828
- }
829
- return new Promise((resolve) => {
830
- const wrappedWaiter = (value) => {
831
- clearTimeout(timeoutId);
832
- resolve(value);
833
- };
834
- receiveWaitQueue.push(wrappedWaiter);
835
- const timeoutId = setTimeout(() => {
836
- const index = receiveWaitQueue.indexOf(wrappedWaiter);
837
- receiveWaitQueue.splice(index, 1);
838
- resolve(None);
839
- }, ms);
840
- });
841
- }
842
- function asyncIterator() {
843
- return {
844
- async next() {
845
- const result = await receive();
846
- if (result.isNone()) {
847
- return { done: true, value: void 0 };
848
- }
849
- return { done: false, value: result.unwrap() };
850
- }
851
- };
852
- }
853
- function createSender() {
854
- return Object.freeze({
855
- [Symbol.toStringTag]: "Sender",
856
- toString() {
857
- if (closed) {
858
- return "Sender(<closed>)";
859
- }
860
- if (capacity === Infinity) {
861
- return `Sender(${buffer.length}/∞)`;
862
- }
863
- return `Sender(${buffer.length}/${capacity})`;
864
- },
865
- get capacity() {
866
- return capacity;
867
- },
868
- get length() {
869
- return buffer.length;
870
- },
871
- get isClosed() {
872
- return closed;
873
- },
874
- get isEmpty() {
875
- return buffer.length === 0;
876
- },
877
- get isFull() {
878
- return buffer.length >= capacity;
879
- },
880
- send,
881
- trySend,
882
- sendTimeout
883
- });
884
- }
885
- function createReceiver() {
886
- return Object.freeze({
887
- [Symbol.toStringTag]: "Receiver",
888
- [Symbol.asyncIterator]: asyncIterator,
889
- toString() {
890
- if (closed) {
891
- return "Receiver(<closed>)";
892
- }
893
- if (capacity === Infinity) {
894
- return `Receiver(${buffer.length}/∞)`;
895
- }
896
- return `Receiver(${buffer.length}/${capacity})`;
897
- },
898
- get capacity() {
899
- return capacity;
900
- },
901
- get length() {
902
- return buffer.length;
903
- },
904
- get isClosed() {
905
- return closed;
906
- },
907
- get isEmpty() {
908
- return buffer.length === 0;
909
- },
910
- get isFull() {
911
- return buffer.length >= capacity;
912
- },
913
- receive,
914
- tryReceive,
915
- receiveTimeout
916
- });
917
- }
918
- return Object.freeze({
919
- [Symbol.toStringTag]: "Channel",
920
- [Symbol.asyncIterator]: asyncIterator,
921
- toString() {
922
- if (closed) {
923
- return "Channel(<closed>)";
924
- }
925
- if (capacity === Infinity) {
926
- return `Channel(${buffer.length}/∞)`;
927
- }
928
- return `Channel(${buffer.length}/${capacity})`;
929
- },
930
- get capacity() {
931
- return capacity;
932
- },
933
- get length() {
934
- return buffer.length;
935
- },
936
- get isClosed() {
937
- return closed;
938
- },
939
- get isEmpty() {
940
- return buffer.length === 0;
941
- },
942
- get isFull() {
943
- return buffer.length >= capacity;
944
- },
945
- get sender() {
946
- return cachedSender ??= createSender();
947
- },
948
- get receiver() {
949
- return cachedReceiver ??= createReceiver();
950
- },
951
- send,
952
- trySend,
953
- sendTimeout,
954
- receive,
955
- tryReceive,
956
- receiveTimeout,
957
- close
958
- });
1214
+ if (capacity < 0 || !Number.isInteger(capacity) && capacity !== Infinity) throw new RangeError("Channel capacity must be a non-negative integer or Infinity");
1215
+ const buffer = new Queue();
1216
+ let closed = false;
1217
+ const sendWaitQueue = [];
1218
+ const receiveWaitQueue = [];
1219
+ let cachedSender;
1220
+ let cachedReceiver;
1221
+ function send(value) {
1222
+ if (closed) return ASYNC_FALSE;
1223
+ if (trySend(value)) return ASYNC_TRUE;
1224
+ return new Promise((resolve) => {
1225
+ sendWaitQueue.push({
1226
+ value,
1227
+ resolve
1228
+ });
1229
+ });
1230
+ }
1231
+ function trySend(value) {
1232
+ if (closed) return false;
1233
+ if (receiveWaitQueue.length > 0) {
1234
+ receiveWaitQueue.shift()(Some(value));
1235
+ return true;
1236
+ }
1237
+ if (buffer.length < capacity) {
1238
+ buffer.push(value);
1239
+ return true;
1240
+ }
1241
+ return false;
1242
+ }
1243
+ function receive() {
1244
+ const result = tryReceive();
1245
+ if (result.isSome()) return Promise.resolve(result);
1246
+ if (closed) return ASYNC_NONE;
1247
+ return new Promise((resolve) => {
1248
+ receiveWaitQueue.push(resolve);
1249
+ });
1250
+ }
1251
+ function tryReceive() {
1252
+ if (buffer.length > 0) {
1253
+ const value = buffer.shift();
1254
+ if (sendWaitQueue.length > 0) {
1255
+ const sender = sendWaitQueue.shift();
1256
+ buffer.push(sender.value);
1257
+ sender.resolve(true);
1258
+ }
1259
+ return Some(value);
1260
+ }
1261
+ if (sendWaitQueue.length > 0) {
1262
+ const sender = sendWaitQueue.shift();
1263
+ sender.resolve(true);
1264
+ return Some(sender.value);
1265
+ }
1266
+ return None;
1267
+ }
1268
+ function close() {
1269
+ if (closed) return;
1270
+ closed = true;
1271
+ while (sendWaitQueue.length > 0) sendWaitQueue.shift().resolve(false);
1272
+ while (receiveWaitQueue.length > 0) receiveWaitQueue.shift()(None);
1273
+ }
1274
+ function sendTimeout(value, ms) {
1275
+ if (closed) return ASYNC_FALSE;
1276
+ if (trySend(value)) return ASYNC_TRUE;
1277
+ return new Promise((resolve) => {
1278
+ const waiter = {
1279
+ value,
1280
+ resolve
1281
+ };
1282
+ sendWaitQueue.push(waiter);
1283
+ const timeoutId = setTimeout(() => {
1284
+ const index = sendWaitQueue.indexOf(waiter);
1285
+ sendWaitQueue.splice(index, 1);
1286
+ resolve(false);
1287
+ }, ms);
1288
+ const originalResolve = waiter.resolve;
1289
+ waiter.resolve = (success) => {
1290
+ clearTimeout(timeoutId);
1291
+ originalResolve(success);
1292
+ };
1293
+ });
1294
+ }
1295
+ function receiveTimeout(ms) {
1296
+ const result = tryReceive();
1297
+ if (result.isSome()) return Promise.resolve(result);
1298
+ if (closed) return ASYNC_NONE;
1299
+ return new Promise((resolve) => {
1300
+ const wrappedWaiter = (value) => {
1301
+ clearTimeout(timeoutId);
1302
+ resolve(value);
1303
+ };
1304
+ receiveWaitQueue.push(wrappedWaiter);
1305
+ const timeoutId = setTimeout(() => {
1306
+ const index = receiveWaitQueue.indexOf(wrappedWaiter);
1307
+ receiveWaitQueue.splice(index, 1);
1308
+ resolve(None);
1309
+ }, ms);
1310
+ });
1311
+ }
1312
+ function asyncIterator() {
1313
+ return { async next() {
1314
+ const result = await receive();
1315
+ if (result.isNone()) return {
1316
+ done: true,
1317
+ value: void 0
1318
+ };
1319
+ return {
1320
+ done: false,
1321
+ value: result.unwrap()
1322
+ };
1323
+ } };
1324
+ }
1325
+ function createSender() {
1326
+ return Object.freeze({
1327
+ [Symbol.toStringTag]: "Sender",
1328
+ toString() {
1329
+ if (closed) return "Sender(<closed>)";
1330
+ if (capacity === Infinity) return `Sender(${buffer.length}/∞)`;
1331
+ return `Sender(${buffer.length}/${capacity})`;
1332
+ },
1333
+ get capacity() {
1334
+ return capacity;
1335
+ },
1336
+ get length() {
1337
+ return buffer.length;
1338
+ },
1339
+ get isClosed() {
1340
+ return closed;
1341
+ },
1342
+ get isEmpty() {
1343
+ return buffer.length === 0;
1344
+ },
1345
+ get isFull() {
1346
+ return buffer.length >= capacity;
1347
+ },
1348
+ send,
1349
+ trySend,
1350
+ sendTimeout
1351
+ });
1352
+ }
1353
+ function createReceiver() {
1354
+ return Object.freeze({
1355
+ [Symbol.toStringTag]: "Receiver",
1356
+ [Symbol.asyncIterator]: asyncIterator,
1357
+ toString() {
1358
+ if (closed) return "Receiver(<closed>)";
1359
+ if (capacity === Infinity) return `Receiver(${buffer.length}/∞)`;
1360
+ return `Receiver(${buffer.length}/${capacity})`;
1361
+ },
1362
+ get capacity() {
1363
+ return capacity;
1364
+ },
1365
+ get length() {
1366
+ return buffer.length;
1367
+ },
1368
+ get isClosed() {
1369
+ return closed;
1370
+ },
1371
+ get isEmpty() {
1372
+ return buffer.length === 0;
1373
+ },
1374
+ get isFull() {
1375
+ return buffer.length >= capacity;
1376
+ },
1377
+ receive,
1378
+ tryReceive,
1379
+ receiveTimeout
1380
+ });
1381
+ }
1382
+ return Object.freeze({
1383
+ [Symbol.toStringTag]: "Channel",
1384
+ [Symbol.asyncIterator]: asyncIterator,
1385
+ toString() {
1386
+ if (closed) return "Channel(<closed>)";
1387
+ if (capacity === Infinity) return `Channel(${buffer.length}/∞)`;
1388
+ return `Channel(${buffer.length}/${capacity})`;
1389
+ },
1390
+ get capacity() {
1391
+ return capacity;
1392
+ },
1393
+ get length() {
1394
+ return buffer.length;
1395
+ },
1396
+ get isClosed() {
1397
+ return closed;
1398
+ },
1399
+ get isEmpty() {
1400
+ return buffer.length === 0;
1401
+ },
1402
+ get isFull() {
1403
+ return buffer.length >= capacity;
1404
+ },
1405
+ get sender() {
1406
+ return cachedSender ??= createSender();
1407
+ },
1408
+ get receiver() {
1409
+ return cachedReceiver ??= createReceiver();
1410
+ },
1411
+ send,
1412
+ trySend,
1413
+ sendTimeout,
1414
+ receive,
1415
+ tryReceive,
1416
+ receiveTimeout,
1417
+ close
1418
+ });
959
1419
  }
960
-
1420
+ /**
1421
+ * A fast FIFO queue implementation using an array and an offset pointer.
1422
+ * This avoids the O(n) overhead of Array.shift() by simply incrementing the offset.
1423
+ *
1424
+ * When the offset exceeds a threshold (1024) and more than half the array is empty,
1425
+ * the array is compacted by slicing. The threshold 1024 was chosen empirically:
1426
+ * - Too small: frequent compaction overhead
1427
+ * - Too large: excessive memory waste
1428
+ * - 1024 balances compaction frequency and memory usage across typical workloads
1429
+ *
1430
+ * Benchmark results show minimal performance difference between thresholds (64-16384),
1431
+ * so 1024 is a reasonable default that works well for most Channel use cases.
1432
+ */
1433
+ var Queue = class {
1434
+ data = [];
1435
+ offset = 0;
1436
+ get length() {
1437
+ return this.data.length - this.offset;
1438
+ }
1439
+ push(item) {
1440
+ this.data.push(item);
1441
+ }
1442
+ shift() {
1443
+ const item = this.data[this.offset];
1444
+ this.data[this.offset] = void 0;
1445
+ this.offset++;
1446
+ if (this.offset > 1024 && this.offset * 2 > this.data.length) {
1447
+ this.data = this.data.slice(this.offset);
1448
+ this.offset = 0;
1449
+ }
1450
+ return item;
1451
+ }
1452
+ };
1453
+ //#endregion
1454
+ //#region src/std/sync/lazy.ts
1455
+ /**
1456
+ * @module
1457
+ * Rust-inspired [LazyLock](https://doc.rust-lang.org/std/sync/struct.LazyLock.html) for lazy initialization.
1458
+ *
1459
+ * Unlike `Once<T>`, which allows setting values manually or with different
1460
+ * initializers, `Lazy<T>` binds the initializer at creation time.
1461
+ *
1462
+ * **When to use `Lazy<T>` vs `LazyAsync<T>`:**
1463
+ * - Use `Lazy<T>` for sync-only initialization
1464
+ * - Use `LazyAsync<T>` for async initialization with concurrent call handling
1465
+ */
1466
+ /**
1467
+ * Creates a new `Lazy<T>` with the given synchronous initialization function.
1468
+ *
1469
+ * The function is called at most once, on first access via `force()`.
1470
+ *
1471
+ * @typeParam T - The type of value to store.
1472
+ * @param fn - The initialization function that produces the value.
1473
+ * @returns A new `Lazy<T>` instance.
1474
+ * @example
1475
+ * ```ts
1476
+ * // Basic usage
1477
+ * const lazy = Lazy(() => {
1478
+ * console.log('Initializing');
1479
+ * return 42;
1480
+ * });
1481
+ *
1482
+ * console.log(lazy.isInitialized()); // false
1483
+ * console.log(lazy.force()); // logs "Initializing", returns 42
1484
+ * console.log(lazy.isInitialized()); // true
1485
+ * console.log(lazy.force()); // returns 42 (no log)
1486
+ * ```
1487
+ *
1488
+ * @example
1489
+ * ```ts
1490
+ * // Lazy singleton pattern
1491
+ * const logger = Lazy(() => new Logger('app'));
1492
+ *
1493
+ * function getLogger(): Logger {
1494
+ * return logger.force();
1495
+ * }
1496
+ * ```
1497
+ *
1498
+ * @example
1499
+ * ```ts
1500
+ * // Expensive computation
1501
+ * const fibonacci = Lazy(() => {
1502
+ * function fib(n: number): number {
1503
+ * if (n <= 1) return n;
1504
+ * return fib(n - 1) + fib(n - 2);
1505
+ * }
1506
+ * return fib(40); // Only computed once
1507
+ * });
1508
+ * ```
1509
+ */
961
1510
  function Lazy(fn) {
962
- let value;
963
- let initialized = false;
964
- return Object.freeze({
965
- [Symbol.toStringTag]: "Lazy",
966
- toString() {
967
- return initialized ? `Lazy(${value})` : "Lazy(<uninitialized>)";
968
- },
969
- force() {
970
- if (!initialized) {
971
- value = fn();
972
- initialized = true;
973
- }
974
- return value;
975
- },
976
- get() {
977
- return initialized ? Some(value) : None;
978
- },
979
- isInitialized() {
980
- return initialized;
981
- }
982
- });
1511
+ let value;
1512
+ let initialized = false;
1513
+ return Object.freeze({
1514
+ [Symbol.toStringTag]: "Lazy",
1515
+ toString() {
1516
+ return initialized ? `Lazy(${value})` : "Lazy(<uninitialized>)";
1517
+ },
1518
+ force() {
1519
+ if (!initialized) {
1520
+ value = fn();
1521
+ initialized = true;
1522
+ }
1523
+ return value;
1524
+ },
1525
+ get() {
1526
+ return initialized ? Some(value) : None;
1527
+ },
1528
+ isInitialized() {
1529
+ return initialized;
1530
+ }
1531
+ });
983
1532
  }
984
-
1533
+ //#endregion
1534
+ //#region src/std/sync/lazy_async.ts
1535
+ /**
1536
+ * @module
1537
+ * Rust-inspired [LazyLock](https://doc.rust-lang.org/std/sync/struct.LazyLock.html) for async lazy initialization.
1538
+ *
1539
+ * **When to use `Lazy<T>` vs `LazyAsync<T>`:**
1540
+ * - Use `Lazy<T>` for sync-only initialization
1541
+ * - Use `LazyAsync<T>` for async initialization with concurrent call handling
1542
+ */
1543
+ /**
1544
+ * Creates a new `LazyAsync<T>` with the given async initialization function.
1545
+ *
1546
+ * The function is called at most once, on first access via `force()`.
1547
+ * Concurrent calls to `force()` before initialization completes will
1548
+ * wait for the single initialization to finish.
1549
+ *
1550
+ * @typeParam T - The type of value to store.
1551
+ * @param fn - A function that returns `PromiseLike<T>` or `T` to initialize.
1552
+ * @returns A new `LazyAsync<T>` instance.
1553
+ * @example
1554
+ * ```ts
1555
+ * // Basic usage
1556
+ * const lazy = LazyAsync(async () => {
1557
+ * const response = await fetch('/api/data');
1558
+ * return await response.json();
1559
+ * });
1560
+ *
1561
+ * const data = await lazy.force();
1562
+ * ```
1563
+ *
1564
+ * @example
1565
+ * ```ts
1566
+ * // Database connection singleton
1567
+ * const db = LazyAsync(async () => {
1568
+ * console.log('Connecting to database...');
1569
+ * return await Database.connect(connectionString);
1570
+ * });
1571
+ *
1572
+ * async function getDb(): Promise<Database> {
1573
+ * return await db.force();
1574
+ * }
1575
+ *
1576
+ * // Multiple calls - connection happens only once
1577
+ * const [db1, db2] = await Promise.all([getDb(), getDb()]);
1578
+ * console.log(db1 === db2); // true
1579
+ * ```
1580
+ *
1581
+ * @example
1582
+ * ```ts
1583
+ * // Configuration loader
1584
+ * const config = LazyAsync(async () => {
1585
+ * const response = await fetch('/api/config');
1586
+ * if (!response.ok) {
1587
+ * throw new Error(`Failed to load config: ${response.status}`);
1588
+ * }
1589
+ * return await response.json() as Config;
1590
+ * });
1591
+ *
1592
+ * // Used throughout the app
1593
+ * async function getApiEndpoint(): Promise<string> {
1594
+ * const cfg = await config.force();
1595
+ * return cfg.apiEndpoint;
1596
+ * }
1597
+ * ```
1598
+ */
985
1599
  function LazyAsync(fn) {
986
- let value;
987
- let initialized = false;
988
- let pendingPromise;
989
- return Object.freeze({
990
- [Symbol.toStringTag]: "LazyAsync",
991
- toString() {
992
- return initialized ? `LazyAsync(${value})` : "LazyAsync(<uninitialized>)";
993
- },
994
- // Use `Promise.resolve(fn())` instead of `async` to preserve sync error behavior:
995
- // sync throws propagate directly, async errors become rejected Promises.
996
- force() {
997
- if (initialized) {
998
- return pendingPromise ??= Promise.resolve(value);
999
- }
1000
- if (pendingPromise) {
1001
- return pendingPromise;
1002
- }
1003
- pendingPromise = Promise.resolve(fn()).then(
1004
- (result) => {
1005
- value = result;
1006
- initialized = true;
1007
- return result;
1008
- }
1009
- ).catch((err) => {
1010
- pendingPromise = void 0;
1011
- throw err;
1012
- });
1013
- return pendingPromise;
1014
- },
1015
- get() {
1016
- return initialized ? Some(value) : None;
1017
- },
1018
- isInitialized() {
1019
- return initialized;
1020
- }
1021
- });
1600
+ let value;
1601
+ let initialized = false;
1602
+ let pendingPromise;
1603
+ return Object.freeze({
1604
+ [Symbol.toStringTag]: "LazyAsync",
1605
+ toString() {
1606
+ return initialized ? `LazyAsync(${value})` : "LazyAsync(<uninitialized>)";
1607
+ },
1608
+ force() {
1609
+ if (initialized) return pendingPromise ??= Promise.resolve(value);
1610
+ if (pendingPromise) return pendingPromise;
1611
+ pendingPromise = Promise.resolve(fn()).then((result) => {
1612
+ value = result;
1613
+ initialized = true;
1614
+ return result;
1615
+ }).catch((err) => {
1616
+ pendingPromise = void 0;
1617
+ throw err;
1618
+ });
1619
+ return pendingPromise;
1620
+ },
1621
+ get() {
1622
+ return initialized ? Some(value) : None;
1623
+ },
1624
+ isInitialized() {
1625
+ return initialized;
1626
+ }
1627
+ });
1022
1628
  }
1023
-
1629
+ //#endregion
1630
+ //#region src/std/sync/mutex.ts
1631
+ /**
1632
+ * @module
1633
+ * Rust-inspired [Mutex](https://doc.rust-lang.org/std/sync/struct.Mutex.html) for async mutual exclusion.
1634
+ *
1635
+ * In JavaScript's single-threaded environment, `Mutex<T>` is used to serialize
1636
+ * async operations, ensuring only one async task accesses the protected resource at a time.
1637
+ */
1638
+ /**
1639
+ * Creates a new `Mutex<T>` protecting the given value.
1640
+ *
1641
+ * @typeParam T - The type of the protected value.
1642
+ * @param value - The initial value to protect.
1643
+ * @returns A new `Mutex<T>` instance.
1644
+ * @example
1645
+ * ```ts
1646
+ * // Protect a simple value
1647
+ * const counter = Mutex(0);
1648
+ *
1649
+ * // Protect an object
1650
+ * const state = Mutex({ users: [], lastUpdate: Date.now() });
1651
+ *
1652
+ * // Protect a resource
1653
+ * const db = Mutex(await createConnection());
1654
+ * ```
1655
+ *
1656
+ * @example
1657
+ * ```ts
1658
+ * // Database transaction safety
1659
+ * const connection = Mutex(db);
1660
+ *
1661
+ * async function transfer(from: string, to: string, amount: number) {
1662
+ * await connection.withLock(async (conn) => {
1663
+ * await conn.beginTransaction();
1664
+ * try {
1665
+ * const balance = await conn.query('SELECT balance FROM accounts WHERE id = ?', [from]);
1666
+ * if (balance < amount) {
1667
+ * throw new Error('Insufficient funds');
1668
+ * }
1669
+ * await conn.query('UPDATE accounts SET balance = balance - ? WHERE id = ?', [amount, from]);
1670
+ * await conn.query('UPDATE accounts SET balance = balance + ? WHERE id = ?', [amount, to]);
1671
+ * await conn.commit();
1672
+ * } catch (e) {
1673
+ * await conn.rollback();
1674
+ * throw e;
1675
+ * }
1676
+ * });
1677
+ * }
1678
+ * ```
1679
+ *
1680
+ * @example
1681
+ * ```ts
1682
+ * // Token refresh with mutex
1683
+ * const authState = Mutex({ token: '', expiresAt: 0 });
1684
+ *
1685
+ * async function getToken(): Promise<string> {
1686
+ * return await authState.withLock(async (state) => {
1687
+ * if (Date.now() > state.expiresAt) {
1688
+ * const response = await fetch('/api/refresh');
1689
+ * const data = await response.json();
1690
+ * state.token = data.token;
1691
+ * state.expiresAt = Date.now() + data.expiresIn * 1000;
1692
+ * }
1693
+ * return state.token;
1694
+ * });
1695
+ * }
1696
+ * ```
1697
+ *
1698
+ * @example
1699
+ * ```ts
1700
+ * // File write serialization
1701
+ * const fileLock = Mutex('/path/to/file.json');
1702
+ *
1703
+ * async function appendToFile(data: string) {
1704
+ * await fileLock.withLock(async (path) => {
1705
+ * const content = await fs.readFile(path, 'utf-8');
1706
+ * const json = JSON.parse(content);
1707
+ * json.entries.push(data);
1708
+ * await fs.writeFile(path, JSON.stringify(json, null, 2));
1709
+ * });
1710
+ * }
1711
+ * ```
1712
+ */
1024
1713
  function Mutex(value) {
1025
- let currentValue = value;
1026
- let locked = false;
1027
- const waitQueue = [];
1028
- function unlock() {
1029
- if (waitQueue.length > 0) {
1030
- const next = waitQueue.shift();
1031
- next();
1032
- } else {
1033
- locked = false;
1034
- }
1035
- }
1036
- function createGuard() {
1037
- let released = false;
1038
- return Object.freeze({
1039
- [Symbol.toStringTag]: "MutexGuard",
1040
- toString() {
1041
- if (released) {
1042
- return "MutexGuard(<released>)";
1043
- }
1044
- return `MutexGuard(${currentValue})`;
1045
- },
1046
- get value() {
1047
- if (released) {
1048
- throw new Error("MutexGuard has been released");
1049
- }
1050
- return currentValue;
1051
- },
1052
- set value(newValue) {
1053
- if (released) {
1054
- throw new Error("MutexGuard has been released");
1055
- }
1056
- currentValue = newValue;
1057
- },
1058
- unlock() {
1059
- if (released) {
1060
- return;
1061
- }
1062
- released = true;
1063
- unlock();
1064
- }
1065
- });
1066
- }
1067
- function lock() {
1068
- if (!locked) {
1069
- locked = true;
1070
- return Promise.resolve(createGuard());
1071
- }
1072
- return new Promise((resolve) => {
1073
- waitQueue.push(() => {
1074
- resolve(createGuard());
1075
- });
1076
- });
1077
- }
1078
- return Object.freeze({
1079
- [Symbol.toStringTag]: "Mutex",
1080
- toString() {
1081
- return locked ? "Mutex(<locked>)" : "Mutex(<unlocked>)";
1082
- },
1083
- async withLock(fn) {
1084
- const guard = await lock();
1085
- try {
1086
- return await fn(guard.value);
1087
- } finally {
1088
- guard.unlock();
1089
- }
1090
- },
1091
- lock,
1092
- tryLock() {
1093
- if (locked) {
1094
- return None;
1095
- }
1096
- locked = true;
1097
- return Some(createGuard());
1098
- },
1099
- isLocked() {
1100
- return locked;
1101
- },
1102
- async get() {
1103
- const guard = await lock();
1104
- try {
1105
- return guard.value;
1106
- } finally {
1107
- guard.unlock();
1108
- }
1109
- },
1110
- async set(value2) {
1111
- const guard = await lock();
1112
- try {
1113
- guard.value = value2;
1114
- } finally {
1115
- guard.unlock();
1116
- }
1117
- },
1118
- async replace(value2) {
1119
- const guard = await lock();
1120
- try {
1121
- const old = guard.value;
1122
- guard.value = value2;
1123
- return old;
1124
- } finally {
1125
- guard.unlock();
1126
- }
1127
- }
1128
- });
1714
+ let currentValue = value;
1715
+ let locked = false;
1716
+ const waitQueue = [];
1717
+ function unlock() {
1718
+ if (waitQueue.length > 0) waitQueue.shift()();
1719
+ else locked = false;
1720
+ }
1721
+ function createGuard() {
1722
+ let released = false;
1723
+ return Object.freeze({
1724
+ [Symbol.toStringTag]: "MutexGuard",
1725
+ toString() {
1726
+ if (released) return "MutexGuard(<released>)";
1727
+ return `MutexGuard(${currentValue})`;
1728
+ },
1729
+ get value() {
1730
+ if (released) throw new Error("MutexGuard has been released");
1731
+ return currentValue;
1732
+ },
1733
+ set value(newValue) {
1734
+ if (released) throw new Error("MutexGuard has been released");
1735
+ currentValue = newValue;
1736
+ },
1737
+ unlock() {
1738
+ if (released) return;
1739
+ released = true;
1740
+ unlock();
1741
+ }
1742
+ });
1743
+ }
1744
+ function lock() {
1745
+ if (!locked) {
1746
+ locked = true;
1747
+ return Promise.resolve(createGuard());
1748
+ }
1749
+ return new Promise((resolve) => {
1750
+ waitQueue.push(() => {
1751
+ resolve(createGuard());
1752
+ });
1753
+ });
1754
+ }
1755
+ return Object.freeze({
1756
+ [Symbol.toStringTag]: "Mutex",
1757
+ toString() {
1758
+ return locked ? "Mutex(<locked>)" : "Mutex(<unlocked>)";
1759
+ },
1760
+ async withLock(fn) {
1761
+ const guard = await lock();
1762
+ try {
1763
+ return await fn(guard.value);
1764
+ } finally {
1765
+ guard.unlock();
1766
+ }
1767
+ },
1768
+ lock,
1769
+ tryLock() {
1770
+ if (locked) return None;
1771
+ locked = true;
1772
+ return Some(createGuard());
1773
+ },
1774
+ isLocked() {
1775
+ return locked;
1776
+ },
1777
+ async get() {
1778
+ const guard = await lock();
1779
+ try {
1780
+ return guard.value;
1781
+ } finally {
1782
+ guard.unlock();
1783
+ }
1784
+ },
1785
+ async set(value) {
1786
+ const guard = await lock();
1787
+ try {
1788
+ guard.value = value;
1789
+ } finally {
1790
+ guard.unlock();
1791
+ }
1792
+ },
1793
+ async replace(value) {
1794
+ const guard = await lock();
1795
+ try {
1796
+ const old = guard.value;
1797
+ guard.value = value;
1798
+ return old;
1799
+ } finally {
1800
+ guard.unlock();
1801
+ }
1802
+ }
1803
+ });
1129
1804
  }
1130
-
1805
+ //#endregion
1806
+ //#region src/std/sync/once.ts
1807
+ /**
1808
+ * @module
1809
+ * Rust-inspired [OnceLock](https://doc.rust-lang.org/std/sync/struct.OnceLock.html) for one-time initialization.
1810
+ *
1811
+ * `Once<T>` is a container which can be written to only once. It provides safe access
1812
+ * to lazily initialized data with synchronous initialization.
1813
+ *
1814
+ * **When to use `Once<T>` vs `OnceAsync<T>`:**
1815
+ * - Use `Once<T>` for sync-only initialization
1816
+ * - Use `OnceAsync<T>` for async initialization with concurrent call handling
1817
+ */
1818
+ /**
1819
+ * Creates a new empty `Once<T>`.
1820
+ *
1821
+ * @typeParam T - The type of value to store.
1822
+ * @returns A new uninitialized `Once`.
1823
+ * @example
1824
+ * ```ts
1825
+ * // Basic usage
1826
+ * const once = Once<string>();
1827
+ * once.set('hello');
1828
+ * console.log(once.get().unwrap()); // 'hello'
1829
+ * ```
1830
+ *
1831
+ * @example
1832
+ * ```ts
1833
+ * // Sync lazy singleton pattern
1834
+ * const logger = Once<Logger>();
1835
+ *
1836
+ * function getLogger(): Logger {
1837
+ * return logger.getOrInit(() => new Logger('app'));
1838
+ * }
1839
+ * ```
1840
+ *
1841
+ * @example
1842
+ * ```ts
1843
+ * // Fallible sync initialization
1844
+ * const config = Once<Config>();
1845
+ *
1846
+ * function loadConfig(): Result<Config, Error> {
1847
+ * return config.getOrTryInit(() => {
1848
+ * const data = readFileSync('config.json');
1849
+ * return data ? Ok(JSON.parse(data)) : Err(new Error('Config not found'));
1850
+ * });
1851
+ * }
1852
+ * ```
1853
+ */
1131
1854
  function Once() {
1132
- let value;
1133
- let initialized = false;
1134
- function setValue(val) {
1135
- value = val;
1136
- initialized = true;
1137
- }
1138
- return Object.freeze({
1139
- [Symbol.toStringTag]: "Once",
1140
- toString() {
1141
- return initialized ? `Once(${value})` : "Once(<uninitialized>)";
1142
- },
1143
- get() {
1144
- return initialized ? Some(value) : None;
1145
- },
1146
- set(newValue) {
1147
- if (initialized) {
1148
- return Err(newValue);
1149
- }
1150
- setValue(newValue);
1151
- return RESULT_VOID;
1152
- },
1153
- tryInsert(newValue) {
1154
- if (initialized) {
1155
- return Err([value, newValue]);
1156
- }
1157
- setValue(newValue);
1158
- return Ok(newValue);
1159
- },
1160
- getOrInit(fn) {
1161
- if (!initialized) {
1162
- setValue(fn());
1163
- }
1164
- return value;
1165
- },
1166
- getOrTryInit(fn) {
1167
- if (initialized) {
1168
- return Ok(value);
1169
- }
1170
- const result = fn();
1171
- if (result.isOk()) {
1172
- setValue(result.unwrap());
1173
- }
1174
- return result;
1175
- },
1176
- take() {
1177
- if (!initialized) {
1178
- return None;
1179
- }
1180
- const taken = value;
1181
- value = void 0;
1182
- initialized = false;
1183
- return Some(taken);
1184
- },
1185
- isInitialized() {
1186
- return initialized;
1187
- }
1188
- });
1855
+ let value;
1856
+ let initialized = false;
1857
+ /**
1858
+ * Sets the value and marks as initialized.
1859
+ */
1860
+ function setValue(val) {
1861
+ value = val;
1862
+ initialized = true;
1863
+ }
1864
+ return Object.freeze({
1865
+ [Symbol.toStringTag]: "Once",
1866
+ toString() {
1867
+ return initialized ? `Once(${value})` : "Once(<uninitialized>)";
1868
+ },
1869
+ get() {
1870
+ return initialized ? Some(value) : None;
1871
+ },
1872
+ set(newValue) {
1873
+ if (initialized) return Err(newValue);
1874
+ setValue(newValue);
1875
+ return RESULT_VOID;
1876
+ },
1877
+ tryInsert(newValue) {
1878
+ if (initialized) return Err([value, newValue]);
1879
+ setValue(newValue);
1880
+ return Ok(newValue);
1881
+ },
1882
+ getOrInit(fn) {
1883
+ if (!initialized) setValue(fn());
1884
+ return value;
1885
+ },
1886
+ getOrTryInit(fn) {
1887
+ if (initialized) return Ok(value);
1888
+ const result = fn();
1889
+ if (result.isOk()) setValue(result.unwrap());
1890
+ return result;
1891
+ },
1892
+ take() {
1893
+ if (!initialized) return None;
1894
+ const taken = value;
1895
+ value = void 0;
1896
+ initialized = false;
1897
+ return Some(taken);
1898
+ },
1899
+ isInitialized() {
1900
+ return initialized;
1901
+ }
1902
+ });
1189
1903
  }
1190
-
1904
+ //#endregion
1905
+ //#region src/std/sync/once_async.ts
1906
+ /**
1907
+ * @module
1908
+ * Async-first one-time initialization container.
1909
+ *
1910
+ * `OnceAsync<T>` is designed for async initialization where the stored value
1911
+ * is always `Awaited<T>`, matching JavaScript's Promise flattening behavior.
1912
+ *
1913
+ * **When to use `OnceAsync<T>` vs `Once<T>`:**
1914
+ * - Use `Once<T>` for sync-only initialization
1915
+ * - Use `OnceAsync<T>` for async initialization with concurrent call handling
1916
+ */
1917
+ /**
1918
+ * Creates a new empty `OnceAsync<T>`.
1919
+ *
1920
+ * `OnceAsync<T>` stores `Awaited<T>`, matching JavaScript's Promise flattening behavior.
1921
+ * This means `OnceAsync<Promise<number>>` and `OnceAsync<number>` behave identically.
1922
+ *
1923
+ * @typeParam T - The type parameter. The actual stored type is `Awaited<T>`.
1924
+ * @returns A new uninitialized `OnceAsync`.
1925
+ * @example
1926
+ * ```ts
1927
+ * // Basic usage
1928
+ * const once = OnceAsync<string>();
1929
+ * await once.getOrInit(async () => 'hello');
1930
+ * console.log(once.get().unwrap()); // 'hello'
1931
+ * ```
1932
+ *
1933
+ * @example
1934
+ * ```ts
1935
+ * // Async lazy singleton pattern
1936
+ * const db = OnceAsync<Database>();
1937
+ *
1938
+ * async function getDb(): Promise<Database> {
1939
+ * return await db.getOrInit(async () => {
1940
+ * console.log('Connecting to database...');
1941
+ * return await Database.connect(connectionString);
1942
+ * });
1943
+ * }
1944
+ *
1945
+ * // Multiple calls - connection happens only once
1946
+ * const [db1, db2] = await Promise.all([getDb(), getDb()]);
1947
+ * console.log(db1 === db2); // true
1948
+ * ```
1949
+ *
1950
+ * @example
1951
+ * ```ts
1952
+ * // Fallible async initialization
1953
+ * const config = OnceAsync<Config>();
1954
+ *
1955
+ * async function loadConfig(): Promise<Result<Config, Error>> {
1956
+ * return await config.getOrTryInit(async () => {
1957
+ * try {
1958
+ * const response = await fetch('/api/config');
1959
+ * if (!response.ok) {
1960
+ * return Err(new Error(`HTTP ${response.status}`));
1961
+ * }
1962
+ * return Ok(await response.json());
1963
+ * } catch (e) {
1964
+ * return Err(e as Error);
1965
+ * }
1966
+ * });
1967
+ * }
1968
+ * ```
1969
+ */
1191
1970
  function OnceAsync() {
1192
- let value;
1193
- let initialized = false;
1194
- let pendingPromise;
1195
- let resolvedPromise;
1196
- let resolvedResultPromise;
1197
- let waiters = [];
1198
- function setValue(val) {
1199
- value = val;
1200
- initialized = true;
1201
- for (const waiter of waiters) {
1202
- waiter(val);
1203
- }
1204
- waiters = [];
1205
- }
1206
- function getOrTryInit(fn) {
1207
- if (initialized) {
1208
- return resolvedResultPromise ??= Promise.resolve(Ok(value));
1209
- }
1210
- if (pendingPromise) {
1211
- return pendingPromise.then(
1212
- () => Ok(value),
1213
- // Previous initialization failed via Err result, let this call try again.
1214
- // Note: fn's sync errors won't throw here since we're inside a .then() callback,
1215
- // they will be caught and converted to rejected Promise by Promise.resolve(fn()).
1216
- () => getOrTryInit(fn)
1217
- );
1218
- }
1219
- const resultPromise = Promise.resolve(fn());
1220
- pendingPromise = resultPromise.then(
1221
- (result) => {
1222
- if (result.isOk()) {
1223
- const val = result.unwrap();
1224
- setValue(val);
1225
- return val;
1226
- }
1227
- throw result;
1228
- }
1229
- ).finally(() => {
1230
- pendingPromise = void 0;
1231
- });
1232
- return pendingPromise.then(
1233
- () => resultPromise,
1234
- () => resultPromise
1235
- );
1236
- }
1237
- return Object.freeze({
1238
- [Symbol.toStringTag]: "OnceAsync",
1239
- toString() {
1240
- return initialized ? `OnceAsync(${value})` : "OnceAsync(<uninitialized>)";
1241
- },
1242
- get() {
1243
- return initialized ? Some(value) : None;
1244
- },
1245
- set(newValue) {
1246
- if (initialized) {
1247
- return Err(newValue);
1248
- }
1249
- setValue(newValue);
1250
- return RESULT_VOID;
1251
- },
1252
- tryInsert(newValue) {
1253
- if (initialized) {
1254
- return Err([value, newValue]);
1255
- }
1256
- setValue(newValue);
1257
- return Ok(newValue);
1258
- },
1259
- // Use `Promise.resolve(fn())` instead of `async` to preserve sync error behavior:
1260
- // sync throws propagate directly, async errors become rejected Promises.
1261
- getOrInit(fn) {
1262
- if (initialized) {
1263
- return resolvedPromise ??= Promise.resolve(value);
1264
- }
1265
- if (pendingPromise) {
1266
- return pendingPromise;
1267
- }
1268
- pendingPromise = Promise.resolve(fn()).then(
1269
- (result) => {
1270
- setValue(result);
1271
- return result;
1272
- }
1273
- ).finally(() => {
1274
- pendingPromise = void 0;
1275
- });
1276
- return pendingPromise;
1277
- },
1278
- getOrTryInit,
1279
- take() {
1280
- if (!initialized) {
1281
- return None;
1282
- }
1283
- const taken = value;
1284
- value = void 0;
1285
- initialized = false;
1286
- resolvedPromise = void 0;
1287
- resolvedResultPromise = void 0;
1288
- return Some(taken);
1289
- },
1290
- isInitialized() {
1291
- return initialized;
1292
- },
1293
- wait() {
1294
- if (initialized) {
1295
- return resolvedPromise ??= Promise.resolve(value);
1296
- }
1297
- if (pendingPromise) {
1298
- return pendingPromise;
1299
- }
1300
- return new Promise((resolve) => {
1301
- waiters.push(resolve);
1302
- });
1303
- }
1304
- });
1971
+ let value;
1972
+ let initialized = false;
1973
+ let pendingPromise;
1974
+ let resolvedPromise;
1975
+ let resolvedResultPromise;
1976
+ let waiters = [];
1977
+ /**
1978
+ * Sets the value, marks as initialized, and notifies all waiters.
1979
+ */
1980
+ function setValue(val) {
1981
+ value = val;
1982
+ initialized = true;
1983
+ for (const waiter of waiters) waiter(val);
1984
+ waiters = [];
1985
+ }
1986
+ function getOrTryInit(fn) {
1987
+ if (initialized) return resolvedResultPromise ??= Promise.resolve(Ok(value));
1988
+ if (pendingPromise) return pendingPromise.then(() => Ok(value), () => getOrTryInit(fn));
1989
+ const resultPromise = Promise.resolve(fn());
1990
+ pendingPromise = resultPromise.then((result) => {
1991
+ if (result.isOk()) {
1992
+ const val = result.unwrap();
1993
+ setValue(val);
1994
+ return val;
1995
+ }
1996
+ throw result;
1997
+ }).finally(() => {
1998
+ pendingPromise = void 0;
1999
+ });
2000
+ return pendingPromise.then(() => resultPromise, () => resultPromise);
2001
+ }
2002
+ return Object.freeze({
2003
+ [Symbol.toStringTag]: "OnceAsync",
2004
+ toString() {
2005
+ return initialized ? `OnceAsync(${value})` : "OnceAsync(<uninitialized>)";
2006
+ },
2007
+ get() {
2008
+ return initialized ? Some(value) : None;
2009
+ },
2010
+ set(newValue) {
2011
+ if (initialized) return Err(newValue);
2012
+ setValue(newValue);
2013
+ return RESULT_VOID;
2014
+ },
2015
+ tryInsert(newValue) {
2016
+ if (initialized) return Err([value, newValue]);
2017
+ setValue(newValue);
2018
+ return Ok(newValue);
2019
+ },
2020
+ getOrInit(fn) {
2021
+ if (initialized) return resolvedPromise ??= Promise.resolve(value);
2022
+ if (pendingPromise) return pendingPromise;
2023
+ pendingPromise = Promise.resolve(fn()).then((result) => {
2024
+ setValue(result);
2025
+ return result;
2026
+ }).finally(() => {
2027
+ pendingPromise = void 0;
2028
+ });
2029
+ return pendingPromise;
2030
+ },
2031
+ getOrTryInit,
2032
+ take() {
2033
+ if (!initialized) return None;
2034
+ const taken = value;
2035
+ value = void 0;
2036
+ initialized = false;
2037
+ resolvedPromise = void 0;
2038
+ resolvedResultPromise = void 0;
2039
+ return Some(taken);
2040
+ },
2041
+ isInitialized() {
2042
+ return initialized;
2043
+ },
2044
+ wait() {
2045
+ if (initialized) return resolvedPromise ??= Promise.resolve(value);
2046
+ if (pendingPromise) return pendingPromise;
2047
+ return new Promise((resolve) => {
2048
+ waiters.push(resolve);
2049
+ });
2050
+ }
2051
+ });
1305
2052
  }
1306
-
2053
+ //#endregion
2054
+ //#region src/std/sync/rwlock.ts
2055
+ /**
2056
+ * @module
2057
+ * Rust-inspired [RwLock](https://doc.rust-lang.org/std/sync/struct.RwLock.html) for async read-write locking.
2058
+ *
2059
+ * In JavaScript's single-threaded environment, `RwLock<T>` allows multiple
2060
+ * concurrent readers or a single exclusive writer. This is useful when
2061
+ * read operations are frequent and write operations are rare.
2062
+ *
2063
+ * **When to use RwLock vs Mutex:**
2064
+ * - Use `RwLock` when reads are frequent, writes are rare, and read operations
2065
+ * contain `await` statements that could benefit from concurrent access.
2066
+ * - Use `Mutex` for simpler cases or when read/write frequency is balanced.
2067
+ *
2068
+ * **Important:** In JS, the benefit of RwLock is limited because:
2069
+ * - JS is single-threaded, so "parallel reads" don't truly execute simultaneously
2070
+ * - If read operations don't contain `await`, there's no opportunity for concurrency
2071
+ * - RwLock adds complexity over Mutex with marginal performance benefit
2072
+ */
2073
+ /**
2074
+ * Creates a new `RwLock<T>` protecting the given value.
2075
+ *
2076
+ * @typeParam T - The type of the protected value.
2077
+ * @param value - The initial value to protect.
2078
+ * @returns A new `RwLock<T>` instance.
2079
+ * @example
2080
+ * ```ts
2081
+ * // Basic usage
2082
+ * const counter = RwLock(0);
2083
+ *
2084
+ * // Read (multiple can proceed)
2085
+ * const value = await counter.withRead(v => v);
2086
+ *
2087
+ * // Write (exclusive)
2088
+ * await counter.withWrite(v => v + 1);
2089
+ * ```
2090
+ *
2091
+ * @example
2092
+ * ```ts
2093
+ * // Cache with read-heavy workload
2094
+ * const cache = RwLock(new Map<string, Data>());
2095
+ *
2096
+ * // Many concurrent reads
2097
+ * async function get(key: string): Promise<Data | undefined> {
2098
+ * return cache.withRead(map => map.get(key));
2099
+ * }
2100
+ *
2101
+ * // Occasional writes
2102
+ * async function set(key: string, value: Data): Promise<void> {
2103
+ * await cache.withWrite(map => { map.set(key, value); });
2104
+ * }
2105
+ * ```
2106
+ *
2107
+ * @example
2108
+ * ```ts
2109
+ * // Configuration that's read frequently, updated rarely
2110
+ * interface AppConfig {
2111
+ * apiUrl: string;
2112
+ * timeout: number;
2113
+ * features: string[];
2114
+ * }
2115
+ *
2116
+ * const config = RwLock<AppConfig>({
2117
+ * apiUrl: 'https://api.example.com',
2118
+ * timeout: 5000,
2119
+ * features: ['feature-a', 'feature-b'],
2120
+ * });
2121
+ *
2122
+ * // Read config (concurrent)
2123
+ * async function isFeatureEnabled(feature: string): Promise<boolean> {
2124
+ * return config.withRead(cfg => cfg.features.includes(feature));
2125
+ * }
2126
+ *
2127
+ * // Update config (exclusive)
2128
+ * async function enableFeature(feature: string): Promise<void> {
2129
+ * await config.withWrite(cfg => {
2130
+ * if (!cfg.features.includes(feature)) {
2131
+ * cfg.features.push(feature);
2132
+ * }
2133
+ * });
2134
+ * }
2135
+ * ```
2136
+ */
1307
2137
  function RwLock(value) {
1308
- let currentValue = value;
1309
- let readers = 0;
1310
- let writer = false;
1311
- let pendingWriters = 0;
1312
- const readWaitQueue = [];
1313
- const writeWaitQueue = [];
1314
- function tryAcquireRead() {
1315
- if (!writer && pendingWriters === 0) {
1316
- readers++;
1317
- return true;
1318
- }
1319
- return false;
1320
- }
1321
- function tryAcquireWrite() {
1322
- if (readers === 0 && !writer) {
1323
- writer = true;
1324
- return true;
1325
- }
1326
- return false;
1327
- }
1328
- function releaseRead() {
1329
- readers--;
1330
- if (readers === 0 && writeWaitQueue.length > 0) {
1331
- const next = writeWaitQueue.shift();
1332
- writer = true;
1333
- pendingWriters--;
1334
- next();
1335
- }
1336
- }
1337
- function releaseWrite() {
1338
- writer = false;
1339
- if (writeWaitQueue.length > 0) {
1340
- const next = writeWaitQueue.shift();
1341
- writer = true;
1342
- pendingWriters--;
1343
- next();
1344
- } else {
1345
- while (readWaitQueue.length > 0) {
1346
- readers++;
1347
- const next = readWaitQueue.shift();
1348
- next();
1349
- }
1350
- }
1351
- }
1352
- function createReadGuard() {
1353
- let released = false;
1354
- return Object.freeze({
1355
- [Symbol.toStringTag]: "RwLockReadGuard",
1356
- toString() {
1357
- if (released) {
1358
- return "RwLockReadGuard(<released>)";
1359
- }
1360
- return `RwLockReadGuard(${currentValue})`;
1361
- },
1362
- get value() {
1363
- if (released) {
1364
- throw new Error("RwLockReadGuard has been released");
1365
- }
1366
- return currentValue;
1367
- },
1368
- unlock() {
1369
- if (released) {
1370
- return;
1371
- }
1372
- released = true;
1373
- releaseRead();
1374
- }
1375
- });
1376
- }
1377
- function createWriteGuard() {
1378
- let released = false;
1379
- return Object.freeze({
1380
- [Symbol.toStringTag]: "RwLockWriteGuard",
1381
- toString() {
1382
- if (released) {
1383
- return "RwLockWriteGuard(<released>)";
1384
- }
1385
- return `RwLockWriteGuard(${currentValue})`;
1386
- },
1387
- get value() {
1388
- if (released) {
1389
- throw new Error("RwLockWriteGuard has been released");
1390
- }
1391
- return currentValue;
1392
- },
1393
- set value(newValue) {
1394
- if (released) {
1395
- throw new Error("RwLockWriteGuard has been released");
1396
- }
1397
- currentValue = newValue;
1398
- },
1399
- unlock() {
1400
- if (released) {
1401
- return;
1402
- }
1403
- released = true;
1404
- releaseWrite();
1405
- }
1406
- });
1407
- }
1408
- function read() {
1409
- if (tryAcquireRead()) {
1410
- return Promise.resolve(createReadGuard());
1411
- }
1412
- return new Promise((resolve) => {
1413
- readWaitQueue.push(() => {
1414
- resolve(createReadGuard());
1415
- });
1416
- });
1417
- }
1418
- function write() {
1419
- if (tryAcquireWrite()) {
1420
- return Promise.resolve(createWriteGuard());
1421
- }
1422
- pendingWriters++;
1423
- return new Promise((resolve) => {
1424
- writeWaitQueue.push(() => {
1425
- resolve(createWriteGuard());
1426
- });
1427
- });
1428
- }
1429
- return Object.freeze({
1430
- [Symbol.toStringTag]: "RwLock",
1431
- toString() {
1432
- if (writer) {
1433
- return "RwLock(<write-locked>)";
1434
- }
1435
- if (readers > 0) {
1436
- return `RwLock(<read-locked:${readers}>)`;
1437
- }
1438
- return "RwLock(<unlocked>)";
1439
- },
1440
- async withRead(fn) {
1441
- const guard = await read();
1442
- try {
1443
- return await fn(guard.value);
1444
- } finally {
1445
- guard.unlock();
1446
- }
1447
- },
1448
- async withWrite(fn) {
1449
- const guard = await write();
1450
- try {
1451
- return await fn(guard.value);
1452
- } finally {
1453
- guard.unlock();
1454
- }
1455
- },
1456
- read,
1457
- write,
1458
- tryRead() {
1459
- if (tryAcquireRead()) {
1460
- return Some(createReadGuard());
1461
- }
1462
- return None;
1463
- },
1464
- tryWrite() {
1465
- if (tryAcquireWrite()) {
1466
- return Some(createWriteGuard());
1467
- }
1468
- return None;
1469
- },
1470
- readerCount() {
1471
- return readers;
1472
- },
1473
- isWriteLocked() {
1474
- return writer;
1475
- },
1476
- async get() {
1477
- const guard = await read();
1478
- try {
1479
- return guard.value;
1480
- } finally {
1481
- guard.unlock();
1482
- }
1483
- },
1484
- async set(value2) {
1485
- const guard = await write();
1486
- try {
1487
- guard.value = value2;
1488
- } finally {
1489
- guard.unlock();
1490
- }
1491
- },
1492
- async replace(value2) {
1493
- const guard = await write();
1494
- try {
1495
- const old = guard.value;
1496
- guard.value = value2;
1497
- return old;
1498
- } finally {
1499
- guard.unlock();
1500
- }
1501
- }
1502
- });
2138
+ let currentValue = value;
2139
+ let readers = 0;
2140
+ let writer = false;
2141
+ let pendingWriters = 0;
2142
+ const readWaitQueue = [];
2143
+ const writeWaitQueue = [];
2144
+ function tryAcquireRead() {
2145
+ if (!writer && pendingWriters === 0) {
2146
+ readers++;
2147
+ return true;
2148
+ }
2149
+ return false;
2150
+ }
2151
+ function tryAcquireWrite() {
2152
+ if (readers === 0 && !writer) {
2153
+ writer = true;
2154
+ return true;
2155
+ }
2156
+ return false;
2157
+ }
2158
+ function releaseRead() {
2159
+ readers--;
2160
+ if (readers === 0 && writeWaitQueue.length > 0) {
2161
+ const next = writeWaitQueue.shift();
2162
+ writer = true;
2163
+ pendingWriters--;
2164
+ next();
2165
+ }
2166
+ }
2167
+ function releaseWrite() {
2168
+ writer = false;
2169
+ if (writeWaitQueue.length > 0) {
2170
+ const next = writeWaitQueue.shift();
2171
+ writer = true;
2172
+ pendingWriters--;
2173
+ next();
2174
+ } else while (readWaitQueue.length > 0) {
2175
+ readers++;
2176
+ readWaitQueue.shift()();
2177
+ }
2178
+ }
2179
+ function createReadGuard() {
2180
+ let released = false;
2181
+ return Object.freeze({
2182
+ [Symbol.toStringTag]: "RwLockReadGuard",
2183
+ toString() {
2184
+ if (released) return "RwLockReadGuard(<released>)";
2185
+ return `RwLockReadGuard(${currentValue})`;
2186
+ },
2187
+ get value() {
2188
+ if (released) throw new Error("RwLockReadGuard has been released");
2189
+ return currentValue;
2190
+ },
2191
+ unlock() {
2192
+ if (released) return;
2193
+ released = true;
2194
+ releaseRead();
2195
+ }
2196
+ });
2197
+ }
2198
+ function createWriteGuard() {
2199
+ let released = false;
2200
+ return Object.freeze({
2201
+ [Symbol.toStringTag]: "RwLockWriteGuard",
2202
+ toString() {
2203
+ if (released) return "RwLockWriteGuard(<released>)";
2204
+ return `RwLockWriteGuard(${currentValue})`;
2205
+ },
2206
+ get value() {
2207
+ if (released) throw new Error("RwLockWriteGuard has been released");
2208
+ return currentValue;
2209
+ },
2210
+ set value(newValue) {
2211
+ if (released) throw new Error("RwLockWriteGuard has been released");
2212
+ currentValue = newValue;
2213
+ },
2214
+ unlock() {
2215
+ if (released) return;
2216
+ released = true;
2217
+ releaseWrite();
2218
+ }
2219
+ });
2220
+ }
2221
+ function read() {
2222
+ if (tryAcquireRead()) return Promise.resolve(createReadGuard());
2223
+ return new Promise((resolve) => {
2224
+ readWaitQueue.push(() => {
2225
+ resolve(createReadGuard());
2226
+ });
2227
+ });
2228
+ }
2229
+ function write() {
2230
+ if (tryAcquireWrite()) return Promise.resolve(createWriteGuard());
2231
+ pendingWriters++;
2232
+ return new Promise((resolve) => {
2233
+ writeWaitQueue.push(() => {
2234
+ resolve(createWriteGuard());
2235
+ });
2236
+ });
2237
+ }
2238
+ return Object.freeze({
2239
+ [Symbol.toStringTag]: "RwLock",
2240
+ toString() {
2241
+ if (writer) return "RwLock(<write-locked>)";
2242
+ if (readers > 0) return `RwLock(<read-locked:${readers}>)`;
2243
+ return "RwLock(<unlocked>)";
2244
+ },
2245
+ async withRead(fn) {
2246
+ const guard = await read();
2247
+ try {
2248
+ return await fn(guard.value);
2249
+ } finally {
2250
+ guard.unlock();
2251
+ }
2252
+ },
2253
+ async withWrite(fn) {
2254
+ const guard = await write();
2255
+ try {
2256
+ return await fn(guard.value);
2257
+ } finally {
2258
+ guard.unlock();
2259
+ }
2260
+ },
2261
+ read,
2262
+ write,
2263
+ tryRead() {
2264
+ if (tryAcquireRead()) return Some(createReadGuard());
2265
+ return None;
2266
+ },
2267
+ tryWrite() {
2268
+ if (tryAcquireWrite()) return Some(createWriteGuard());
2269
+ return None;
2270
+ },
2271
+ readerCount() {
2272
+ return readers;
2273
+ },
2274
+ isWriteLocked() {
2275
+ return writer;
2276
+ },
2277
+ async get() {
2278
+ const guard = await read();
2279
+ try {
2280
+ return guard.value;
2281
+ } finally {
2282
+ guard.unlock();
2283
+ }
2284
+ },
2285
+ async set(value) {
2286
+ const guard = await write();
2287
+ try {
2288
+ guard.value = value;
2289
+ } finally {
2290
+ guard.unlock();
2291
+ }
2292
+ },
2293
+ async replace(value) {
2294
+ const guard = await write();
2295
+ try {
2296
+ const old = guard.value;
2297
+ guard.value = value;
2298
+ return old;
2299
+ } finally {
2300
+ guard.unlock();
2301
+ }
2302
+ }
2303
+ });
1503
2304
  }
1504
-
2305
+ //#endregion
1505
2306
  exports.ASYNC_NONE = ASYNC_NONE;
1506
2307
  exports.Break = Break;
1507
2308
  exports.Channel = Channel;
@@ -1529,4 +2330,5 @@ exports.tryAsyncOption = tryAsyncOption;
1529
2330
  exports.tryAsyncResult = tryAsyncResult;
1530
2331
  exports.tryOption = tryOption;
1531
2332
  exports.tryResult = tryResult;
1532
- //# sourceMappingURL=main.cjs.map
2333
+
2334
+ //# sourceMappingURL=main.cjs.map