import type { DataSourceAspect } from '../DataSourceAspect' import type { Described } from '../Described' import type { BlockedRequests } from './BlockedRequests' import type { Continue } from './Continue' import type { Cause } from '@principia/base/IO/Cause' import * as E from '@principia/base/Either' import * as Ca from '@principia/base/IO/Cause' import { matchTag_ } from '@principia/base/util/match' import * as BRS from './BlockedRequests' import * as Cont from './Continue' export class Blocked { readonly _R!: (_: R) => void readonly _E!: () => E readonly _A!: () => A readonly _tag = 'Blocked' constructor(readonly blockedRequests: BlockedRequests, readonly cont: Continue) {} } export class Done { readonly _R!: (_: unknown) => void readonly _E!: () => never readonly _A!: () => A readonly _tag = 'Done' constructor(readonly value: A) {} } export class Fail { readonly _R!: (_: unknown) => void readonly _E!: () => E readonly _A!: () => never readonly _tag = 'Fail' constructor(readonly cause: Cause) {} } export type Result = Blocked | Done | Fail export function blocked(blockedRequests: BlockedRequests, cont: Continue): Result { return new Blocked(blockedRequests, cont) } export function failCause(cause: Cause): Result { return new Fail(cause) } export function done(value: A): Done { return new Done(value) } export function map_(fa: Result, f: (a: A) => B): Result { return matchTag_(fa, { Blocked: ({ blockedRequests, cont }) => blocked(blockedRequests, Cont.map_(cont, f)), Fail: ({ cause }) => failCause(cause), Done: ({ value }) => done(f(value)) }) } export function map(f: (a: A) => B): (fa: Result) => Result { return (fa) => map_(fa, f) } export function mapDataSources_(fa: Result, f: DataSourceAspect): Result { return matchTag_(fa, { Blocked: ({ blockedRequests, cont }) => blocked(BRS.mapDataSources(blockedRequests, f), Cont.mapDataSources_(cont, f)), Done: ({ value }) => done(value), Fail: ({ cause }) => failCause(cause) }) } export function mapDataSources(f: DataSourceAspect): (fa: Result) => Result { return (fa) => mapDataSources_(fa, f) } export function fromEither(either: E.Either): Result { return E.match_( either, (e) => failCause(Ca.fail(e)), (a) => done(a) ) } export function gives_(ra: Result, f: Described<(r0: R0) => R>): Result { return matchTag_(ra, { Blocked: ({ blockedRequests, cont }) => blocked(BRS.gives_(blockedRequests, f), Cont.gives_(cont, f)), Fail: ({ cause }) => failCause(cause), Done: ({ value }) => done(value) }) } export function gives(f: Described<(r0: R0) => R>): (ra: Result) => Result { return (ra) => gives_(ra, f) }