nalloc 0.0.3 → 0.2.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Values that represent None (absence of a value). */\nexport type NoneValueType = null | undefined | void;\n\n/** Widens literal types to their base types for better type inference. */\nexport type Widen<T> = T extends string\n ? string\n : T extends number\n ? number\n : T extends boolean\n ? boolean\n : T extends bigint\n ? bigint\n : T extends symbol\n ? symbol\n : T;\n\n/** Widens never to unknown, otherwise preserves the type. */\nexport type WidenNever<T> = [T] extends [never] ? unknown : T;\n\n/** Excludes None values from a type, leaving only valid Some values. */\nexport type ValueType<T> = Exclude<T, NoneValueType>;\n\nexport declare const SOME_BRAND: unique symbol;\n\n/** Represents a value that is present. The value itself is the Some - no wrapper object. */\nexport type Some<T> = ValueType<T> & { readonly [SOME_BRAND]: true };\n\n/** Represents the absence of a value (null or undefined). */\nexport type None = NoneValueType & { readonly [SOME_BRAND]: false };\n\n/** Constant representing None. Use this instead of null/undefined for clarity. */\nexport const NONE = undefined as None;\n\n/** Shared frozen empty array to avoid allocations. */\nexport const EMPTY: readonly unknown[] = Object.freeze([]);\n\n/** A value that may or may not be present. Some(T) is the value itself; None is null/undefined. */\nexport type Option<T> = Some<ValueType<T>> | None;\n\n/** Extracts the value type from an Option type. */\nexport type OptionValue<TOption> = TOption extends Option<infer TValue> ? TValue : never;\n\n/** Type predicate: true if T is an Option type. */\nexport type IsOption<T> = T extends Option<any> ? true : false;\n\n/** Infers the Some type from a value, preserving the inner type. */\nexport type InferSome<T> = T extends Some<infer TValue> ? Some<ValueType<TValue>> : never;\n\n/**\n * Checks if an Option contains a value (is Some).\n * @param opt - The Option to check\n * @returns true if the Option is Some, false if None\n * @example\n * isSome(42) // true\n * isSome(null) // false\n * isSome(undefined) // false\n */\nexport function isSome<T>(opt: Some<T>): true;\nexport function isSome(opt: None): false;\nexport function isSome<T>(opt: unknown): opt is Some<T>;\nexport function isSome(opt: unknown): boolean {\n return opt !== null && opt !== undefined;\n}\n\n/**\n * Checks if an Option is None (absent).\n * @param opt - The Option to check\n * @returns true if the Option is None, false if Some\n * @example\n * isNone(null) // true\n * isNone(undefined) // true\n * isNone(42) // false\n */\nexport function isNone<T>(opt: Some<T>): false;\nexport function isNone(opt: None): true;\nexport function isNone(opt: unknown): opt is None;\nexport function isNone(opt: unknown): boolean {\n return opt === null || opt === undefined;\n}\n\n/**\n * Creates an Option from a nullable value. Returns None for null/undefined, Some otherwise.\n * @param value - The value to wrap\n * @returns Some(value) if value is non-null, None otherwise\n * @example\n * optionOf(42) // Some(42)\n * optionOf(null) // None\n * optionOf(undefined) // None\n */\nexport function optionOf(value: null): None;\nexport function optionOf(value: undefined): None;\nexport function optionOf<T>(value: T): T extends NoneValueType ? None : Some<T>;\nexport function optionOf<T>(value: T): Option<T> {\n return isNone(value as Option<T>) ? NONE : (value as Some<T>);\n}\n\nexport function someUnchecked<T>(value: T): Some<ValueType<T>> {\n return value as Some<ValueType<T>>;\n}\n\n/**\n * Creates a Some value with runtime validation.\n * @param value - The value to wrap\n * @returns The value typed as Some\n * @throws TypeError if value is null or undefined\n * @example\n * some(42) // Some(42)\n */\nexport function some<T>(value: ValueType<T>): Some<ValueType<T>> {\n if (value === null || value === undefined) {\n throw new TypeError('some() requires a non-nullable value');\n }\n return someUnchecked(value);\n}\n\n/** Constant representing None. Alias for NONE. */\nexport const none: None = NONE;\n\ndeclare const OK_BRAND: unique symbol;\n\n/** Represents a successful Result value. The value itself is the Ok - no wrapper object. */\nexport type Ok<T> = T & { readonly [OK_BRAND]: true };\n\nconst ERR_BRAND = Symbol.for('nalloc.ResultError');\n\ninterface ResultErrorShape<E> {\n readonly error: E;\n readonly [ERR_BRAND]: true;\n}\n\nfunction ResultErrorCtor<E>(this: ResultErrorShape<E>, error: E): void {\n (this as { error: E }).error = error;\n}\n(ResultErrorCtor.prototype as { [ERR_BRAND]: true })[ERR_BRAND] = true;\n\n/** The error wrapper type used internally. */\nexport type ResultError<E> = ResultErrorShape<E>;\n\n/** Represents a failed Result containing an error. */\nexport type Err<E> = ResultError<E>;\n\n/** A value that is either successful (Ok) or failed (Err). Ok is the value itself; Err wraps the error. */\nexport type Result<T, E> = Ok<T> | Err<E>;\n\n/** Extracts the success value type from a Result type. */\nexport type ResultValue<TResult> = TResult extends Result<infer TValue, any> ? TValue : never;\n\n/** Extracts the error type from a Result type. */\nexport type ResultErrorType<TResult> = TResult extends Result<any, infer TError> ? TError : never;\n\n/** Type predicate: true if T is a Result type. */\nexport type IsResult<T> = T extends Result<any, any> ? true : false;\n\n/** Infers the Err type from a value, preserving the error type. */\nexport type InferErr<T> = T extends Err<infer TError> ? Err<TError> : never;\n\n/**\n * Checks if a Result is Ok (successful).\n * @param result - The Result to check\n * @returns true if the Result is Ok, false if Err\n * @example\n * isOk(42) // true (Ok value)\n * isOk(err('fail')) // false\n */\nexport function isOk<T>(result: Ok<T>): true;\nexport function isOk<E>(result: Err<E>): false;\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T>;\nexport function isOk(result: unknown): boolean;\nexport function isOk(result: unknown): boolean {\n return typeof result !== 'object' || result === null || !(result as Record<symbol, boolean>)[ERR_BRAND];\n}\n\n/**\n * Checks if a Result is Err (failed).\n * @param result - The Result to check\n * @returns true if the Result is Err, false if Ok\n * @example\n * isErr(err('fail')) // true\n * isErr(42) // false (Ok value)\n */\nexport function isErr<E>(result: Err<E>): true;\nexport function isErr(result: Ok<unknown>): false;\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E>;\nexport function isErr(result: unknown): result is Err<unknown>;\nexport function isErr(result: unknown): boolean {\n return typeof result === 'object' && result !== null && (result as Record<symbol, boolean>)[ERR_BRAND] === true;\n}\n\nexport function okUnchecked<T>(value: T): Ok<T> {\n return value as Ok<T>;\n}\n\n/**\n * Creates an Ok value with runtime validation.\n * @param value - The success value\n * @returns The value typed as Ok\n * @throws TypeError if value is an Err\n * @example\n * ok(42) // Ok(42)\n */\nexport function ok<T>(value: T): Ok<T> {\n if (isErr(value)) {\n throw new TypeError('ok() cannot wrap an Err value');\n }\n return okUnchecked(value);\n}\n\n/**\n * Creates an Err value wrapping an error.\n * @param error - The error value\n * @returns An Err containing the error\n * @example\n * err('something went wrong') // Err('something went wrong')\n * err(new Error('failed')) // Err(Error)\n */\nexport function err<E>(error: E): Err<E> {\n return new (ResultErrorCtor as unknown as new (error: E) => Err<E>)(error);\n}\n\n/** A value that may or may not be a Promise. */\nexport type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;\n\n/**\n * Checks if a value is a thenable (has a .then method).\n * @param value - The value to check\n * @returns true if value is a PromiseLike\n */\nexport function isThenable<T>(value: MaybePromise<T>): value is PromiseLike<T> {\n return typeof (value as PromiseLike<T>)?.then === 'function';\n}\n\n/**\n * Checks if a value is synchronous (not a thenable).\n * @param value - The value to check\n * @returns true if value is not a PromiseLike\n */\nexport function isSync<T>(value: MaybePromise<T>): value is T {\n return typeof (value as PromiseLike<T>)?.then !== 'function';\n}\n"],"names":["NONE","undefined","EMPTY","Object","freeze","isSome","opt","isNone","optionOf","value","someUnchecked","some","TypeError","none","ERR_BRAND","Symbol","for","ResultErrorCtor","error","prototype","isOk","result","isErr","okUnchecked","ok","err","isThenable","then","isSync"],"mappings":"AA+BA,OAAO,MAAMA,OAAOC,UAAkB;AAGtC,OAAO,MAAMC,QAA4BC,OAAOC,MAAM,CAAC,EAAE,EAAE;AA0B3D,OAAO,SAASC,OAAOC,GAAY;IACjC,OAAOA,QAAQ,QAAQA,QAAQL;AACjC;AAcA,OAAO,SAASM,OAAOD,GAAY;IACjC,OAAOA,QAAQ,QAAQA,QAAQL;AACjC;AAcA,OAAO,SAASO,SAAYC,KAAQ;IAClC,OAAOF,OAAOE,SAAsBT,OAAQS;AAC9C;AAEA,OAAO,SAASC,cAAiBD,KAAQ;IACvC,OAAOA;AACT;AAUA,OAAO,SAASE,KAAQF,KAAmB;IACzC,IAAIA,UAAU,QAAQA,UAAUR,WAAW;QACzC,MAAM,IAAIW,UAAU;IACtB;IACA,OAAOF,cAAcD;AACvB;AAGA,OAAO,MAAMI,OAAab,KAAK;AAO/B,MAAMc,YAAYC,OAAOC,GAAG,CAAC;AAO7B,SAASC,gBAA8CC,KAAQ;IAC7D,AAAC,IAAI,CAAkBA,KAAK,GAAGA;AACjC;AACCD,gBAAgBE,SAAS,AAA0B,CAACL,UAAU,GAAG;AAmClE,OAAO,SAASM,KAAKC,MAAe;IAClC,OAAO,OAAOA,WAAW,YAAYA,WAAW,QAAQ,CAAC,AAACA,MAAkC,CAACP,UAAU;AACzG;AAcA,OAAO,SAASQ,MAAMD,MAAe;IACnC,OAAO,OAAOA,WAAW,YAAYA,WAAW,QAAQ,AAACA,MAAkC,CAACP,UAAU,KAAK;AAC7G;AAEA,OAAO,SAASS,YAAed,KAAQ;IACrC,OAAOA;AACT;AAUA,OAAO,SAASe,GAAMf,KAAQ;IAC5B,IAAIa,MAAMb,QAAQ;QAChB,MAAM,IAAIG,UAAU;IACtB;IACA,OAAOW,YAAYd;AACrB;AAUA,OAAO,SAASgB,IAAOP,KAAQ;IAC7B,OAAO,IAAKD,gBAAwDC;AACtE;AAUA,OAAO,SAASQ,WAAcjB,KAAsB;IAClD,OAAO,OAAQA,OAA0BkB,SAAS;AACpD;AAOA,OAAO,SAASC,OAAUnB,KAAsB;IAC9C,OAAO,OAAQA,OAA0BkB,SAAS;AACpD"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Values that represent None (absence of a value). */\nexport type NoneValueType = null | undefined | void;\n\n/** Widens literal types to their base types for better type inference. */\nexport type Widen<T> = T extends string\n ? string\n : T extends number\n ? number\n : T extends boolean\n ? boolean\n : T extends bigint\n ? bigint\n : T extends symbol\n ? symbol\n : T;\n\n/** Widens never to unknown, otherwise preserves the type. */\nexport type WidenNever<T> = [T] extends [never] ? unknown : T;\n\n/** Excludes None values from a type, leaving only valid Some values. */\nexport type ValueType<T> = Exclude<T, NoneValueType>;\n\nexport declare const SOME_BRAND: unique symbol;\n\n/** Represents a value that is present. The value itself is the Some - no wrapper object. */\nexport type Some<T> = ValueType<T> & { readonly [SOME_BRAND]: true };\n\n/** Represents the absence of a value (null or undefined). */\nexport type None = NoneValueType & { readonly [SOME_BRAND]: false };\n\nexport type UnOption<V, T extends Option<V>> = T extends Some<V> ? V : None;\n\n/** Constant representing None. Use this instead of null/undefined for clarity. */\nexport const NONE = undefined as None;\n\n/** Shared frozen empty array to avoid allocations. */\nexport const EMPTY: readonly unknown[] = Object.freeze([]);\n\n/** A value that may or may not be present. Some(T) is the value itself; None is null/undefined. */\nexport type Option<T> = Some<ValueType<T>> | None;\n\n/** Extracts the value type from an Option type. */\nexport type OptionValue<TOption> = TOption extends Option<infer TValue> ? TValue : never;\n\n/** Type predicate: true if T is an Option type. */\nexport type IsOption<T> = T extends Option<any> ? true : false;\n\n/** Infers the Some type from a value, preserving the inner type. */\nexport type InferSome<T> = T extends Some<infer TValue> ? Some<ValueType<TValue>> : never;\n\n/**\n * Checks if an Option contains a value (is Some).\n * @param opt - The Option to check\n * @returns true if the Option is Some, false if None\n * @example\n * isSome(42) // true\n * isSome(null) // false\n * isSome(undefined) // false\n */\nexport function isSome<T>(opt: Some<T>): true;\nexport function isSome(opt: None): false;\nexport function isSome<T>(opt: unknown): opt is Some<T>;\nexport function isSome(opt: unknown): boolean {\n return opt !== null && opt !== undefined;\n}\n\n/**\n * Checks if an Option is None (absent).\n * @param opt - The Option to check\n * @returns true if the Option is None, false if Some\n * @example\n * isNone(null) // true\n * isNone(undefined) // true\n * isNone(42) // false\n */\nexport function isNone<T>(opt: Some<T>): false;\nexport function isNone(opt: None): true;\nexport function isNone(opt: unknown): opt is None;\nexport function isNone(opt: unknown): boolean {\n return opt === null || opt === undefined;\n}\n\n/**\n * Creates an Option from a nullable value. Returns None for null/undefined, Some otherwise.\n * @param value - The value to wrap\n * @returns Some(value) if value is non-null, None otherwise\n * @example\n * optionOf(42) // Some(42)\n * optionOf(null) // None\n * optionOf(undefined) // None\n */\nexport function optionOf(value: null): None;\nexport function optionOf(value: undefined): None;\nexport function optionOf<T>(value: T): T extends NoneValueType ? None : Some<T>;\nexport function optionOf<T>(value: T): Option<T> {\n return isNone(value as Option<T>) ? NONE : (value as Some<T>);\n}\n\nexport function someUnchecked<T>(value: T): Some<ValueType<T>> {\n return value as Some<ValueType<T>>;\n}\n\n/**\n * Creates a Some value with runtime validation.\n * @param value - The value to wrap\n * @returns The value typed as Some\n * @throws TypeError if value is null or undefined\n * @example\n * some(42) // Some(42)\n */\nexport function some<T>(value: ValueType<T>): Some<ValueType<T>> {\n if (value === null || value === undefined) {\n throw new TypeError('some() requires a non-nullable value');\n }\n return someUnchecked(value);\n}\n\n/** Constant representing None. Alias for NONE. */\nexport const none: None = NONE;\n\ndeclare const OK_BRAND: unique symbol;\n\n/** Represents a successful Result value. The value itself is the Ok - no wrapper object. */\nexport type Ok<T> = T & { readonly [OK_BRAND]: true };\n\nconst ERR_BRAND = Symbol.for('nalloc.ResultError');\n\ninterface ResultErrorShape<E> {\n readonly error: E;\n readonly [ERR_BRAND]: true;\n}\n\nfunction ResultErrorCtor<E>(this: ResultErrorShape<E>, error: E): void {\n (this as { error: E }).error = error;\n}\n(ResultErrorCtor.prototype as { [ERR_BRAND]: true })[ERR_BRAND] = true;\n\n/** The error wrapper type used internally. */\nexport type ResultError<E> = ResultErrorShape<E>;\n\n/** Represents a failed Result containing an error. */\nexport type Err<E> = ResultError<E>;\n\n/** A value that is either successful (Ok) or failed (Err). Ok is the value itself; Err wraps the error. */\nexport type Result<T, E> = Ok<T> | Err<E>;\n\n/** Extracts the success value type from a Result type. */\nexport type ResultValue<TResult> = TResult extends Result<infer TValue, any> ? TValue : never;\n\n/** Extracts the error type from a Result type. */\nexport type ResultErrorType<TResult> = TResult extends Result<any, infer TError> ? TError : never;\n\n/** Type predicate: true if T is a Result type. */\nexport type IsResult<T> = T extends Result<any, any> ? true : false;\n\n/** Infers the Err type from a value, preserving the error type. */\nexport type InferErr<T> = T extends Err<infer TError> ? Err<TError> : never;\n\n/**\n * Checks if a Result is Ok (successful).\n * @param result - The Result to check\n * @returns true if the Result is Ok, false if Err\n * @example\n * isOk(42) // true (Ok value)\n * isOk(err('fail')) // false\n */\nexport function isOk<T>(result: Ok<T>): true;\nexport function isOk<E>(result: Err<E>): false;\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T>;\nexport function isOk(result: unknown): boolean;\nexport function isOk(result: unknown): boolean {\n return typeof result !== 'object' || result === null || !(result as Record<symbol, boolean>)[ERR_BRAND];\n}\n\n/**\n * Checks if a Result is Err (failed).\n * @param result - The Result to check\n * @returns true if the Result is Err, false if Ok\n * @example\n * isErr(err('fail')) // true\n * isErr(42) // false (Ok value)\n */\nexport function isErr<E>(result: Err<E>): true;\nexport function isErr(result: Ok<unknown>): false;\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E>;\nexport function isErr(result: unknown): result is Err<unknown>;\nexport function isErr(result: unknown): boolean {\n return typeof result === 'object' && result !== null && (result as Record<symbol, boolean>)[ERR_BRAND] === true;\n}\n\nexport function okUnchecked<T>(value: T): Ok<T> {\n return value as Ok<T>;\n}\n\n/**\n * Creates an Ok value with runtime validation.\n * @param value - The success value\n * @returns The value typed as Ok\n * @throws TypeError if value is an Err\n * @example\n * ok(42) // Ok(42)\n */\nexport function ok<T>(value: T): Ok<T> {\n if (isErr(value)) {\n throw new TypeError('ok() cannot wrap an Err value');\n }\n return okUnchecked(value);\n}\n\n/**\n * Creates an Err value wrapping an error.\n * @param error - The error value\n * @returns An Err containing the error\n * @example\n * err('something went wrong') // Err('something went wrong')\n * err(new Error('failed')) // Err(Error)\n */\nexport function err<E>(error: E): Err<E> {\n return new (ResultErrorCtor as unknown as new (error: E) => Err<E>)(error);\n}\n\n/** A value that may or may not be a Promise. */\nexport type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;\n\n/**\n * Checks if a value is a thenable (has a .then method).\n * @param value - The value to check\n * @returns true if value is a PromiseLike\n */\nexport function isThenable<T>(value: MaybePromise<T>): value is PromiseLike<T> {\n return (typeof value === 'object' || typeof value === 'function') && value !== null && typeof (value as PromiseLike<T>).then === 'function';\n}\n\n/**\n * Checks if a value is synchronous (not a thenable).\n * @param value - The value to check\n * @returns true if value is not a PromiseLike\n */\nexport function isSync<T>(value: MaybePromise<T>): value is T {\n return !(typeof value === 'object' || typeof value === 'function') || value === null || typeof (value as PromiseLike<T>).then !== 'function';\n}\n"],"names":["NONE","undefined","EMPTY","Object","freeze","isSome","opt","isNone","optionOf","value","someUnchecked","some","TypeError","none","ERR_BRAND","Symbol","for","ResultErrorCtor","error","prototype","isOk","result","isErr","okUnchecked","ok","err","isThenable","then","isSync"],"mappings":"AAiCA,OAAO,MAAMA,OAAOC,UAAkB;AAGtC,OAAO,MAAMC,QAA4BC,OAAOC,MAAM,CAAC,EAAE,EAAE;AA0B3D,OAAO,SAASC,OAAOC,GAAY;IACjC,OAAOA,QAAQ,QAAQA,QAAQL;AACjC;AAcA,OAAO,SAASM,OAAOD,GAAY;IACjC,OAAOA,QAAQ,QAAQA,QAAQL;AACjC;AAcA,OAAO,SAASO,SAAYC,KAAQ;IAClC,OAAOF,OAAOE,SAAsBT,OAAQS;AAC9C;AAEA,OAAO,SAASC,cAAiBD,KAAQ;IACvC,OAAOA;AACT;AAUA,OAAO,SAASE,KAAQF,KAAmB;IACzC,IAAIA,UAAU,QAAQA,UAAUR,WAAW;QACzC,MAAM,IAAIW,UAAU;IACtB;IACA,OAAOF,cAAcD;AACvB;AAGA,OAAO,MAAMI,OAAab,KAAK;AAO/B,MAAMc,YAAYC,OAAOC,GAAG,CAAC;AAO7B,SAASC,gBAA8CC,KAAQ;IAC7D,AAAC,IAAI,CAAkBA,KAAK,GAAGA;AACjC;AACCD,gBAAgBE,SAAS,AAA0B,CAACL,UAAU,GAAG;AAmClE,OAAO,SAASM,KAAKC,MAAe;IAClC,OAAO,OAAOA,WAAW,YAAYA,WAAW,QAAQ,CAAC,AAACA,MAAkC,CAACP,UAAU;AACzG;AAcA,OAAO,SAASQ,MAAMD,MAAe;IACnC,OAAO,OAAOA,WAAW,YAAYA,WAAW,QAAQ,AAACA,MAAkC,CAACP,UAAU,KAAK;AAC7G;AAEA,OAAO,SAASS,YAAed,KAAQ;IACrC,OAAOA;AACT;AAUA,OAAO,SAASe,GAAMf,KAAQ;IAC5B,IAAIa,MAAMb,QAAQ;QAChB,MAAM,IAAIG,UAAU;IACtB;IACA,OAAOW,YAAYd;AACrB;AAUA,OAAO,SAASgB,IAAOP,KAAQ;IAC7B,OAAO,IAAKD,gBAAwDC;AACtE;AAUA,OAAO,SAASQ,WAAcjB,KAAsB;IAClD,OAAO,AAAC,CAAA,OAAOA,UAAU,YAAY,OAAOA,UAAU,UAAS,KAAMA,UAAU,QAAQ,OAAO,AAACA,MAAyBkB,IAAI,KAAK;AACnI;AAOA,OAAO,SAASC,OAAUnB,KAAsB;IAC9C,OAAO,CAAE,CAAA,OAAOA,UAAU,YAAY,OAAOA,UAAU,UAAS,KAAMA,UAAU,QAAQ,OAAO,AAACA,MAAyBkB,IAAI,KAAK;AACpI"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nalloc",
3
3
  "description": "Rust-like Option and Result for TypeScript with near-zero allocations for extreme performance",
