import { checkFunction } from "../_check" import { AnyEvent, Dispose, EndHandler, ErrorHandler, Handler, ValueHandler, ValuesHandler, } from "../_interfaces" import { Transaction } from "../_tx" import { curry2, isArray } from "../_util" import * as Event from "../Event" import { Observable } from "../Observable" import { Eff, runEffects } from "./_eff" export const subscribe: CurriedSubscribe = curry2(_subscribe) export interface CurriedSubscribe { (f: Handler, observable: Observable): Dispose (f: Handler): (observable: Observable) => Dispose } export const onValue: CurriedOnValue = curry2(_onValue) export interface CurriedOnValue { (f: ValueHandler, observable: Observable): Dispose (f: ValueHandler): (observable: Observable) => Dispose } export const onValues: CurriedOnValues = curry2(_onValues) export interface CurriedOnValues { (f: ValuesHandler, observable: Observable): Dispose (f: ValuesHandler): (observable: Observable) => Dispose } export const onError: CurriedOnError = curry2(_onError) export interface CurriedOnError { (f: ErrorHandler, observable: Observable): Dispose (f: ErrorHandler): (observable: Observable) => Dispose } export const onEnd: CurriedOnEnd = curry2(_onEnd) export interface CurriedOnEnd { (f: EndHandler, observable: Observable): Dispose (f: EndHandler): (observable: Observable) => Dispose } function _subscribe(f: Handler, observable: Observable): Dispose { checkFunction(f) const s = new Subscribe(f) runEffects(s, observable) return function dispose(): void { s.dispose() } } function _onValue(f: ValueHandler, observable: Observable): Dispose { return _subscribe(e => Event.isNext(e) && f(e.value), observable) } function _onValues(f: ValuesHandler, observable: Observable): Dispose { const unfold = (vals: T[]) => (isArray(vals) ? f(...vals) : f(vals as any)) return _onValue(unfold, observable) } function _onError(f: ErrorHandler, observable: Observable): Dispose { return _subscribe(e => Event.isError(e) && f(e.error), observable) } function _onEnd(f: EndHandler, observable: Observable): Dispose { return _subscribe(e => Event.isEnd(e) && f(), observable) } class Subscribe extends Eff { constructor(private f: Handler) { super() } public next(tx: Transaction, val: T): void { this.handleEvent(new Event.Next(val)) } public error(tx: Transaction, err: Error): void { this.handleEvent(new Event.Error(err)) } public end(tx: Transaction): void { this.dispose() this.handleEvent(new Event.End()) } private handleEvent(event: AnyEvent): void { const { f } = this const result = f(event) if (result === Event.noMore) { this.dispose() } } }