diff options
Diffstat (limited to 'u/trace/itrace.ts')
-rw-r--r-- | u/trace/itrace.ts | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/u/trace/itrace.ts b/u/trace/itrace.ts new file mode 100644 index 0000000..e6189d3 --- /dev/null +++ b/u/trace/itrace.ts @@ -0,0 +1,107 @@ +import type { Mapper, SideEffect, Supplier } from "@emprespresso/pengueno"; + +// the "thing" every Trace writer must "trace()" +type BaseTraceWith = string; +export type ITraceWith<T> = BaseTraceWith | T; +export interface ITrace<TraceWith> { + addTrace: Mapper<ITraceWith<TraceWith>, ITrace<TraceWith>>; + trace: SideEffect<ITraceWith<TraceWith>>; +} + +export type ITraceableTuple<T, TraceWith> = [T, BaseTraceWith | TraceWith]; +export type ITraceableMapper< + T, + U, + TraceWith, + W = ITraceable<T, TraceWith>, +> = ( + w: W, +) => U; + +export interface ITraceable<T, Trace = BaseTraceWith> { + readonly trace: ITrace<Trace>; + get: Supplier<T>; + move: <U>(u: U) => ITraceable<U, Trace>; + map: <U>( + mapper: ITraceableMapper<T, U, Trace>, + ) => ITraceable<U, Trace>; + bimap: <U>( + mapper: ITraceableMapper< + T, + ITraceableTuple<U, Array<Trace> | Trace>, + Trace + >, + ) => ITraceable<U, Trace>; + peek: (peek: ITraceableMapper<T, void, Trace>) => ITraceable<T, Trace>; + flatMap: <U>( + mapper: ITraceableMapper<T, ITraceable<U, Trace>, Trace>, + ) => ITraceable<U, Trace>; + flatMapAsync<U>( + mapper: ITraceableMapper<T, Promise<ITraceable<U, Trace>>, Trace>, + ): ITraceable<Promise<U>, Trace>; +} + +export class TraceableImpl<T, TraceWith> implements ITraceable<T, TraceWith> { + protected constructor( + private readonly item: T, + public readonly trace: ITrace<TraceWith>, + ) {} + + public map<U>( + mapper: ITraceableMapper<T, U, TraceWith>, + ) { + const result = mapper(this); + return new TraceableImpl(result, this.trace); + } + + public flatMap<U>( + mapper: ITraceableMapper< + T, + ITraceable<U, TraceWith>, + TraceWith + >, + ): ITraceable<U, TraceWith> { + return mapper(this); + } + + public flatMapAsync<U>( + mapper: ITraceableMapper< + T, + Promise<ITraceable<U, TraceWith>>, + TraceWith + >, + ): ITraceable<Promise<U>, TraceWith> { + return new TraceableImpl( + mapper(this).then((t) => t.get()), + this.trace, + ); + } + + public peek(peek: ITraceableMapper<T, void, TraceWith>) { + peek(this); + return this; + } + + public move<Tt>(t: Tt): ITraceable<Tt, TraceWith> { + return this.map(() => t); + } + + public bimap<U>( + mapper: ITraceableMapper< + T, + ITraceableTuple<U, Array<TraceWith> | TraceWith>, + TraceWith + >, + ) { + const [item, trace] = mapper(this); + const traces = Array.isArray(trace) ? trace : [trace]; + return new TraceableImpl( + item, + traces.reduce((trace, _trace) => trace.addTrace(_trace), this.trace), + ); + } + + public get() { + return this.item; + } +} |