4
- "version": "0.0.3",
4
+ "version": "0.2.0",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
7
7
  "main": "build/index.cjs",
@@ -50,15 +50,32 @@
50
50
  "result",
51
51
  "maybe",
52
52
  "either",
53
+ "ok",
54
+ "err",
55
+ "some",
56
+ "none",
57
+ "unwrap",
53
58
  "rust",
54
59
  "typescript",
55
60
  "type-safe",
56
61
  "monad",
57
62
  "functional",
63
+ "fp",
64
+ "adt",
65
+ "algebraic-data-types",
66
+ "discriminated-union",
58
67
  "error-handling",
68
+ "try-catch",
69
+ "safe",
70
+ "nullable",
71
+ "null-safety",
59
72
  "pattern-matching",
60
73
  "zero-allocation",
61
- "performance"
74
+ "no-allocation",
75
+ "gc-friendly",
76
+ "performance",
77
+ "neverthrow-alternative",
78
+ "fp-ts-alternative"
62
79
  ],
63
80
  "author": "Ivan Zakharchanka",
64
81
  "license": "MIT",
@@ -68,23 +85,25 @@
68
85
  "homepage": "https://github.com/3axap4eHko/nalloc#readme",
69
86
  "devDependencies": {
70
87
  "@eslint/js": "^10.0.1",
71
- "@vitest/coverage-v8": "^4.0.18",
72
- "eslint": "^10.0.2",
88
+ "@vitest/coverage-v8": "^4.1.2",
89
+ "eslint": "^10.1.0",
73
90
  "eslint-plugin-prettier": "^5.5.5",
74
91
  "inop": "^0.9.0",
75
- "overtake": "^1.4.0",
92
+ "overtake": "^2.1.1",
76
93
  "prettier": "^3.8.1",
77
94
  "tsafe": "^1.8.12",
78
95
  "tslib": "^2.8.1",
79
- "typescript": "^5.9.3",
80
- "typescript-eslint": "^8.56.1",
81
- "vitest": "^4.0.18"
96
+ "typescript": "^6.0.2",
97
+ "typescript-eslint": "^8.58.0",
98
+ "vitest": "^4.1.2"
82
99
  },
