import { Lambda1, Lambda1_deps, Lambda1_toFunction, Lambda2, Lambda2_deps, Lambda2_toFunction } from "./Lambda"; import { StreamWithSend } from "./Stream"; import { CoalesceHandler } from "./CoalesceHandler"; import { Transaction } from "./Transaction"; import { Vertex } from './Vertex'; /** * A stream that allows values to be pushed into it, acting as an interface between the * world of I/O and the world of FRP. Code that exports StreamSinks for read-only use * should downcast to {@link Stream}. */ export class StreamSink extends StreamWithSend { private disableListenCheck: boolean = false; constructor(f? : ((l : A, r : A) => A) | Lambda2) { super(); if (!f) f = <(l : A, r : A) => A>((l : A, r : A) => { throw new Error("send() called more than once per transaction, which isn't allowed. Did you want to combine the events? Then pass a combining function to your StreamSink constructor."); }); this.coalescer = new CoalesceHandler(f, this); } private coalescer : CoalesceHandler; send(a : A) : void { Transaction.run( () => { // We throw this error if we send into FRP logic that has been constructed // but nothing is listening to it yet. We need to do it this way because // it's the only way to manage memory in a language with no finalizers. if (!this.disableListenCheck) { if (this.vertex.refCount() == 0) { throw new Error("send() was invoked before listeners were registered"); } } // if (Transaction.currentTransaction.inCallback > 0) throw new Error("You are not allowed to use send() inside a Sodium callback"); this.coalescer.send_(a); } ) } listen_(target : Vertex, h : (a : A) => void, suppressEarlierFirings : boolean) : () => void { let result = super.listen_(target, h, suppressEarlierFirings); this.disableListenCheck = true; return result; } }