summaryrefslogtreecommitdiff
path: root/u/trace/itrace.ts
diff options
context:
space:
mode:
Diffstat (limited to 'u/trace/itrace.ts')
-rw-r--r--u/trace/itrace.ts107
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;
+ }
+}