83
100
  "scripts": {
84
- "check": "tsc src/__tests__/option.types.ts src/__tests__/result.types.ts --noEmit --lib esnext,dom --target esnext --module nodenext --moduleResolution nodenext",
101
+ "check": "tsc --noEmit -p tsconfig.check.json",
85
102
  "build": "rm -rf build && inop src build -i __tests__ -i *.tmp.ts && tsc --declaration --emitDeclarationOnly",
86
103
  "lint": "eslint .",
87
104
  "test": "vitest run",
88
- "bench": "overtake benchmarks/*"
105
+ "bench": "overtake benchmarks/* --pin-cores -w 1 --progress",
106
+ "bench:save": "pnpm bench --save-baseline .bench-baseline.json",
107
+ "bench:test": "pnpm bench --compare-baseline .bench-baseline.json"
89
108
  }
90
109
  }
@@ -1,6 +1,8 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import * as index from '../index.js';
3
+ import { pipe, Result } from '../index.js';
3
4
  import { isThenable, isSync } from '../types.js';
5
+ import { ok, err } from '../types.js';
4
6
 
5
7
  describe('index.ts exports', () => {
6
8
  it('exports exist', () => {
@@ -52,4 +54,36 @@ describe('MaybePromise guards', () => {
52
54
  expect(isSync(undefined)).toBe(true);
53
55
  });
54
56
  });
57
+ });
58
+
59
+ describe('pipe', () => {
60
+ it('returns value with no functions', () => {
61
+ expect(pipe(42)).toBe(42);
62
+ });
63
+
64
+ it('applies single function', () => {
65
+ expect(pipe(2, x => x * 3)).toBe(6);
66
+ });
67
+
68
+ it('applies multiple functions left to right', () => {
69
+ expect(pipe(2, x => x * 3, x => x + 1, x => String(x))).toBe('7');
70
+ });
71
+
72
+ it('works with Result operations', () => {
73
+ const result = pipe(
74
+ Result.tryCatch(() => JSON.parse('{"a":1}')),
75
+ r => Result.map(r, (v: { a: number }) => v.a),
76
+ r => Result.unwrapOr(r, 0),
77
+ );
78
+ expect(result).toBe(1);
79
+ });
80
+
81
+ it('works with Result error path', () => {
82
+ const result = pipe(
83
+ Result.tryCatch(() => JSON.parse('invalid')),
84
+ r => Result.map(r, (v: unknown) => v),
85
+ r => Result.unwrapOr(r, 'fallback'),
86
+ );
87
+ expect(result).toBe('fallback');
88
+ });
55
89
  });
