209 lines
8.0 KiB
TypeScript
209 lines
8.0 KiB
TypeScript
import { bench, describe } from 'vitest';
|
|
import { STANDARD } from '../helpers/bench-options.js';
|
|
import {
|
|
ok,
|
|
err,
|
|
ntOk,
|
|
ntErr,
|
|
TsOk,
|
|
TsErr,
|
|
OxOk,
|
|
OxErr,
|
|
oxMatch,
|
|
E,
|
|
pipe,
|
|
TmResult,
|
|
} from '../helpers/imports.js';
|
|
|
|
const double = (x: number) => x * 2;
|
|
const toUpper = (e: string) => e.toUpperCase();
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// map — success path
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.map — success path', () => {
|
|
const nm = ok(42);
|
|
const nt = ntOk(42);
|
|
const ts = TsOk(42);
|
|
const ox = OxOk(42);
|
|
const fp = E.right(42);
|
|
const tm = TmResult.ok<number, string>(42);
|
|
|
|
bench('native-monad', () => { nm.map(double); }, STANDARD);
|
|
bench('neverthrow', () => { nt.map(double); }, STANDARD);
|
|
bench('ts-results-es', () => { ts.map(double); }, STANDARD);
|
|
bench('oxide.ts', () => { ox.map(double); }, STANDARD);
|
|
bench('fp-ts', () => { pipe(fp, E.map(double)); }, STANDARD);
|
|
bench('true-myth', () => { tm.map(double); }, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// map — failure path (no-op)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.map — failure path (no-op)', () => {
|
|
const nm = err('fail');
|
|
const nt = ntErr('fail');
|
|
const ts = TsErr('fail');
|
|
const ox = OxErr('fail');
|
|
const fp = E.left('fail');
|
|
const tm = TmResult.err<number, string>('fail');
|
|
|
|
bench('native-monad', () => { nm.map(double); }, STANDARD);
|
|
bench('neverthrow', () => { nt.map(double); }, STANDARD);
|
|
bench('ts-results-es', () => { ts.map(double); }, STANDARD);
|
|
bench('oxide.ts', () => { ox.map(double); }, STANDARD);
|
|
bench('fp-ts', () => { pipe(fp, E.map(double)); }, STANDARD);
|
|
bench('true-myth', () => { tm.map(double); }, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// flatMap — success path
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.flatMap — success path', () => {
|
|
const nm = ok(42);
|
|
const nt = ntOk(42);
|
|
const ts = TsOk<number, string>(42);
|
|
const ox = OxOk(42);
|
|
const fp = E.right(42);
|
|
const tm = TmResult.ok<number, string>(42);
|
|
|
|
bench('native-monad', () => { nm.flatMap(x => ok(x * 2)); }, STANDARD);
|
|
bench('neverthrow', () => { nt.andThen(x => ntOk(x * 2)); }, STANDARD);
|
|
bench('ts-results-es', () => { ts.andThen(x => TsOk(x * 2)); }, STANDARD);
|
|
bench('oxide.ts', () => { ox.andThen(x => OxOk(x * 2)); }, STANDARD);
|
|
bench('fp-ts', () => { pipe(fp, E.flatMap(x => E.right(x * 2))); }, STANDARD);
|
|
bench('true-myth', () => { tm.andThen(x => TmResult.ok(x * 2)); }, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// flatMap — failure path (no-op)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.flatMap — failure path (no-op)', () => {
|
|
const nm = err('fail');
|
|
const nt = ntErr('fail');
|
|
const ts = TsErr<number, string>('fail');
|
|
const ox = OxErr('fail');
|
|
const fp = E.left('fail');
|
|
const tm = TmResult.err<number, string>('fail');
|
|
|
|
bench('native-monad', () => { nm.flatMap(x => ok(x * 2)); }, STANDARD);
|
|
bench('neverthrow', () => { nt.andThen(x => ntOk(x * 2)); }, STANDARD);
|
|
bench('ts-results-es', () => { ts.andThen(x => TsOk(x * 2)); }, STANDARD);
|
|
bench('oxide.ts', () => { ox.andThen(x => OxOk(x * 2)); }, STANDARD);
|
|
bench('fp-ts', () => { pipe(fp, E.flatMap(x => E.right(x * 2))); }, STANDARD);
|
|
bench('true-myth', () => { tm.andThen(x => TmResult.ok(x * 2)); }, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// mapErr — error path
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.mapErr — error path', () => {
|
|
const nm = err('fail');
|
|
const nt = ntErr('fail');
|
|
const ts = TsErr<number, string>('fail');
|
|
const ox = OxErr('fail');
|
|
const fp = E.left('fail');
|
|
const tm = TmResult.err<number, string>('fail');
|
|
|
|
bench('native-monad', () => { nm.mapErr(toUpper); }, STANDARD);
|
|
bench('neverthrow', () => { nt.mapErr(toUpper); }, STANDARD);
|
|
bench('ts-results-es', () => { ts.mapErr(toUpper); }, STANDARD);
|
|
bench('oxide.ts', () => { ox.mapErr(toUpper); }, STANDARD);
|
|
bench('fp-ts', () => { pipe(fp, E.mapLeft(toUpper)); }, STANDARD);
|
|
bench('true-myth', () => { tm.mapErr(toUpper); }, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// mapErr — success path (no-op)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.mapErr — success path (no-op)', () => {
|
|
const nm = ok(42);
|
|
const nt = ntOk(42);
|
|
const ts = TsOk<number, string>(42);
|
|
const ox = OxOk(42);
|
|
const fp = E.right(42);
|
|
const tm = TmResult.ok<number, string>(42);
|
|
|
|
bench('native-monad', () => { nm.mapErr(toUpper); }, STANDARD);
|
|
bench('neverthrow', () => { nt.mapErr(toUpper); }, STANDARD);
|
|
bench('ts-results-es', () => { ts.mapErr(toUpper); }, STANDARD);
|
|
bench('oxide.ts', () => { ox.mapErr(toUpper); }, STANDARD);
|
|
bench('fp-ts', () => { pipe(fp, E.mapLeft(toUpper)); }, STANDARD);
|
|
bench('true-myth', () => { tm.mapErr(toUpper); }, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// match — success path
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.match — success path', () => {
|
|
const nm = ok(42);
|
|
const nt = ntOk(42);
|
|
const ox = OxOk(42);
|
|
const fp = E.right(42);
|
|
const tm = TmResult.ok<number, string>(42);
|
|
|
|
bench('native-monad', () => { nm.match(x => x * 2, () => 0); }, STANDARD);
|
|
bench('neverthrow', () => { nt.match(x => x * 2, () => 0); }, STANDARD);
|
|
// ts-results-es has no match — skip
|
|
bench('oxide.ts', () => { oxMatch(ox, { Ok: (x: number) => x * 2, Err: () => 0 }); }, STANDARD);
|
|
bench('fp-ts', () => { pipe(fp, E.match(() => 0, x => x * 2)); }, STANDARD);
|
|
bench('true-myth', () => { tm.match({ Ok: x => x * 2, Err: () => 0 }); }, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// match — failure path
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.match — failure path', () => {
|
|
const nm = err('fail');
|
|
const nt = ntErr('fail');
|
|
const ox = OxErr('fail');
|
|
const fp = E.left('fail');
|
|
const tm = TmResult.err<number, string>('fail');
|
|
|
|
bench('native-monad', () => { nm.match(() => 0, e => e.length); }, STANDARD);
|
|
bench('neverthrow', () => { nt.match(() => 0, e => e.length); }, STANDARD);
|
|
bench('oxide.ts', () => { oxMatch(ox, { Ok: () => 0, Err: (e: string) => e.length }); }, STANDARD);
|
|
bench('fp-ts', () => { pipe(fp, E.match(e => e.length, () => 0)); }, STANDARD);
|
|
bench('true-myth', () => { tm.match({ Ok: () => 0, Err: e => e.length }); }, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// filter — success path (predicate passes)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.filter — predicate passes', () => {
|
|
const nm = ok(42);
|
|
const fp = E.right(42);
|
|
|
|
bench('native-monad', () => { nm.filter(x => x > 0, () => 'negative'); }, STANDARD);
|
|
// neverthrow: no filter — skip
|
|
// ts-results-es: no filter — skip
|
|
// oxide.ts: filter returns Option, not Result — different semantics, skip
|
|
bench('fp-ts', () => {
|
|
pipe(fp, E.filterOrElse(x => x > 0, () => 'negative' as const));
|
|
}, STANDARD);
|
|
// true-myth: no filter — skip
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// filter — predicate fails
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Result.filter — predicate fails', () => {
|
|
const nm = ok(-1);
|
|
const fp = E.right(-1);
|
|
|
|
bench('native-monad', () => { nm.filter(x => x > 0, () => 'negative'); }, STANDARD);
|
|
bench('fp-ts', () => {
|
|
pipe(fp, E.filterOrElse(x => x > 0, () => 'negative' as const));
|
|
}, STANDARD);
|
|
});
|