// ets_tracing: off /** * inspired by https://github.com/tusharmath/qio/pull/22 (revised) */ import * as Tp from "../Collections/Immutable/Tuple/index.js" import type { Either } from "../Either/index.js" import type { NoSuchElementException } from "../GlobalExceptions/index.js" import type { Has, Tag } from "../Has/index.js" import type { Managed } from "../Managed/managed.js" import { ManagedImpl } from "../Managed/managed.js" import type { ReleaseMap } from "../Managed/ReleaseMap/index.js" import { makeReleaseMap } from "../Managed/ReleaseMap/makeReleaseMap.js" import { releaseAll } from "../Managed/ReleaseMap/releaseAll.js" import type { Option } from "../Option/index.js" import * as Utils from "../Utils/index.js" import { bracketExit_ } from "./bracketExit.js" import { _A, _E, _R } from "./commons.js" import { chain_, succeed, suspend, unit } from "./core.js" import type { Effect } from "./effect.js" import { sequential } from "./ExecutionStrategy.js" import { fail } from "./fail.js" import { fromEither } from "./fromEither.js" import { getOrFail } from "./getOrFail.js" import { service } from "./has.js" import { map_ } from "./map.js" import { provideSome_ } from "./provideSome.js" export class GenEffect { readonly [_R]!: (_R: R) => void; readonly [_E]!: () => E; readonly [_A]!: () => A constructor( readonly effect: Effect | Managed, readonly trace?: string ) {} *[Symbol.iterator](): Generator, A, any> { return yield this } } function adapter(_: any, __?: any, ___?: any) { if (Utils.isEither(_)) { return new GenEffect( fromEither(() => _), __ ) } if (Utils.isOption(_)) { if (__ && typeof __ === "function") { return new GenEffect(_._tag === "None" ? fail(__()) : succeed(_.value), ___) } return new GenEffect(getOrFail(_), __) } if (Utils.isTag(_)) { return new GenEffect(service(_), __) } return new GenEffect(_, __) } export interface Adapter { (_: Tag, __trace?: string): GenEffect, never, A> (_: Option, onNone: () => E, __trace?: string): GenEffect (_: Option, __trace?: string): GenEffect (_: Either, __trace?: string): GenEffect (_: Effect, __trace?: string): GenEffect } export interface AdapterWithManaged extends Adapter { (_: Managed, __trace?: string): GenEffect } export function genM, AEff>( f: (i: AdapterWithManaged) => Generator, __trace?: string ): Effect, Utils._E, AEff> { return suspend(() => { const iterator = f(adapter as any) const state = iterator.next() function run( rm: ReleaseMap, state: IteratorYieldResult | IteratorReturnResult ): Effect { if (state.done) { return succeed(state.value) } return chain_( suspend( () => state.value.trace ? state.value["effect"] instanceof ManagedImpl ? map_( provideSome_(state.value["effect"]["effect"], (r0) => Tp.tuple(r0, rm) ), (_) => _.get(1) ) : (state.value["effect"] as Effect) : state.value["effect"] instanceof ManagedImpl ? map_( provideSome_(state.value["effect"]["effect"], (r0) => Tp.tuple(r0, rm) ), (_) => _.get(1) ) : (state.value["effect"] as Effect), state.value.trace ), (val) => { const next = iterator.next(val) return run(rm, next) } ) } return chain_(makeReleaseMap, (rm) => bracketExit_( unit, () => run(rm, state), (_, e) => releaseAll(e, sequential)(rm) ) ) }, __trace) } export function gen, AEff>( f: (i: Adapter) => Generator, __trace?: string ): Effect, Utils._E, AEff> { return suspend(() => { const iterator = f(adapter as any) const state = iterator.next() function run( state: IteratorYieldResult | IteratorReturnResult ): Effect { if (state.done) { return succeed(state.value) } return chain_( suspend( () => state.value["effect"] as Effect, state.value.trace ), (val: any) => run(iterator.next(val)) ) } return run(state) }, __trace) }