@@ -38,7 +38,8 @@ import {
38
38
  satisfiesOption,
39
39
  filterMap,
40
40
  isNoneOr,
41
- findMap
41
+ findMap,
42
+ tapNone
42
43
  } from '../option.js';
43
44
  import { ok, err, some, none } from '../types.js';
44
45
 
@@ -176,6 +177,27 @@ describe('Option', () => {
176
177
  });
177
178
  });
178
179
 
180
+ describe('tapNone', () => {
181
+ it('runs for None and returns original', () => {
182
+ let called = false;
183
+ const result = tapNone(none, () => {
184
+ called = true;
185
+ });
186
+ expect(isNone(result)).toBe(true);
187
+ expect(called).toBe(true);
188
+ });
189
+
190
+ it('does not run for Some', () => {
191
+ let called = false;
192
+ const opt = of(5);
193
+ const result = tapNone(opt, () => {
194
+ called = true;
195
+ });
196
+ expect(result).toBe(opt);
197
+ expect(called).toBe(false);
198
+ });
199
+ });
200
+
179
201
  describe('filter', () => {
180
202
  it('keeps Some if predicate is true', () => {
181
203
  const result = filter(of(5), x => x > 3);
@@ -32,7 +32,8 @@ assert<Equals<typeof noneValue, None>>;
32
32
  const optValue: Option<number> = Math.random() > 0 ? of(5) : none;
33
33
  if (isSome(optValue)) {
34
34
  assert<Equals<typeof optValue, Some<number>>>;
35
- const directAccess: number = optValue;}
35
+ const _: number = optValue;
36
+ }
36
37
  if (isNone(optValue)) {
37
38
  assert<Equals<typeof optValue, None>>;
38
39
  }
@@ -33,6 +33,8 @@ import {
33
33
  isOkAnd,
34
34
  isErrAnd,
35
35
  tryCatch,
36
+ wrap,
37
+ toThrowable,
36
38
  unwrapOrReturn,
37
39
  assertOk,
38
40
  assertErr,
@@ -46,8 +48,12 @@ import {
46
48
  filterErr,
47
49
  safeTry,
48
50
  safeTryAsync,
49
- fromPromise
51
+ fromPromise,
52
+ fromSchema,
53
+ gen,
54
+ genAsync
50
55
  } from '../result.js';
56
+ import type { StandardSchema } from '../result.js';
51
57
  import { ok, err, isOk, isErr, optionOf as optOf, none } from '../types.js';
52
58
 
53
59
  describe('Result', () => {
@@ -600,6 +606,63 @@ describe('Result', () => {
600
606
 
601
607
  });
602
608
 
609
+ describe('wrap', () => {
610
+ it('wraps a function that succeeds', () => {
611
+ const safeParse = wrap(JSON.parse);
612
+ const result = safeParse('{"a":1}');
613
+ expect(isOk(result)).toBe(true);
614
+ expect(unwrap(result)).toEqual({ a: 1 });
615
+ });
616
+
617
+ it('wraps a function that throws', () => {
618
+ const safeParse = wrap(JSON.parse);
619
+ const result = safeParse('invalid');
620
+ expect(isErr(result)).toBe(true);
621
+ expect((result as any).error).toBeInstanceOf(SyntaxError);
622
+ });
623
+
624
+ it('preserves multi-arg signatures', () => {
625
+ const safeSlice = wrap((s: string, start: number, end: number) => s.slice(start, end));
626
+ const result = safeSlice('hello', 1, 3);
627
+ expect(unwrap(result)).toBe('el');
628
+ });
629
+
630
+ it('uses onError mapper', () => {
631
+ const safeParse = wrap(JSON.parse, (e) => (e as Error).message);
632
+ const result = safeParse('invalid');
633
+ expect(isErr(result)).toBe(true);
634
+ expect((result as any).error).toContain('JSON');
635
+ });
636
+ });
637
+
638
+ describe('toThrowable', () => {
639
+ it('returns Ok value for successful Result', () => {
640
+ const fn = (x: number) => ok(x * 2);
641
+ const throwing = toThrowable(fn);
642
+ expect(throwing(5)).toBe(10);
643
+ });
644
+
645
+ it('throws Err error for failed Result', () => {
646
+ const fn = (x: number) => x > 0 ? ok(x) : err('negative');
647
+ const throwing = toThrowable(fn);
648
+ expect(() => throwing(-1)).toThrow('negative');
649
+ });
650
+
651
+ it('throws Error instances directly', () => {
652
+ const fn = () => err(new TypeError('bad type'));
653
+ const throwing = toThrowable(fn);
654
+ expect(() => throwing()).toThrow(TypeError);
655
+ });
656
+
657
+ it('round-trips with wrap', () => {
658
+ const original = JSON.parse;
659
+ const safe = wrap(original);
660
+ const restored = toThrowable(safe);
661
+ expect(restored('{"a":1}')).toEqual({ a: 1 });
662
+ expect(() => restored('invalid')).toThrow(SyntaxError);
663
+ });
664
+ });
665
+
603
666
  describe('control helpers', () => {
604
667
  it('unwrapOrReturn returns value for Ok', () => {
605
668
  const value = unwrapOrReturn(ok(42), () => 'fallback');
@@ -788,6 +851,16 @@ describe('Result', () => {
788
851
  expect(await result).toEqual([[1, 2], ['a']]);
789
852
  });
790
853
 
854
+ it('preserves input order with interleaved sync/async', async () => {
855
+ const result = await partitionMaybePromise([
856
+ Promise.resolve(ok(1)),
857
+ ok(2),
858
+ Promise.resolve(err('a')),
859
+ err('b'),
860
+ ]);
861
+ expect(result).toEqual([[1, 2], ['a', 'b']]);
862
+ });
863
+
791
864
  it('handles all async values', async () => {
792
865
  const result = await partitionMaybePromise([
793
866
  Promise.resolve(ok(1)),
@@ -949,4 +1022,124 @@ describe('Result', () => {
949
1022
  });
950
1023
  });
951
1024
 
1025
+ describe('fromSchema', () => {
1026
+ const validSchema: StandardSchema<string> = {
1027
+ '~standard': {
1028
+ validate: (value) => typeof value === 'string'
1029
+ ? { value }
1030
+ : { issues: [{ message: 'Expected string' }] },
1031
+ },
1032
+ };
1033
+
1034
+ const asyncSchema: StandardSchema<number> = {
1035
+ '~standard': {
1036
+ validate: (value) => Promise.resolve(
1037
+ typeof value === 'number'
1038
+ ? { value }
1039
+ : { issues: [{ message: 'Expected number' }] },
1040
+ ),
1041
+ },
1042
+ };
1043
+
1044
+ it('returns Ok for valid sync schema', () => {
1045
+ const result = fromSchema(validSchema, 'hello');
1046
+ expect(isOk(result)).toBe(true);
1047
+ expect(result).toBe('hello');
1048
+ });
1049
+
1050
+ it('returns Err with issues for invalid sync schema', () => {
1051
+ const result = fromSchema(validSchema, 42);
1052
+ expect(isErr(result)).toBe(true);
1053
+ expect((result as any).error).toEqual([{ message: 'Expected string' }]);
1054
+ });
1055
+
1056
+ it('returns Ok for valid async schema', async () => {
1057
+ const result = await fromSchema(asyncSchema, 42);
1058
+ expect(isOk(result)).toBe(true);
1059
+ expect(result).toBe(42);
1060
+ });
1061
+
1062
+ it('returns Err for invalid async schema', async () => {
1063
+ const result = await fromSchema(asyncSchema, 'hello');
1064
+ expect(isErr(result)).toBe(true);
1065
+ expect((result as any).error).toEqual([{ message: 'Expected number' }]);
1066
+ });
1067
+ });
1068
+
1069
+ describe('gen', () => {
1070
+ it('returns Ok for successful execution', () => {
1071
+ const result = gen(function*($) {
1072
+ const a = yield* $(ok(10));
1073
+ const b = yield* $(ok(5));
1074
+ return a + b;
1075
+ });
1076
+ expect(isOk(result)).toBe(true);
1077
+ expect(result).toBe(15);
1078
+ });
1079
+
1080
+ it('short-circuits on first Err', () => {
1081
+ const result = gen(function*($) {
1082
+ const a = yield* $(ok(10));
1083
+ const b = yield* $(err('fail') as Result<number, string>);
1084
+ const c = yield* $(ok(5));
1085
+ return a + b + c;
1086
+ });
1087
+ expect(isErr(result)).toBe(true);
1088
+ expect((result as any).error).toBe('fail');
1089
+ });
1090
+
1091
+ it('propagates Err through chain', () => {
1092
+ const parse = (s: string) => s === 'bad' ? err('parse error') : ok(Number(s));
1093
+ const result = gen(function*($) {
1094
+ const a = yield* $(parse('10'));
1095
+ const b = yield* $(parse('bad'));
1096
+ const c = yield* $(parse('5'));
1097
+ return a + b + c;
1098
+ });
1099
+ expect(isErr(result)).toBe(true);
1100
+ expect((result as any).error).toBe('parse error');
1101
+ });
1102
+
1103
+ it('returns Ok for empty generator', () => {
1104
+ const result = gen(function*() {
1105
+ return 42;
1106
+ });
1107
+ expect(isOk(result)).toBe(true);
1108
+ expect(result).toBe(42);
1109
+ });
1110
+ });
1111
+
1112
+ describe('genAsync', () => {
1113
+ it('returns Ok for successful async execution', async () => {
1114
+ const result = await genAsync(async function*($) {
1115
+ const a = yield* $(ok(10));
1116
+ const b = yield* $(await fromPromise(Promise.resolve(5)));
1117
+ return a + b;
1118
+ });
1119
+ expect(isOk(result)).toBe(true);
1120
+ expect(result).toBe(15);
1121
+ });
1122
+
1123
+ it('short-circuits on first Err', async () => {
1124
+ const result = await genAsync(async function*($) {
1125
+ const a = yield* $(ok(10));
1126
+ const b = yield* $(err('async fail') as Result<number, string>);
1127
+ return a + b;
1128
+ });
1129
+ expect(isErr(result)).toBe(true);
1130
+ expect((result as any).error).toBe('async fail');
1131
+ });
1132
+
1133
+ it('handles rejected promises via fromPromise', async () => {
1134
+ const result = await genAsync(async function*($) {
1135
+ const a = yield* $(await fromPromise(Promise.resolve(10)));
1136
+ const b = yield* $(await fromPromise(Promise.reject('boom')));
1137
+ return a + b;
1138
+ });
1139
+ expect(isErr(result)).toBe(true);
1140
+ expect((result as any).error).toBe('boom');
1141
+ });
1142
+ });
1143
+
952
1144
  });
1145
+
@@ -6,12 +6,8 @@ import {
6
6
  mapErr,
7
7
  flatMap,
8
8
  bimap,
9
- unwrap,
10
- unwrapErr,
11
9
  unwrapOr,
12
10
  unwrapOrElse,
13
- expect,
14
- expectErr,
15
11
  and,
16
12
  or,
17
13
  orElse,
@@ -165,6 +161,12 @@ const tryResultTyped = of(() => {
165
161
  });
166
162
  assert<Equals<typeof tryResultTyped, Result<number, unknown>>>;
167
163
 
164
+ const tryResultResult= of(() => {
165
+ if (Math.random() > 0.5) err("error");
166
+ return 42;
167
+ });
168
+ assert<Equals<typeof tryResultResult, Result<number, unknown>>>;
169
+
168
170
 
169
171
  const unwrapOrResult = unwrapOr(err<string>("error") as Result<number, string>, 42);
170
172
  assert<Equals<typeof unwrapOrResult, number>>;
@@ -205,9 +207,20 @@ const tryCatchTyped = tryCatch<number, string>(() => {
205
207
  }, error => (error as Error).message);
206
208
  assert<Equals<typeof tryCatchTyped, Result<number, string>>>;
207
209
 
210
+ const tryCatchPassthroughErr = tryCatch(() => err('payload'));
211
+ assert<Equals<typeof tryCatchPassthroughErr, Err<unknown>>>;
212
+
213
+ const tryCatchPassthroughResult = tryCatch(() => Math.random() > 0.5 ? ok(1) : err('fail'));
214
+ assert<Equals<typeof tryCatchPassthroughResult, Result<1, unknown>>>;
215
+
216
+ const tryCatchPassthroughErrTyped = tryCatch(
217
+ () => err('payload'),
218
+ () => 0,
219
+ );
220
+ assert<Equals<typeof tryCatchPassthroughErrTyped, Err<string | number>>>;
208
221
 
209
222
  const unwrapFallback = unwrapOrReturn(ok(1) as Result<number, string>, () => 'fallback');
210
- assert<Equals<typeof unwrapFallback, number | string>>;
223
+ assert<Equals<typeof unwrapFallback, number | 'fallback'>>;
211
224
 
212
225
  declare const maybeResult: Result<number, string>;
213
226
  assertOk(maybeResult);
package/src/iter.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { isSome, isErr, err as ERR } from './types.js';
2
2
  import type { Option, Result, Ok } from './types.js';
3
3
 
4
+ const ITER_DONE: IteratorResult<never> = Object.freeze({ value: undefined as never, done: true as const });
5
+
4
6
  /**
5
7
  * Yields mapped values while the mapping function returns Some, stops at the first None.
6
8
  * @param source - The iterable to map over
@@ -42,7 +44,7 @@ export function safeIter<T>(source: Iterable<T>): IterableIterator<Result<T, unk
42
44
  return this;
43
45
  },
44
46
  next(): IteratorResult<Result<T, unknown>> {
45
- if (done) return { value: undefined, done: true };
47
+ if (done) return ITER_DONE;
46
48
  try {
47
49
  const next = iter.next();
48
50
  if (next.done) {
@@ -64,7 +66,7 @@ export function safeIter<T>(source: Iterable<T>): IterableIterator<Result<T, unk
64
66
  // suppressed
65
67
  }
66
68
  }
67
- return { value: undefined, done: true };
69
+ return ITER_DONE;
68
70
  },
69
71
  };
70
72
  }
package/src/option.ts CHANGED
@@ -4,6 +4,8 @@ import type { Some, None, Option, NoneValueType, ValueType, Result, Ok, Widen }
4
4
  export type { Some, None, Option };
5
5
  export { isSome, isNone, of };
6
6
 
7
+ const NONE_PAIR: readonly [None, None] = Object.freeze([NONE, NONE]);
8
+
7
9
  /**
8
10
  * Creates an Option from a nullable value with widened types.
9
11
  * @param value - The value to wrap
@@ -158,11 +160,7 @@ export function flatMap<T, U>(opt: Option<T>, fn: (value: T) => Option<U>): Opti
158
160
  * @param fn - Function returning an Option
159
161
  * @returns The result of fn(value) if Some, None otherwise
160
162
  */
161
- export function andThen<T, U>(opt: None, fn: (value: T) => Option<U>): None;
162
- export function andThen<T, U>(opt: Option<T>, fn: (value: T) => Option<U>): Option<U>;
163
- export function andThen<T, U>(opt: Option<T>, fn: (value: T) => Option<U>): Option<U> {
164
- return isNone(opt) ? NONE : fn(opt);
165
- }
163
+ export const andThen: typeof flatMap = flatMap;
166
164
 
167
165
  /**
168
166
  * Executes a side effect if Some, then returns the original Option.
@@ -182,6 +180,24 @@ export function tap<T>(opt: Option<T>, fn: (value: T) => void): Option<T> {
182
180
  return opt;
183
181
  }
184
182
 
183
+ /**
184
+ * Executes a side effect if None, then returns the original Option.
185
+ * @param opt - The Option to tap
186
+ * @param fn - Side effect function
187
+ * @returns The original Option unchanged
188
+ * @example
189
+ * tapNone(none, () => console.log('missing')) // logs 'missing', returns None
190
+ */
191
+ export function tapNone<T>(opt: Some<T>, fn: () => void): Some<T>;
192
+ export function tapNone(opt: None, fn: () => void): None;
193
+ export function tapNone<T>(opt: Option<T>, fn: () => void): Option<T>;
194
+ export function tapNone<T>(opt: Option<T>, fn: () => void): Option<T> {
195
+ if (isNone(opt)) {
196
+ fn();
197
+ }
198
+ return opt;
199
+ }
200
+
185
201
  /**
186
202
  * Returns true if None, or if Some and predicate returns true.
187
203
  * @param opt - The Option to check
@@ -355,7 +371,7 @@ export function zip<T, U>(opt: Option<T>, other: Option<U>): Option<[T, U]> {
355
371
  * unzip(none) // [None, None]
356
372
  */
357
373
  export function unzip<T, U>(opt: Option<[T, U]>): [Option<T>, Option<U>] {
358
- if (isNone(opt)) return [NONE, NONE];
374
+ if (isNone(opt)) return NONE_PAIR as [Option<T>, Option<U>];
359
375
  const [a, b] = opt;
360
376
  return [of(a), of(b)];
361
377
  }
@@ -412,7 +428,7 @@ export function flatten<T>(opt: Option<Option<T>>): Option<T> {
412
428
  * contains(none, 42) // false
413
429
  */
414
430
  export function contains<T>(opt: Option<T>, value: T): boolean {
415
- return isSome(opt) && opt === value;
431
+ return isSome(opt) && (opt === value || (opt !== opt && value !== value));
416
432
  }
417
433
 
418
434
  /**