summaryrefslogtreecommitdiff
path: root/u/trace/itrace.ts
blob: b4830676dec8c565ffa603f78e9e3fd367091c69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import { Mapper, SideEffect } from "../fn/mod.ts";

export interface ITrace<TracingW> {
  addTrace: Mapper<TracingW, ITrace<TracingW>>;
  trace: SideEffect<TracingW>;
}

export type ITraceableTuple<T, Trace> = [T, Trace];
export type ITraceableMapper<T, Trace, U, W = ITraceable<T, Trace>> = (
  w: W,
) => U;

export interface ITraceable<T, Trace> {
  readonly item: T;
  readonly trace: ITrace<Trace>;

  move<U>(u: U): ITraceable<U, Trace>;
  map: <U>(
    mapper: ITraceableMapper<T, Trace, U>,
  ) => ITraceable<U, Trace>;
  bimap: <U>(
    mapper: ITraceableMapper<T, Trace, ITraceableTuple<U, Trace>>,
  ) => ITraceable<U, Trace>;
  peek: (peek: ITraceableMapper<T, Trace, void>) => ITraceable<T, Trace>;
  flatMap: <U>(
    mapper: ITraceableMapper<T, Trace, ITraceable<U, Trace>>,
  ) => ITraceable<U, Trace>;
  flatMapAsync<U>(
    mapper: ITraceableMapper<T, Trace, Promise<ITraceable<U, Trace>>>,
  ): ITraceable<Promise<U>, Trace>;
}

export class TraceableImpl<T, L> implements ITraceable<T, L> {
  protected constructor(
    readonly item: T,
    readonly trace: ITrace<L>,
  ) {}

  public map<U>(mapper: ITraceableMapper<T, L, U>) {
    const result = mapper(this);
    return new TraceableImpl(result, this.trace);
  }

  public flatMap<U>(
    mapper: ITraceableMapper<T, L, ITraceable<U, L>>,
  ): ITraceable<U, L> {
    return mapper(this);
  }

  public flatMapAsync<U>(
    mapper: ITraceableMapper<T, L, Promise<ITraceable<U, L>>>,
  ): ITraceable<Promise<U>, L> {
    return new TraceableImpl(
      mapper(this).then(({ item }) => item),
      this.trace,
    );
  }

  public peek(peek: ITraceableMapper<T, L, void>) {
    peek(this);
    return this;
  }

  public move<Tt>(t: Tt): ITraceable<Tt, L> {
    return this.map(() => t);
  }

  public bimap<U>(mapper: ITraceableMapper<T, L, ITraceableTuple<U, L>>) {
    const [item, trace] = mapper(this);
    return new TraceableImpl(item, this.trace.addTrace(trace));
  }
}