Mirror: 🎩 A tiny but capable push & pull stream library for TypeScript and Flow
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Restructure all the things

+1572 -1488
+15 -4
bsconfig.json
··· 15 15 "sources": [ 16 16 { 17 17 "dir": "src", 18 - "subdirs": [{ 19 - "dir": "web", 20 - "backend": ["js"] 21 - }] 18 + "subdirs": [ 19 + { 20 + "dir": "operators" 21 + }, 22 + { 23 + "dir": "sources" 24 + }, 25 + { 26 + "dir": "sinks" 27 + }, 28 + { 29 + "dir": "web", 30 + "backend": ["js"] 31 + } 32 + ] 22 33 }, 23 34 { 24 35 "dir": "__tests__",
+1 -2
src/index.d.ts
··· 1 - export { Talkback, Signal, Sink, Subscription, Source, Operator, Observer, Subject } from './wonka_types'; 2 - 3 1 export * from './pipe'; 2 + export * from './wonka_types'; 4 3 export * from './wonka'; 5 4 export * from './web/wonkaJs';
+3
src/operators/wonka_operator_combine.d.ts
··· 1 + import { Source } from '../wonka_types'; 2 + 3 + export const combine: <A, B>(a: Source<A>, b: Source<B>) => Source<[A, B]>;
+86
src/operators/wonka_operator_combine.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type combineStateT('a, 'b) = { 5 + mutable talkbackA: (.talkbackT) => unit, 6 + mutable talkbackB: (.talkbackT) => unit, 7 + mutable lastValA: option('a), 8 + mutable lastValB: option('b), 9 + mutable gotSignal: bool, 10 + mutable endCounter: int, 11 + mutable ended: bool, 12 + }; 13 + 14 + let combine = (sourceA, sourceB) => curry(sink => { 15 + let state = { 16 + talkbackA: talkbackPlaceholder, 17 + talkbackB: talkbackPlaceholder, 18 + lastValA: None, 19 + lastValB: None, 20 + gotSignal: false, 21 + endCounter: 0, 22 + ended: false 23 + }; 24 + 25 + sourceA((.signal) => { 26 + switch (signal, state.lastValB) { 27 + | (Start(tb), _) => state.talkbackA = tb 28 + | (Push(a), None) => { 29 + state.lastValA = Some(a); 30 + state.gotSignal = false; 31 + } 32 + | (Push(a), Some(b)) when !state.ended => { 33 + state.lastValA = Some(a); 34 + state.gotSignal = false; 35 + sink(.Push((a, b))); 36 + } 37 + | (End, _) when state.endCounter < 1 => 38 + state.endCounter = state.endCounter + 1 39 + | (End, _) when !state.ended => { 40 + state.ended = true; 41 + sink(.End); 42 + } 43 + | _ => () 44 + } 45 + }); 46 + 47 + sourceB((.signal) => { 48 + switch (signal, state.lastValA) { 49 + | (Start(tb), _) => state.talkbackB = tb 50 + | (Push(b), None) => { 51 + state.lastValB = Some(b); 52 + state.gotSignal = false; 53 + } 54 + | (Push(b), Some(a)) when !state.ended => { 55 + state.lastValB = Some(b); 56 + state.gotSignal = false; 57 + sink(.Push((a, b))); 58 + } 59 + | (End, _) when state.endCounter < 1 => 60 + state.endCounter = state.endCounter + 1 61 + | (End, _) when !state.ended => { 62 + state.ended = true; 63 + sink(.End); 64 + } 65 + | _ => () 66 + } 67 + }); 68 + 69 + sink(.Start((.signal) => { 70 + if (!state.ended) { 71 + switch (signal) { 72 + | Close => { 73 + state.ended = true; 74 + state.talkbackA(.Close); 75 + state.talkbackB(.Close); 76 + } 77 + | Pull when !state.gotSignal => { 78 + state.gotSignal = true; 79 + state.talkbackA(.signal); 80 + state.talkbackB(.signal); 81 + } 82 + | Pull => () 83 + } 84 + }; 85 + })); 86 + });
+3
src/operators/wonka_operator_combine.rei
··· 1 + open Wonka_types; 2 + 3 + let combine: (sourceT('a), sourceT('b), sinkT(('a, 'b))) => unit;
+5
src/operators/wonka_operator_concatMap.d.ts
··· 1 + import { Source, Operator } from '../wonka_types'; 2 + 3 + export const concatMap: <A, B>(f: (value: A) => Source<B>) => Operator<A, B>; 4 + export const concat: <A>(sources: Array<Source<A>>) => Source<A>; 5 + export const concatAll: <A>(source: Source<Source<A>>) => Source<A>;
+94
src/operators/wonka_operator_concatMap.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type concatMapStateT('a) = { 5 + inputQueue: Rebel.MutableQueue.t('a), 6 + mutable outerTalkback: (.talkbackT) => unit, 7 + mutable innerTalkback: (.talkbackT) => unit, 8 + mutable innerActive: bool, 9 + mutable closed: bool, 10 + mutable ended: bool 11 + }; 12 + 13 + let concatMap = f => curry(source => curry(sink => { 14 + let state: concatMapStateT('a) = { 15 + inputQueue: Rebel.MutableQueue.make(), 16 + outerTalkback: talkbackPlaceholder, 17 + innerTalkback: talkbackPlaceholder, 18 + innerActive: false, 19 + closed: false, 20 + ended: false 21 + }; 22 + 23 + let rec applyInnerSource = innerSource => 24 + innerSource((.signal) => { 25 + switch (signal) { 26 + | End => { 27 + state.innerActive = false; 28 + state.innerTalkback = talkbackPlaceholder; 29 + 30 + switch (Rebel.MutableQueue.pop(state.inputQueue)) { 31 + | Some(input) => applyInnerSource(f(.input)) 32 + | None when state.ended => sink(.End) 33 + | None => () 34 + }; 35 + } 36 + | Start(tb) => { 37 + state.innerActive = true; 38 + state.innerTalkback = tb; 39 + tb(.Pull); 40 + } 41 + | Push(x) when !state.closed => { 42 + sink(.Push(x)); 43 + state.innerTalkback(.Pull); 44 + } 45 + | Push(_) => () 46 + } 47 + }); 48 + 49 + source((.signal) => { 50 + switch (signal) { 51 + | End when !state.ended => { 52 + state.ended = true; 53 + if (!state.innerActive && Rebel.MutableQueue.isEmpty(state.inputQueue)) { 54 + sink(.End); 55 + } 56 + } 57 + | End => () 58 + | Start(tb) => { 59 + state.outerTalkback = tb; 60 + tb(.Pull); 61 + } 62 + | Push(x) when !state.ended => { 63 + if (state.innerActive) { 64 + Rebel.MutableQueue.add(state.inputQueue, x); 65 + } else { 66 + applyInnerSource(f(.x)); 67 + } 68 + 69 + state.outerTalkback(.Pull); 70 + } 71 + | Push(_) => () 72 + } 73 + }); 74 + 75 + sink(.Start((.signal) => { 76 + switch (signal) { 77 + | Pull => if (!state.ended) state.innerTalkback(.Pull) 78 + | Close when !state.ended => { 79 + state.ended = true; 80 + state.closed = true; 81 + state.outerTalkback(.Close); 82 + state.innerTalkback(.Close); 83 + } 84 + | Close => () 85 + } 86 + })); 87 + })); 88 + 89 + let concatAll = source => concatMap((.x) => x, source); 90 + 91 + let concat = sources => { 92 + open Wonka_source_fromArray; 93 + concatMap((.x) => x, fromArray(sources)); 94 + };
+5
src/operators/wonka_operator_concatMap.rei
··· 1 + open Wonka_types; 2 + 3 + let concatMap: ((.'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 4 + let concat: (array(sourceT('a)), sinkT('a)) => unit; 5 + let concatAll: (sourceT(sourceT('a)), sinkT('a)) => unit;
+3
src/operators/wonka_operator_filter.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const filter: <A>(f: (value: A) => boolean) => Operator<A, A>;
+11
src/operators/wonka_operator_filter.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + let filter = f => curry(source => curry(sink => { 5 + captureTalkback(source, (.signal, talkback) => { 6 + switch (signal) { 7 + | Push(x) when !f(.x) => talkback(.Pull) 8 + | _ => sink(.signal) 9 + } 10 + }); 11 + }));
+3
src/operators/wonka_operator_filter.rei
··· 1 + open Wonka_types; 2 + 3 + let filter: ((.'a) => bool, sourceT('a), sinkT('a)) => unit;
+3
src/operators/wonka_operator_map.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const map: <A, B>(f: (value: A) => B) => Operator<A, B>;
+11
src/operators/wonka_operator_map.re
··· 1 + open Wonka_types; 2 + 3 + let map = f => curry(source => curry(sink => { 4 + source((.signal) => sink(. 5 + switch (signal) { 6 + | Start(x) => Start(x) 7 + | Push(x) => Push(f(.x)) 8 + | End => End 9 + } 10 + )); 11 + }));
+3
src/operators/wonka_operator_map.rei
··· 1 + open Wonka_types; 2 + 3 + let map: ((.'a) => 'b, sourceT('a), sinkT('b)) => unit;
+6
src/operators/wonka_operator_mergeMap.d.ts
··· 1 + import { Source, Operator } from '../wonka_types'; 2 + 3 + export const mergeMap: <A, B>(f: (value: A) => Source<B>) => Operator<A, B>; 4 + export const merge: <A>(sources: Array<Source<A>>) => Source<A>; 5 + export const mergeAll: <A>(source: Source<Source<A>>) => Source<A>; 6 + export const flatten: <A>(source: Source<Source<A>>) => Source<A>;
+85
src/operators/wonka_operator_mergeMap.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type mergeMapStateT = { 5 + mutable outerTalkback: (.talkbackT) => unit, 6 + mutable innerTalkbacks: Rebel.Array.t((.talkbackT) => unit), 7 + mutable ended: bool 8 + }; 9 + 10 + let mergeMap = f => curry(source => curry(sink => { 11 + let state: mergeMapStateT = { 12 + outerTalkback: talkbackPlaceholder, 13 + innerTalkbacks: Rebel.Array.makeEmpty(), 14 + ended: false 15 + }; 16 + 17 + let applyInnerSource = innerSource => { 18 + let talkback = ref(talkbackPlaceholder); 19 + 20 + innerSource((.signal) => { 21 + switch (signal) { 22 + | End => { 23 + state.innerTalkbacks = Rebel.Array.filter(state.innerTalkbacks, x => x !== talkback^); 24 + if (state.ended && Rebel.Array.size(state.innerTalkbacks) === 0) { 25 + sink(.End); 26 + } 27 + } 28 + | Start(tb) => { 29 + talkback := tb; 30 + state.innerTalkbacks = Rebel.Array.append(state.innerTalkbacks, tb); 31 + tb(.Pull); 32 + } 33 + | Push(x) when Rebel.Array.size(state.innerTalkbacks) !== 0 => { 34 + sink(.Push(x)); 35 + talkback^(.Pull); 36 + } 37 + | Push(_) => () 38 + } 39 + }); 40 + }; 41 + 42 + source((.signal) => { 43 + switch (signal) { 44 + | End when !state.ended => { 45 + state.ended = true; 46 + if (Rebel.Array.size(state.innerTalkbacks) === 0) { 47 + sink(.End); 48 + } 49 + } 50 + | End => () 51 + | Start(tb) => { 52 + state.outerTalkback = tb; 53 + tb(.Pull); 54 + } 55 + | Push(x) when !state.ended => { 56 + applyInnerSource(f(.x)); 57 + state.outerTalkback(.Pull); 58 + } 59 + | Push(_) => () 60 + } 61 + }); 62 + 63 + sink(.Start((.signal) => { 64 + switch (signal) { 65 + | Close when !state.ended => { 66 + state.ended = true; 67 + state.outerTalkback(.Close); 68 + Rebel.Array.forEach(state.innerTalkbacks, talkback => talkback(.Close)); 69 + state.innerTalkbacks = Rebel.Array.makeEmpty(); 70 + } 71 + | Close => () 72 + | Pull when !state.ended => 73 + Rebel.Array.forEach(state.innerTalkbacks, talkback => talkback(.Pull)); 74 + | Pull => () 75 + } 76 + })); 77 + })); 78 + 79 + let merge = sources => { 80 + open Wonka_source_fromArray; 81 + mergeMap((.x) => x, fromArray(sources)); 82 + }; 83 + 84 + let mergeAll = source => mergeMap((.x) => x, source); 85 + let flatten = mergeAll;
+6
src/operators/wonka_operator_mergeMap.rei
··· 1 + open Wonka_types; 2 + 3 + let mergeMap: ((.'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 4 + let merge: (array(sourceT('a)), sinkT('a)) => unit; 5 + let mergeAll: (sourceT(sourceT('a)), sinkT('a)) => unit; 6 + let flatten: (sourceT(sourceT('a)), sinkT('a)) => unit;
+3
src/operators/wonka_operator_scan.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const scan: <A, B>(f: (acc: B, value: A) => B, acc: B) => Operator<A, B>;
+16
src/operators/wonka_operator_scan.re
··· 1 + open Wonka_types; 2 + 3 + let scan = (f, seed) => curry(source => curry(sink => { 4 + let acc = ref(seed); 5 + 6 + source((.signal) => sink(. 7 + switch (signal) { 8 + | Push(x) => { 9 + acc := f(acc^, x); 10 + Push(acc^) 11 + } 12 + | Start(x) => Start(x) 13 + | End => End 14 + } 15 + )); 16 + }));
+3
src/operators/wonka_operator_scan.rei
··· 1 + open Wonka_types; 2 + 3 + let scan: (('b, 'a) => 'b, 'b, sourceT('a), sinkT('b)) => unit;
+3
src/operators/wonka_operator_share.d.ts
··· 1 + import { Source } from '../wonka_types'; 2 + 3 + export const share: <A>(source: Source<A>) => Source<A>;
+52
src/operators/wonka_operator_share.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type shareStateT('a) = { 5 + mutable sinks: Rebel.Array.t(sinkT('a)), 6 + mutable talkback: (.talkbackT) => unit, 7 + mutable gotSignal: bool 8 + }; 9 + 10 + let share = source => { 11 + let state = { 12 + sinks: Rebel.Array.makeEmpty(), 13 + talkback: talkbackPlaceholder, 14 + gotSignal: false 15 + }; 16 + 17 + sink => { 18 + state.sinks = Rebel.Array.append(state.sinks, sink); 19 + 20 + if (Rebel.Array.size(state.sinks) === 1) { 21 + source((.signal) => { 22 + switch (signal) { 23 + | Push(_) => { 24 + state.gotSignal = false; 25 + Rebel.Array.forEach(state.sinks, sink => sink(.signal)); 26 + } 27 + | Start(x) => state.talkback = x 28 + | End => { 29 + Rebel.Array.forEach(state.sinks, sink => sink(.End)); 30 + state.sinks = Rebel.Array.makeEmpty(); 31 + } 32 + } 33 + }); 34 + }; 35 + 36 + sink(.Start((.signal) => { 37 + switch (signal) { 38 + | Close => { 39 + state.sinks = Rebel.Array.filter(state.sinks, x => x !== sink); 40 + if (Rebel.Array.size(state.sinks) === 0) { 41 + state.talkback(.Close); 42 + }; 43 + } 44 + | Pull when !state.gotSignal => { 45 + state.gotSignal = true; 46 + state.talkback(.signal); 47 + } 48 + | Pull => () 49 + } 50 + })); 51 + } 52 + };
+3
src/operators/wonka_operator_share.rei
··· 1 + open Wonka_types; 2 + 3 + let share: (sourceT('a), sinkT('a)) => unit;
+3
src/operators/wonka_operator_skip.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const skip: <A>(max: number) => Operator<A, A>;
+16
src/operators/wonka_operator_skip.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + let skip = wait => curry(source => curry(sink => { 5 + let rest = ref(wait); 6 + 7 + captureTalkback(source, (.signal, talkback) => { 8 + switch (signal) { 9 + | Push(_) when rest^ > 0 => { 10 + rest := rest^ - 1; 11 + talkback(.Pull); 12 + } 13 + | _ => sink(.signal) 14 + } 15 + }); 16 + }));
+3
src/operators/wonka_operator_skip.rei
··· 1 + open Wonka_types; 2 + 3 + let skip: (int, sourceT('a), sinkT('a)) => unit;
+3
src/operators/wonka_operator_skipUntil.d.ts
··· 1 + import { Source, Operator } from '../wonka_types'; 2 + 3 + export const skipUntil: <A>(signal: Source<any>) => Operator<A, A>;
+69
src/operators/wonka_operator_skipUntil.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type skipUntilStateT = { 5 + mutable skip: bool, 6 + mutable ended: bool, 7 + mutable gotSignal: bool, 8 + mutable sourceTalkback: (.talkbackT) => unit, 9 + mutable notifierTalkback: (.talkbackT) => unit 10 + }; 11 + 12 + let skipUntil = notifier => curry(source => curry(sink => { 13 + let state: skipUntilStateT = { 14 + skip: true, 15 + ended: false, 16 + gotSignal: false, 17 + sourceTalkback: talkbackPlaceholder, 18 + notifierTalkback: talkbackPlaceholder 19 + }; 20 + 21 + source((.signal) => { 22 + switch (signal) { 23 + | Start(tb) => { 24 + state.sourceTalkback = tb; 25 + 26 + notifier((.signal) => { 27 + switch (signal) { 28 + | Start(innerTb) => { 29 + state.notifierTalkback = innerTb; 30 + innerTb(.Pull); 31 + tb(.Pull); 32 + } 33 + | Push(_) => { 34 + state.skip = false; 35 + state.notifierTalkback(.Close); 36 + } 37 + | End => () 38 + } 39 + }); 40 + } 41 + | Push(_) when state.skip && !state.ended => state.sourceTalkback(.Pull) 42 + | Push(_) when !state.ended => { 43 + state.gotSignal = false; 44 + sink(.signal) 45 + } 46 + | Push(_) => () 47 + | End => { 48 + if (state.skip) state.notifierTalkback(.Close); 49 + state.ended = true; 50 + sink(.End) 51 + } 52 + } 53 + }); 54 + 55 + sink(.Start((.signal) => { 56 + switch (signal) { 57 + | Close => { 58 + if (state.skip) state.notifierTalkback(.Close); 59 + state.ended = true; 60 + state.sourceTalkback(.Close); 61 + } 62 + | Pull when !state.gotSignal && !state.ended => { 63 + state.gotSignal = true; 64 + state.sourceTalkback(.Pull); 65 + } 66 + | Pull => () 67 + } 68 + })); 69 + }));
+3
src/operators/wonka_operator_skipUntil.rei
··· 1 + open Wonka_types; 2 + 3 + let skipUntil: (sourceT('a), sourceT('b), sinkT('b)) => unit;
+3
src/operators/wonka_operator_skipWhile.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const skipWhile: <A>(f: (x: A) => boolean) => Operator<A, A>;
+20
src/operators/wonka_operator_skipWhile.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + let skipWhile = f => curry(source => curry(sink => { 5 + let skip = ref(true); 6 + 7 + captureTalkback(source, (.signal, talkback) => { 8 + switch (signal) { 9 + | Push(x) when skip^ => { 10 + if (f(.x)) { 11 + talkback(.Pull); 12 + } else { 13 + skip := false; 14 + sink(.signal); 15 + }; 16 + } 17 + | _ => sink(.signal) 18 + } 19 + }); 20 + }));
+3
src/operators/wonka_operator_skipWhile.rei
··· 1 + open Wonka_types; 2 + 3 + let skipWhile: ((.'a) => bool, sourceT('a), sinkT('a)) => unit;
+3
src/operators/wonka_operator_switchMap.d.ts
··· 1 + import { Source, Operator } from '../wonka_types'; 2 + 3 + export const switchMap: <A, B>(f: (value: A) => Source<B>) => Operator<A, B>;
+78
src/operators/wonka_operator_switchMap.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type switchMapStateT('a) = { 5 + mutable outerTalkback: (.talkbackT) => unit, 6 + mutable innerTalkback: (.talkbackT) => unit, 7 + mutable innerActive: bool, 8 + mutable closed: bool, 9 + mutable ended: bool 10 + }; 11 + 12 + let switchMap = f => curry(source => curry(sink => { 13 + let state: switchMapStateT('a) = { 14 + outerTalkback: talkbackPlaceholder, 15 + innerTalkback: talkbackPlaceholder, 16 + innerActive: false, 17 + closed: false, 18 + ended: false 19 + }; 20 + 21 + let applyInnerSource = innerSource => 22 + innerSource((.signal) => { 23 + switch (signal) { 24 + | End => { 25 + state.innerActive = false; 26 + state.innerTalkback = talkbackPlaceholder; 27 + if (state.ended) sink(.End); 28 + } 29 + | Start(tb) => { 30 + state.innerActive = true; 31 + state.innerTalkback = tb; 32 + tb(.Pull); 33 + } 34 + | Push(x) when !state.closed => { 35 + sink(.Push(x)); 36 + state.innerTalkback(.Pull); 37 + } 38 + | Push(_) => () 39 + } 40 + }); 41 + 42 + source((.signal) => { 43 + switch (signal) { 44 + | End when !state.ended => { 45 + state.ended = true; 46 + if (!state.innerActive) sink(.End); 47 + } 48 + | End => () 49 + | Start(tb) => { 50 + state.outerTalkback = tb; 51 + tb(.Pull); 52 + } 53 + | Push(x) when !state.ended => { 54 + if (state.innerActive) { 55 + state.innerTalkback(.Close); 56 + state.innerTalkback = talkbackPlaceholder; 57 + } 58 + applyInnerSource(f(.x)); 59 + state.outerTalkback(.Pull); 60 + } 61 + | Push(_) => () 62 + } 63 + }); 64 + 65 + sink(.Start((.signal) => { 66 + switch (signal) { 67 + | Pull => state.innerTalkback(.Pull) 68 + | Close when !state.ended => { 69 + state.ended = true; 70 + state.closed = true; 71 + state.outerTalkback(.Close); 72 + state.innerTalkback(.Close); 73 + state.innerTalkback = talkbackPlaceholder; 74 + } 75 + | Close => () 76 + } 77 + })); 78 + }));
+3
src/operators/wonka_operator_switchMap.rei
··· 1 + open Wonka_types; 2 + 3 + let switchMap: ((.'a) => sourceT('b), sourceT('a), sinkT('b)) => unit;
+3
src/operators/wonka_operator_take.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const take: <A>(max: number) => Operator<A, A>;
+47
src/operators/wonka_operator_take.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type takeStateT = { 5 + mutable taken: int, 6 + mutable talkback: (.talkbackT) => unit 7 + }; 8 + 9 + let take = max => curry(source => curry(sink => { 10 + let state: takeStateT = { 11 + taken: 0, 12 + talkback: talkbackPlaceholder 13 + }; 14 + 15 + source((.signal) => { 16 + switch (signal) { 17 + | Start(tb) => state.talkback = tb; 18 + | Push(_) when state.taken < max => { 19 + state.taken = state.taken + 1; 20 + sink(.signal); 21 + 22 + if (state.taken === max) { 23 + sink(.End); 24 + state.talkback(.Close); 25 + }; 26 + } 27 + | Push(_) => () 28 + | End when state.taken < max => { 29 + state.taken = max; 30 + sink(.End) 31 + } 32 + | End => () 33 + } 34 + }); 35 + 36 + sink(.Start((.signal) => { 37 + if (state.taken < max) { 38 + switch (signal) { 39 + | Pull => state.talkback(.Pull); 40 + | Close => { 41 + state.taken = max; 42 + state.talkback(.Close); 43 + } 44 + } 45 + }; 46 + })); 47 + }));
+3
src/operators/wonka_operator_take.rei
··· 1 + open Wonka_types; 2 + 3 + let take: (int, sourceT('a), sinkT('a)) => unit;
+3
src/operators/wonka_operator_takeLast.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const takeLast: <A>(max: number) => Operator<A, A>;
+23
src/operators/wonka_operator_takeLast.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + let takeLast = max => curry(source => curry(sink => { 5 + open Rebel; 6 + let queue = MutableQueue.make(); 7 + 8 + captureTalkback(source, (.signal, talkback) => { 9 + switch (signal) { 10 + | Start(_) => talkback(.Pull) 11 + | Push(x) => { 12 + let size = MutableQueue.size(queue); 13 + if (size >= max && max > 0) { 14 + ignore(MutableQueue.pop(queue)); 15 + }; 16 + 17 + MutableQueue.add(queue, x); 18 + talkback(.Pull); 19 + } 20 + | End => makeTrampoline(sink, (.) => MutableQueue.pop(queue)) 21 + } 22 + }); 23 + }));
+3
src/operators/wonka_operator_takeLast.rei
··· 1 + open Wonka_types; 2 + 3 + let takeLast: (int, sourceT('a), sinkT('a)) => unit;
+3
src/operators/wonka_operator_takeUntil.d.ts
··· 1 + import { Source, Operator } from '../wonka_types'; 2 + 3 + export const takeUntil: <A>(signal: Source<any>) => Operator<A, A>;
+60
src/operators/wonka_operator_takeUntil.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type takeUntilStateT = { 5 + mutable ended: bool, 6 + mutable sourceTalkback: (.talkbackT) => unit, 7 + mutable notifierTalkback: (.talkbackT) => unit 8 + }; 9 + 10 + let takeUntil = notifier => curry(source => curry(sink => { 11 + let state: takeUntilStateT = { 12 + ended: false, 13 + sourceTalkback: talkbackPlaceholder, 14 + notifierTalkback: talkbackPlaceholder 15 + }; 16 + 17 + source((.signal) => { 18 + switch (signal) { 19 + | Start(tb) => { 20 + state.sourceTalkback = tb; 21 + 22 + notifier((.signal) => { 23 + switch (signal) { 24 + | Start(innerTb) => { 25 + state.notifierTalkback = innerTb; 26 + innerTb(.Pull); 27 + } 28 + | Push(_) => { 29 + state.ended = true; 30 + state.notifierTalkback(.Close); 31 + state.sourceTalkback(.Close); 32 + sink(.End); 33 + } 34 + | End => () 35 + } 36 + }); 37 + } 38 + | End when !state.ended => { 39 + state.notifierTalkback(.Close); 40 + state.ended = true; 41 + sink(.End); 42 + } 43 + | End => () 44 + | Push(_) when !state.ended => sink(.signal) 45 + | Push(_) => () 46 + } 47 + }); 48 + 49 + sink(.Start((.signal) => { 50 + if (!state.ended) { 51 + switch (signal) { 52 + | Close => { 53 + state.sourceTalkback(.Close); 54 + state.notifierTalkback(.Close); 55 + } 56 + | Pull => state.sourceTalkback(.Pull) 57 + } 58 + }; 59 + })); 60 + }));
+3
src/operators/wonka_operator_takeUntil.rei
··· 1 + open Wonka_types; 2 + 3 + let takeUntil: (sourceT('a), sourceT('b), sinkT('b)) => unit;
+3
src/operators/wonka_operator_takeWhile.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const takeWhile: <A>(f: (x: A) => boolean) => Operator<A, A>;
+43
src/operators/wonka_operator_takeWhile.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + let takeWhile = f => curry(source => curry(sink => { 5 + let ended = ref(false); 6 + let talkback = ref(talkbackPlaceholder); 7 + 8 + source((.signal) => { 9 + switch (signal) { 10 + | Start(tb) => { 11 + talkback := tb; 12 + sink(.signal); 13 + } 14 + | End when !ended^ => { 15 + ended := true; 16 + sink(.End); 17 + } 18 + | End => () 19 + | Push(x) when !ended^ => { 20 + if (!f(.x)) { 21 + ended := true; 22 + sink(.End); 23 + talkback^(.Close); 24 + } else { 25 + sink(.signal); 26 + }; 27 + } 28 + | Push(_) => () 29 + } 30 + }); 31 + 32 + sink(.Start((.signal) => { 33 + if (!ended^) { 34 + switch (signal) { 35 + | Pull => talkback^(.Pull); 36 + | Close => { 37 + ended := true; 38 + talkback^(.Close); 39 + } 40 + } 41 + }; 42 + })); 43 + }));
+3
src/operators/wonka_operator_takeWhile.rei
··· 1 + open Wonka_types; 2 + 3 + let takeWhile: ((.'a) => bool, sourceT('a), sinkT('a)) => unit;
+3
src/operators/wonka_operator_tap.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const tap: <A>(f: (value: A) => void) => Operator<A, A>;
+12
src/operators/wonka_operator_tap.re
··· 1 + open Wonka_types; 2 + 3 + let tap = f => curry(source => curry(sink => { 4 + source((.signal) => { 5 + switch (signal) { 6 + | Push(x) => f(.x) 7 + | _ => () 8 + }; 9 + 10 + sink(.signal); 11 + }); 12 + }));
+3
src/operators/wonka_operator_tap.rei
··· 1 + open Wonka_types; 2 + 3 + let tap: ((.'a) => unit, sourceT('a), sinkT('a)) => unit;
+3
src/sinks/wonka_sink_publish.d.ts
··· 1 + import { Source, Subscription } from '../wonka_types'; 2 + 3 + export const publish: <A>(source: Source<A>) => Subscription;
+33
src/sinks/wonka_sink_publish.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type publishStateT = { 5 + mutable talkback: (.talkbackT) => unit, 6 + mutable ended: bool 7 + }; 8 + 9 + let publish = source => { 10 + let state: publishStateT = { 11 + talkback: talkbackPlaceholder, 12 + ended: false 13 + }; 14 + 15 + source((.signal) => { 16 + switch (signal) { 17 + | Start(x) => { 18 + state.talkback = x; 19 + x(.Pull); 20 + } 21 + | Push(_) => if (!state.ended) state.talkback(.Pull); 22 + | End => state.ended = true; 23 + } 24 + }); 25 + 26 + { 27 + unsubscribe: () => 28 + if (!state.ended) { 29 + state.ended = true; 30 + state.talkback(.Close); 31 + } 32 + } 33 + };
+3
src/sinks/wonka_sink_publish.rei
··· 1 + open Wonka_types; 2 + 3 + let publish: sourceT('a) => subscriptionT;
+4
src/sinks/wonka_sink_subscribe.d.ts
··· 1 + import { Source, Subscription } from '../wonka_types'; 2 + 3 + export const subscribe: <A>(f: (x: A) => void) => (source: Source<A>) => Subscription; 4 + export const forEach: <A>(f: (x: A) => void) => (source: Source<A>) => void;
+41
src/sinks/wonka_sink_subscribe.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + type subscribeStateT = { 5 + mutable talkback: (.talkbackT) => unit, 6 + mutable ended: bool 7 + }; 8 + 9 + let subscribe = f => curry(source => { 10 + let state: subscribeStateT = { 11 + talkback: talkbackPlaceholder, 12 + ended: false 13 + }; 14 + 15 + source((.signal) => { 16 + switch (signal) { 17 + | Start(x) => { 18 + state.talkback = x; 19 + x(.Pull); 20 + } 21 + | Push(x) when !state.ended => { 22 + f(.x); 23 + state.talkback(.Pull); 24 + } 25 + | Push(_) => () 26 + | End => state.ended = true; 27 + } 28 + }); 29 + 30 + { 31 + unsubscribe: () => 32 + if (!state.ended) { 33 + state.ended = true; 34 + state.talkback(.Close); 35 + } 36 + } 37 + }); 38 + 39 + let forEach = f => curry(source => { 40 + ignore(subscribe(f, source)); 41 + });
+4
src/sinks/wonka_sink_subscribe.rei
··· 1 + open Wonka_types; 2 + 3 + let subscribe: ((.'a) => unit, sourceT('a)) => subscriptionT; 4 + let forEach: ((.'a) => unit, sourceT('a)) => unit;
+3
src/sources/wonka_source_fromArray.d.ts
··· 1 + import { Source } from '../wonka_types'; 2 + 3 + export const fromArray: <A>(array: A[]) => Source<A>;
+44
src/sources/wonka_source_fromArray.re
··· 1 + open Wonka_types; 2 + 3 + type fromArrayState('a) = { 4 + mutable index: int, 5 + mutable ended: bool, 6 + mutable looping: bool, 7 + mutable pull: bool 8 + }; 9 + 10 + let fromArray = arr => curry(sink => { 11 + let size = Rebel.Array.size(arr); 12 + let state = { 13 + index: 0, 14 + ended: false, 15 + looping: false, 16 + pull: false 17 + }; 18 + 19 + sink(.Start((.signal) => { 20 + switch (signal, state.looping) { 21 + | (Pull, false) => { 22 + state.pull = true; 23 + state.looping = true; 24 + 25 + while (state.pull && !state.ended) { 26 + let index = state.index; 27 + if (index < size) { 28 + let x = Rebel.Array.getUnsafe(arr, index); 29 + state.index = index + 1; 30 + state.pull = false; 31 + sink(.Push(x)); 32 + } else { 33 + state.ended = true; 34 + sink(.End); 35 + } 36 + }; 37 + 38 + state.looping = false; 39 + } 40 + | (Pull, true) => state.pull = true 41 + | (Close, _) => state.ended = true 42 + } 43 + })); 44 + });
+3
src/sources/wonka_source_fromArray.rei
··· 1 + open Wonka_types; 2 + 3 + let fromArray: (array('a), sinkT('a)) => unit;
+3
src/sources/wonka_source_fromList.d.ts
··· 1 + import { List, Source } from '../wonka_types'; 2 + 3 + export const fromList: <A>(list: List<A>) => Source<A>;
+44
src/sources/wonka_source_fromList.re
··· 1 + open Wonka_types; 2 + 3 + type fromListState('a) = { 4 + mutable value: 'a, 5 + mutable ended: bool, 6 + mutable looping: bool, 7 + mutable pull: bool 8 + }; 9 + 10 + let fromList = ls => curry(sink => { 11 + let state = { 12 + value: ls, 13 + ended: false, 14 + looping: false, 15 + pull: false 16 + }; 17 + 18 + sink(.Start((.signal) => { 19 + switch (signal, state.looping) { 20 + | (Pull, false) => { 21 + state.pull = true; 22 + state.looping = true; 23 + 24 + while (state.pull && !state.ended) { 25 + switch (state.value) { 26 + | [x, ...rest] => { 27 + state.value = rest; 28 + state.pull = false; 29 + sink(.Push(x)); 30 + } 31 + | [] => { 32 + state.ended = true; 33 + sink(.End); 34 + } 35 + } 36 + }; 37 + 38 + state.looping = false; 39 + } 40 + | (Pull, true) => state.pull = true 41 + | (Close, _) => state.ended = true 42 + } 43 + })); 44 + });
+3
src/sources/wonka_source_fromList.rei
··· 1 + open Wonka_types; 2 + 3 + let fromList: (list('a), sinkT('a)) => unit;
+3
src/sources/wonka_source_fromValue.d.ts
··· 1 + import { Source } from '../wonka_types'; 2 + 3 + export const fromValue: <A>(value: A) => Source<A>;
+16
src/sources/wonka_source_fromValue.re
··· 1 + open Wonka_types; 2 + 3 + let fromValue = x => curry(sink => { 4 + let ended = ref(false); 5 + 6 + sink(.Start((.signal) => { 7 + switch (signal) { 8 + | Pull when !ended^ => { 9 + ended := true; 10 + sink(.Push(x)); 11 + sink(.End); 12 + } 13 + | _ => () 14 + } 15 + })); 16 + });
+3
src/sources/wonka_source_fromValue.rei
··· 1 + open Wonka_types; 2 + 3 + let fromValue: ('a, sinkT('a)) => unit;
+3
src/sources/wonka_source_make.d.ts
··· 1 + import { Source, Observer } from '../wonka_types'; 2 + 3 + export const make: <A>(f: (observer: Observer<A>) => (() => void)) => Source<A>;
+15
src/sources/wonka_source_make.re
··· 1 + open Wonka_types; 2 + 3 + let make = f => curry(sink => { 4 + let teardown = f(.{ 5 + next: value => sink(.Push(value)), 6 + complete: () => sink(.End) 7 + }); 8 + 9 + sink(.Start((.signal) => { 10 + switch (signal) { 11 + | Close => teardown(.) 12 + | Pull => () 13 + } 14 + })); 15 + });
+3
src/sources/wonka_source_make.rei
··· 1 + open Wonka_types; 2 + 3 + let make: ((.observerT('a)) => teardownT, sinkT('a)) => unit;
+3
src/sources/wonka_source_makeSubject.d.ts
··· 1 + import { Subject } from '../wonka_types'; 2 + 3 + export const makeSubject: <A>() => Subject<A>;
+35
src/sources/wonka_source_makeSubject.re
··· 1 + open Wonka_types; 2 + 3 + type subjectState('a) = { 4 + mutable sinks: Rebel.Array.t(sinkT('a)), 5 + mutable ended: bool 6 + }; 7 + 8 + let makeSubject = () => { 9 + let state: subjectState('a) = { 10 + sinks: Rebel.Array.makeEmpty(), 11 + ended: false, 12 + }; 13 + 14 + let source = sink => { 15 + state.sinks = Rebel.Array.append(state.sinks, sink); 16 + sink(.Start((.signal) => { 17 + if (signal === Close) { 18 + state.sinks = Rebel.Array.filter(state.sinks, x => x !== sink); 19 + } 20 + })); 21 + }; 22 + 23 + let next = value => 24 + if (!state.ended) { 25 + Rebel.Array.forEach(state.sinks, sink => sink(.Push(value))); 26 + }; 27 + 28 + let complete = () => 29 + if (!state.ended) { 30 + state.ended = true; 31 + Rebel.Array.forEach(state.sinks, sink => sink(.End)); 32 + }; 33 + 34 + { source, next, complete } 35 + };
+3
src/sources/wonka_source_makeSubject.rei
··· 1 + open Wonka_types; 2 + 3 + let makeSubject: unit => subjectT('a);
+4
src/sources/wonka_source_primitives.d.ts
··· 1 + import { Source } from '../wonka_types'; 2 + 3 + export const empty: Source<{}>; 4 + export const never: Source<{}>;
+11
src/sources/wonka_source_primitives.re
··· 1 + open Wonka_types; 2 + open Wonka_helpers; 3 + 4 + let empty = sink => { 5 + sink(.Start(talkbackPlaceholder)); 6 + sink(.End); 7 + }; 8 + 9 + let never = sink => { 10 + sink(.Start(talkbackPlaceholder)); 11 + };
+4
src/sources/wonka_source_primitives.rei
··· 1 + open Wonka_types; 2 + 3 + let empty: (sinkT('a)) => unit; 4 + let never: (sinkT('a)) => unit;
+12 -15
src/web/wonkaJs.d.ts
··· 1 - import { Sink, Source, Operator } from '../wonka_types'; 1 + /* operators */ 2 + export * from './wonka_operator_debounce'; 3 + export * from './wonka_operator_delay'; 4 + export * from './wonka_operator_interval'; 5 + export * from './wonka_operator_sample'; 6 + export * from './wonka_operator_throttle'; 2 7 3 - export const fromListener: <E>( 4 - addListener: (cb: (event: E) => void) => void, 5 - removeListener: (cb: (event: E) => void) => void 6 - ) => Source<E>; 8 + /* sinks */ 9 + export * from './wonka_sink_toPromise'; 7 10 8 - export const fromDomEvent: <E>(HTMLElement, string) => Source<E>; 9 - export const interval: (interval: number) => Source<number>; 10 - export const fromPromise: <A>(promise: Promise<A>) => Source<A>; 11 - 12 - export const debounce: <A>(f: (x: A) => number) => Operator<A, A>; 13 - export const throttle: <A>(f: (x: A) => number) => Operator<A, A>; 14 - export const sample: <A>(signal: Source<any>) => Operator<A, A>; 15 - export const delay: <A>(duration: number) => Operator<A, A>; 16 - 17 - export const toPromise: <A>(source: Source<A>) => Promise<A>; 11 + /* sources */ 12 + export * from './wonka_source_fromDomEvent'; 13 + export * from './wonka_source_fromListener'; 14 + export * from './wonka_source_fromPromise';
+12 -275
src/web/wonkaJs.re
··· 1 - open Wonka_types; 2 - 3 - let fromListener = (addListener, removeListener) => curry(sink => { 4 - let handler = event => sink(.Push(event)); 5 - 6 - sink(.Start((.signal) => { 7 - switch (signal) { 8 - | Close => removeListener(handler) 9 - | _ => () 10 - } 11 - })); 12 - 13 - addListener(handler); 14 - }); 15 - 16 - let fromDomEvent = (element, event) => curry(sink => { 17 - let addEventListener: ( 18 - Dom.element, 19 - string, 20 - (Dom.event) => unit 21 - ) => unit = [%raw {| 22 - function (element, event, handler) { 23 - element.addEventListener(event, handler); 24 - } 25 - |}]; 26 - 27 - let removeEventListener: ( 28 - Dom.element, 29 - string, 30 - (Dom.event) => unit 31 - ) => unit = [%raw {| 32 - function (element, event, handler) { 33 - element.removeEventListener(event, handler); 34 - } 35 - |}]; 36 - 37 - fromListener( 38 - handler => addEventListener(element, event, handler), 39 - handler => removeEventListener(element, event, handler), 40 - sink 41 - ) 42 - }); 43 - 44 - let interval = p => curry(sink => { 45 - let i = ref(0); 46 - let id = Js.Global.setInterval(() => { 47 - let num = i^; 48 - i := i^ + 1; 49 - sink(.Push(num)); 50 - }, p); 51 - 52 - sink(.Start((.signal) => { 53 - switch (signal) { 54 - | Close => Js.Global.clearInterval(id) 55 - | _ => () 56 - } 57 - })); 58 - }); 59 - 60 - let fromPromise = promise => curry(sink => { 61 - let ended = ref(false); 62 - 63 - ignore(Js.Promise.then_(value => { 64 - if (!ended^) { 65 - sink(.Push(value)); 66 - sink(.End); 67 - }; 68 - 69 - Js.Promise.resolve(()) 70 - }, promise)); 71 - 72 - sink(.Start((.signal) => { 73 - switch (signal) { 74 - | Close => ended := true 75 - | _ => () 76 - } 77 - })); 78 - }); 79 - 80 - let debounce = f => curry(source => curry(sink => { 81 - let gotEndSignal = ref(false); 82 - let id: ref(option(Js.Global.timeoutId)) = ref(None); 83 - 84 - let clearTimeout = () => 85 - switch (id^) { 86 - | Some(timeoutId) => { 87 - id := None; 88 - Js.Global.clearTimeout(timeoutId); 89 - } 90 - | None => () 91 - }; 92 - 93 - source((.signal) => { 94 - switch (signal) { 95 - | Start(tb) => { 96 - sink(.Start((.signal) => { 97 - switch (signal) { 98 - | Close => { 99 - clearTimeout(); 100 - tb(.Close); 101 - } 102 - | _ => tb(.signal) 103 - } 104 - })); 105 - } 106 - | Push(x) => { 107 - clearTimeout(); 108 - id := Some(Js.Global.setTimeout(() => { 109 - id := None; 110 - sink(.signal); 111 - if (gotEndSignal^) sink(.End); 112 - }, f(.x))); 113 - } 114 - | End => { 115 - gotEndSignal := true; 116 - 117 - switch (id^) { 118 - | None => sink(.End) 119 - | _ => () 120 - }; 121 - } 122 - } 123 - }); 124 - })); 1 + /* operators */ 2 + include Wonka_operator_debounce; 3 + include Wonka_operator_delay; 4 + include Wonka_operator_interval; 5 + include Wonka_operator_sample; 6 + include Wonka_operator_throttle; 125 7 126 - let throttle = f => curry(source => curry(sink => { 127 - let skip = ref(false); 128 - let id: ref(option(Js.Global.timeoutId)) = ref(None); 129 - let clearTimeout = () => 130 - switch (id^) { 131 - | Some(timeoutId) => Js.Global.clearTimeout(timeoutId); 132 - | None => () 133 - }; 8 + /* sinks */ 9 + include Wonka_sink_toPromise; 134 10 135 - source((.signal) => { 136 - switch (signal) { 137 - | Start(tb) => { 138 - sink(.Start((.signal) => { 139 - switch (signal) { 140 - | Close => { 141 - clearTimeout(); 142 - tb(.Close); 143 - } 144 - | _ => tb(.signal) 145 - } 146 - })); 147 - } 148 - | End => { 149 - clearTimeout(); 150 - sink(.End); 151 - } 152 - | Push(x) when !skip^ => { 153 - skip := true; 154 - clearTimeout(); 155 - id := Some(Js.Global.setTimeout(() => { 156 - id := None; 157 - skip := false; 158 - }, f(.x))); 159 - sink(.signal); 160 - } 161 - | Push(_) => () 162 - } 163 - }); 164 - })); 165 - 166 - type sampleStateT('a) = { 167 - mutable ended: bool, 168 - mutable value: option('a), 169 - mutable sourceTalkback: (.talkbackT) => unit, 170 - mutable notifierTalkback: (.talkbackT) => unit 171 - }; 172 - 173 - let sample = notifier => curry(source => curry(sink => { 174 - let state = { 175 - ended: false, 176 - value: None, 177 - sourceTalkback: (._: talkbackT) => (), 178 - notifierTalkback: (._: talkbackT) => () 179 - }; 180 - 181 - source((.signal) => { 182 - switch (signal) { 183 - | Start(tb) => state.sourceTalkback = tb 184 - | End => { 185 - state.ended = true; 186 - state.notifierTalkback(.Close); 187 - sink(.End); 188 - } 189 - | Push(x) => state.value = Some(x) 190 - } 191 - }); 192 - 193 - notifier((.signal) => { 194 - switch (signal, state.value) { 195 - | (Start(tb), _) => state.notifierTalkback = tb 196 - | (End, _) => { 197 - state.ended = true; 198 - state.sourceTalkback(.Close); 199 - sink(.End); 200 - } 201 - | (Push(_), Some(x)) when !state.ended => { 202 - state.value = None; 203 - sink(.Push(x)); 204 - } 205 - | (Push(_), _) => () 206 - } 207 - }); 208 - 209 - sink(.Start((.signal) => { 210 - switch (signal) { 211 - | Pull => { 212 - state.sourceTalkback(.Pull); 213 - state.notifierTalkback(.Pull); 214 - } 215 - | Close => { 216 - state.ended = true; 217 - state.sourceTalkback(.Close); 218 - state.notifierTalkback(.Close); 219 - } 220 - } 221 - })); 222 - })); 223 - 224 - type delayStateT = { 225 - mutable talkback: (.talkbackT) => unit, 226 - mutable active: int, 227 - mutable gotEndSignal: bool 228 - }; 229 - 230 - let delay = wait => curry(source => curry(sink => { 231 - let state: delayStateT = { 232 - talkback: Wonka_helpers.talkbackPlaceholder, 233 - active: 0, 234 - gotEndSignal: false 235 - }; 236 - 237 - source((.signal) => { 238 - switch (signal) { 239 - | Start(tb) => state.talkback = tb 240 - | _ when !state.gotEndSignal => { 241 - state.active = state.active + 1; 242 - ignore(Js.Global.setTimeout(() => { 243 - if (state.gotEndSignal && state.active === 0) { 244 - sink(.End); 245 - } else { 246 - state.active = state.active - 1; 247 - }; 248 - 249 - sink(.signal); 250 - }, wait)); 251 - } 252 - | _ => () 253 - } 254 - }); 255 - 256 - sink(.Start((.signal) => { 257 - switch (signal) { 258 - | Close => { 259 - state.gotEndSignal = true; 260 - if (state.active === 0) sink(.End); 261 - } 262 - | _ when !state.gotEndSignal => state.talkback(.signal) 263 - | _ => () 264 - } 265 - })); 266 - })); 267 - 268 - let toPromise = source => 269 - Js.Promise.make((~resolve, ~reject as _) => { 270 - Wonka.takeLast(1, source, (.signal) => { 271 - switch (signal) { 272 - | Start(x) => x(.Pull) 273 - | Push(x) => resolve(.x) 274 - | End => () 275 - } 276 - }); 277 - }); 11 + /* sources */ 12 + include Wonka_source_fromDomEvent; 13 + include Wonka_source_fromListener; 14 + include Wonka_source_fromPromise;
-66
src/web/wonkaJs.rei
··· 1 - open Wonka_types; 2 - 3 - /* -- source factories */ 4 - 5 - /* Accepts an event listening start function and stop function 6 - and creates a listenable source that emits the received events. 7 - This stream will emit values indefinitely until it receives an 8 - End signal from a talkback passed downwards to its sink, which 9 - calls the stop function using the internal handler. 10 - This works well for Dom event listeners, for example the ones 11 - in bs-webapi-incubator: 12 - https://github.com/reasonml-community/bs-webapi-incubator/blob/master/src/dom/events/EventTargetRe.re 13 - */ 14 - let fromListener: 15 - ( 16 - ('event => unit) => unit, 17 - ('event => unit) => unit, 18 - sinkT('event) 19 - ) => 20 - unit; 21 - 22 - /* Accepts a Dom.element type and an event nme and creates a listenable 23 - source that emits values of the Dom.event type. This stream is 24 - created using the fromListener helper and more specific events 25 - should be created using the methods in bs-webapi-incubator: 26 - https://github.com/reasonml-community/bs-webapi-incubator/blob/master/src/dom/events/EventTargetRe.re 27 - */ 28 - let fromDomEvent: (Dom.element, string, sinkT(Dom.event)) => unit; 29 - 30 - /* Accepts a period in milliseconds and creates a listenable source 31 - that emits ascending numbers for each time the interval fires. 32 - This stream will emit values indefinitely until it receives an 33 - End signal from a talkback passed downwards to its sink. */ 34 - let interval: (int, sinkT(int)) => unit; 35 - 36 - /* Accepts a JS promise and creates a listenable source that emits 37 - the promise's value once it resolves. 38 - This stream will wait for the promise's completion, unless it 39 - receives an End signal first. */ 40 - let fromPromise: (Js.Promise.t('a), sinkT('a)) => unit; 41 - 42 - /* -- operators */ 43 - 44 - /* Takes a projection to a period in milliseconds and a source, and creates 45 - a listenable source that emits the last emitted value if no other value 46 - has been emitted during the passed debounce period. */ 47 - let debounce: ((.'a) => int, sourceT('a), sinkT('a)) => unit; 48 - 49 - /* Takes a projection to a period in milliseconds and a source, and creates 50 - a listenable source that ignores values after the last emitted value for 51 - the duration of the returned throttle period. */ 52 - let throttle: ((.'a) => int, sourceT('a), sinkT('a)) => unit; 53 - 54 - /* Takes a notifier source and an input source, and creates a sink & source. 55 - When the notifier emits a value, it will emit the value that it most recently 56 - received from the input source, unless said source hasn't emitted anything 57 - since the last signal. */ 58 - let sample: (sourceT('a), sourceT('b), sinkT('b)) => unit; 59 - 60 - /* Takes a projection to a period in milliseconds and a source, and creates 61 - a listenable source that delays every emission by that passed period. */ 62 - let delay: (int, sourceT('a), sinkT('a)) => unit; 63 - 64 - /* Converts a stream into a promise by resolving to the last value of the 65 - stream. */ 66 - let toPromise: sourceT('a) => Js.Promise.t('a);
+3
src/web/wonka_operator_debounce.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const debounce: <A>(f: (x: A) => number) => Operator<A, A>;
+47
src/web/wonka_operator_debounce.re
··· 1 + open Wonka_types; 2 + 3 + let debounce = f => curry(source => curry(sink => { 4 + let gotEndSignal = ref(false); 5 + let id: ref(option(Js.Global.timeoutId)) = ref(None); 6 + 7 + let clearTimeout = () => 8 + switch (id^) { 9 + | Some(timeoutId) => { 10 + id := None; 11 + Js.Global.clearTimeout(timeoutId); 12 + } 13 + | None => () 14 + }; 15 + 16 + source((.signal) => { 17 + switch (signal) { 18 + | Start(tb) => { 19 + sink(.Start((.signal) => { 20 + switch (signal) { 21 + | Close => { 22 + clearTimeout(); 23 + tb(.Close); 24 + } 25 + | _ => tb(.signal) 26 + } 27 + })); 28 + } 29 + | Push(x) => { 30 + clearTimeout(); 31 + id := Some(Js.Global.setTimeout(() => { 32 + id := None; 33 + sink(.signal); 34 + if (gotEndSignal^) sink(.End); 35 + }, f(.x))); 36 + } 37 + | End => { 38 + gotEndSignal := true; 39 + 40 + switch (id^) { 41 + | None => sink(.End) 42 + | _ => () 43 + }; 44 + } 45 + } 46 + }); 47 + }));
+3
src/web/wonka_operator_debounce.rei
··· 1 + open Wonka_types; 2 + 3 + let debounce: ((.'a) => int, sourceT('a), sinkT('a)) => unit;
+3
src/web/wonka_operator_delay.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const delay: <A>(duration: number) => Operator<A, A>;
+45
src/web/wonka_operator_delay.re
··· 1 + open Wonka_types; 2 + 3 + type delayStateT = { 4 + mutable talkback: (.talkbackT) => unit, 5 + mutable active: int, 6 + mutable gotEndSignal: bool 7 + }; 8 + 9 + let delay = wait => curry(source => curry(sink => { 10 + let state: delayStateT = { 11 + talkback: Wonka_helpers.talkbackPlaceholder, 12 + active: 0, 13 + gotEndSignal: false 14 + }; 15 + 16 + source((.signal) => { 17 + switch (signal) { 18 + | Start(tb) => state.talkback = tb 19 + | _ when !state.gotEndSignal => { 20 + state.active = state.active + 1; 21 + ignore(Js.Global.setTimeout(() => { 22 + if (state.gotEndSignal && state.active === 0) { 23 + sink(.End); 24 + } else { 25 + state.active = state.active - 1; 26 + }; 27 + 28 + sink(.signal); 29 + }, wait)); 30 + } 31 + | _ => () 32 + } 33 + }); 34 + 35 + sink(.Start((.signal) => { 36 + switch (signal) { 37 + | Close => { 38 + state.gotEndSignal = true; 39 + if (state.active === 0) sink(.End); 40 + } 41 + | _ when !state.gotEndSignal => state.talkback(.signal) 42 + | _ => () 43 + } 44 + })); 45 + }));
+3
src/web/wonka_operator_delay.rei
··· 1 + open Wonka_types; 2 + 3 + let delay: (int, sourceT('a), sinkT('a)) => unit;
+3
src/web/wonka_operator_interval.d.ts
··· 1 + import { Source } from '../wonka_types'; 2 + 3 + export const interval: (interval: number) => Source<number>;
+17
src/web/wonka_operator_interval.re
··· 1 + open Wonka_types; 2 + 3 + let interval = p => curry(sink => { 4 + let i = ref(0); 5 + let id = Js.Global.setInterval(() => { 6 + let num = i^; 7 + i := i^ + 1; 8 + sink(.Push(num)); 9 + }, p); 10 + 11 + sink(.Start((.signal) => { 12 + switch (signal) { 13 + | Close => Js.Global.clearInterval(id) 14 + | _ => () 15 + } 16 + })); 17 + });
+3
src/web/wonka_operator_interval.rei
··· 1 + open Wonka_types; 2 + 3 + let interval: (int, sinkT(int)) => unit;
+3
src/web/wonka_operator_sample.d.ts
··· 1 + import { Source, Operator } from '../wonka_types'; 2 + 3 + export const sample: <A>(signal: Source<any>) => Operator<A, A>;
+59
src/web/wonka_operator_sample.re
··· 1 + open Wonka_types; 2 + 3 + type sampleStateT('a) = { 4 + mutable ended: bool, 5 + mutable value: option('a), 6 + mutable sourceTalkback: (.talkbackT) => unit, 7 + mutable notifierTalkback: (.talkbackT) => unit 8 + }; 9 + 10 + let sample = notifier => curry(source => curry(sink => { 11 + let state = { 12 + ended: false, 13 + value: None, 14 + sourceTalkback: (._: talkbackT) => (), 15 + notifierTalkback: (._: talkbackT) => () 16 + }; 17 + 18 + source((.signal) => { 19 + switch (signal) { 20 + | Start(tb) => state.sourceTalkback = tb 21 + | End => { 22 + state.ended = true; 23 + state.notifierTalkback(.Close); 24 + sink(.End); 25 + } 26 + | Push(x) => state.value = Some(x) 27 + } 28 + }); 29 + 30 + notifier((.signal) => { 31 + switch (signal, state.value) { 32 + | (Start(tb), _) => state.notifierTalkback = tb 33 + | (End, _) => { 34 + state.ended = true; 35 + state.sourceTalkback(.Close); 36 + sink(.End); 37 + } 38 + | (Push(_), Some(x)) when !state.ended => { 39 + state.value = None; 40 + sink(.Push(x)); 41 + } 42 + | (Push(_), _) => () 43 + } 44 + }); 45 + 46 + sink(.Start((.signal) => { 47 + switch (signal) { 48 + | Pull => { 49 + state.sourceTalkback(.Pull); 50 + state.notifierTalkback(.Pull); 51 + } 52 + | Close => { 53 + state.ended = true; 54 + state.sourceTalkback(.Close); 55 + state.notifierTalkback(.Close); 56 + } 57 + } 58 + })); 59 + }));
+3
src/web/wonka_operator_sample.rei
··· 1 + open Wonka_types; 2 + 3 + let sample: (sourceT('a), sourceT('b), sinkT('b)) => unit;
+3
src/web/wonka_operator_throttle.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const throttle: <A>(f: (x: A) => number) => Operator<A, A>;
+41
src/web/wonka_operator_throttle.re
··· 1 + open Wonka_types; 2 + 3 + let throttle = f => curry(source => curry(sink => { 4 + let skip = ref(false); 5 + let id: ref(option(Js.Global.timeoutId)) = ref(None); 6 + let clearTimeout = () => 7 + switch (id^) { 8 + | Some(timeoutId) => Js.Global.clearTimeout(timeoutId); 9 + | None => () 10 + }; 11 + 12 + source((.signal) => { 13 + switch (signal) { 14 + | Start(tb) => { 15 + sink(.Start((.signal) => { 16 + switch (signal) { 17 + | Close => { 18 + clearTimeout(); 19 + tb(.Close); 20 + } 21 + | _ => tb(.signal) 22 + } 23 + })); 24 + } 25 + | End => { 26 + clearTimeout(); 27 + sink(.End); 28 + } 29 + | Push(x) when !skip^ => { 30 + skip := true; 31 + clearTimeout(); 32 + id := Some(Js.Global.setTimeout(() => { 33 + id := None; 34 + skip := false; 35 + }, f(.x))); 36 + sink(.signal); 37 + } 38 + | Push(_) => () 39 + } 40 + }); 41 + }));
+3
src/web/wonka_operator_throttle.rei
··· 1 + open Wonka_types; 2 + 3 + let throttle: ((.'a) => int, sourceT('a), sinkT('a)) => unit;
+3
src/web/wonka_sink_toPromise.d.ts
··· 1 + import { Source } from '../wonka_types'; 2 + 3 + export const toPromise: <A>(source: Source<A>) => Promise<A>;
+12
src/web/wonka_sink_toPromise.re
··· 1 + open Wonka_types; 2 + 3 + let toPromise = source => 4 + Js.Promise.make((~resolve, ~reject as _) => { 5 + Wonka.takeLast(1, source, (.signal) => { 6 + switch (signal) { 7 + | Start(x) => x(.Pull) 8 + | Push(x) => resolve(.x) 9 + | End => () 10 + } 11 + }); 12 + });
+3
src/web/wonka_sink_toPromise.rei
··· 1 + open Wonka_types; 2 + 3 + let toPromise: sourceT('a) => Js.Promise.t('a);
+3
src/web/wonka_source_fromDomEvent.d.ts
··· 1 + import { Source } from '../wonka_types'; 2 + 3 + export const fromDomEvent: <E>(HTMLElement, string) => Source<E>;
+30
src/web/wonka_source_fromDomEvent.re
··· 1 + open Wonka_types; 2 + open Wonka_source_fromListener; 3 + 4 + let fromDomEvent = (element, event) => curry(sink => { 5 + let addEventListener: ( 6 + Dom.element, 7 + string, 8 + (Dom.event) => unit 9 + ) => unit = [%raw {| 10 + function (element, event, handler) { 11 + element.addEventListener(event, handler); 12 + } 13 + |}]; 14 + 15 + let removeEventListener: ( 16 + Dom.element, 17 + string, 18 + (Dom.event) => unit 19 + ) => unit = [%raw {| 20 + function (element, event, handler) { 21 + element.removeEventListener(event, handler); 22 + } 23 + |}]; 24 + 25 + fromListener( 26 + handler => addEventListener(element, event, handler), 27 + handler => removeEventListener(element, event, handler), 28 + sink 29 + ) 30 + });
+3
src/web/wonka_source_fromDomEvent.rei
··· 1 + open Wonka_types; 2 + 3 + let fromDomEvent: (Dom.element, string, sinkT(Dom.event)) => unit;
+6
src/web/wonka_source_fromListener.d.ts
··· 1 + import { Source } from '../wonka_types'; 2 + 3 + export const fromListener: <E>( 4 + addListener: (cb: (event: E) => void) => void, 5 + removeListener: (cb: (event: E) => void) => void 6 + ) => Source<E>;
+14
src/web/wonka_source_fromListener.re
··· 1 + open Wonka_types; 2 + 3 + let fromListener = (addListener, removeListener) => curry(sink => { 4 + let handler = event => sink(.Push(event)); 5 + 6 + sink(.Start((.signal) => { 7 + switch (signal) { 8 + | Close => removeListener(handler) 9 + | _ => () 10 + } 11 + })); 12 + 13 + addListener(handler); 14 + });
+8
src/web/wonka_source_fromListener.rei
··· 1 + open Wonka_types; 2 + 3 + let fromListener: 4 + ( 5 + ('event => unit) => unit, 6 + ('event => unit) => unit, 7 + sinkT('event) 8 + ) => unit;
+3
src/web/wonka_source_fromPromise.d.ts
··· 1 + import { Operator } from '../wonka_types'; 2 + 3 + export const fromPromise: <A>(promise: Promise<A>) => Source<A>;
+21
src/web/wonka_source_fromPromise.re
··· 1 + open Wonka_types; 2 + 3 + let fromPromise = promise => curry(sink => { 4 + let ended = ref(false); 5 + 6 + ignore(Js.Promise.then_(value => { 7 + if (!ended^) { 8 + sink(.Push(value)); 9 + sink(.End); 10 + }; 11 + 12 + Js.Promise.resolve(()) 13 + }, promise)); 14 + 15 + sink(.Start((.signal) => { 16 + switch (signal) { 17 + | Close => ended := true 18 + | _ => () 19 + } 20 + })); 21 + });
+3
src/web/wonka_source_fromPromise.rei
··· 1 + open Wonka_types; 2 + 3 + let fromPromise: (Js.Promise.t('a), sinkT('a)) => unit;
+27 -38
src/wonka.d.ts
··· 1 - import { List, Sink, Source, Subscription, Operator, Observer, Subject } from './wonka_types'; 1 + /* sources */ 2 + export * from './sources/wonka_source_fromArray'; 3 + export * from './sources/wonka_source_fromList'; 4 + export * from './sources/wonka_source_fromValue'; 5 + export * from './sources/wonka_source_make'; 6 + export * from './sources/wonka_source_makeSubject'; 7 + export * from './sources/wonka_source_primitives'; 2 8 3 - export const makeSubject: <A>() => Subject<A>; 9 + /* operators */ 10 + export * from './operators/wonka_operator_combine'; 11 + export * from './operators/wonka_operator_concatMap'; 12 + export * from './operators/wonka_operator_filter'; 13 + export * from './operators/wonka_operator_map'; 14 + export * from './operators/wonka_operator_mergeMap'; 15 + export * from './operators/wonka_operator_scan'; 16 + export * from './operators/wonka_operator_share'; 17 + export * from './operators/wonka_operator_skip'; 18 + export * from './operators/wonka_operator_skipUntil'; 19 + export * from './operators/wonka_operator_skipWhile'; 20 + export * from './operators/wonka_operator_switchMap'; 21 + export * from './operators/wonka_operator_take'; 22 + export * from './operators/wonka_operator_takeLast'; 23 + export * from './operators/wonka_operator_takeUntil'; 24 + export * from './operators/wonka_operator_takeWhile'; 25 + export * from './operators/wonka_operator_tap'; 4 26 5 - export const make: <A>(f: (observer: Observer<A>) => (() => void)) => Source<A>; 6 - export const fromList: <A>(list: List<A>) => Source<A>; 7 - export const fromArray: <A>(array: A[]) => Source<A>; 8 - export const fromValue: <A>(value: A) => Source<A>; 9 - export const empty: Source<{}>; 10 - export const never: Source<{}>; 11 - 12 - export const tap: <A>(f: (value: A) => void) => Operator<A, A>; 13 - export const map: <A, B>(f: (value: A) => B) => Operator<A, B>; 14 - export const filter: <A>(f: (value: A) => boolean) => Operator<A, A>; 15 - export const scan: <A, B>(f: (acc: B, value: A) => B, acc: B) => Operator<A, B>; 16 - 17 - export const mergeMap: <A, B>(f: (value: A) => Source<B>) => Operator<A, B>; 18 - export const switchMap: <A, B>(f: (value: A) => Source<B>) => Operator<A, B>; 19 - export const concatMap: <A, B>(f: (value: A) => Source<B>) => Operator<A, B>; 20 - 21 - export const merge: <A>(sources: Array<Source<A>>) => Source<A>; 22 - export const concat: <A>(sources: Array<Source<A>>) => Source<A>; 23 - export const share: <A>(source: Source<A>) => Source<A>; 24 - export const combine: <A, B>(a: Source<A>, b: Source<B>) => Source<[A, B]>; 25 - 26 - export const concatAll: <A>(source: Source<Source<A>>) => Source<A>; 27 - export const mergeAll: <A>(source: Source<Source<A>>) => Source<A>; 28 - export const flatten: <A>(source: Source<Source<A>>) => Source<A>; 29 - 30 - export const take: <A>(max: number) => Operator<A, A>; 31 - export const takeLast: <A>(max: number) => Operator<A, A>; 32 - export const takeWhile: <A>(f: (x: A) => boolean) => Operator<A, A>; 33 - export const takeUntil: <A>(signal: Source<any>) => Operator<A, A>; 34 - export const skip: <A>(max: number) => Operator<A, A>; 35 - export const skipWhile: <A>(f: (x: A) => boolean) => Operator<A, A>; 36 - export const skipUntil: <A>(signal: Source<any>) => Operator<A, A>; 37 - 38 - export const publish: <A>(source: Source<A>) => Subscription; 39 - export const forEach: <A>(f: (x: A) => void) => (source: Source<A>) => void; 40 - export const subscribe: <A>(f: (x: A) => void) => (source: Source<A>) => Subscription; 27 + /* sinks */ 28 + export * from './sinks/wonka_sink_publish'; 29 + export * from './sinks/wonka_sink_subscribe';
+37
src/wonka.ml
··· 1 + module Types = Wonka_types 2 + 3 + (* sources *) 4 + include Wonka_source_fromArray 5 + include Wonka_source_fromList 6 + include Wonka_source_fromValue 7 + include Wonka_source_make 8 + include Wonka_source_makeSubject 9 + include Wonka_source_primitives 10 + 11 + (* operators *) 12 + include Wonka_operator_combine 13 + include Wonka_operator_concatMap 14 + include Wonka_operator_filter 15 + include Wonka_operator_map 16 + include Wonka_operator_mergeMap 17 + include Wonka_operator_scan 18 + include Wonka_operator_share 19 + include Wonka_operator_skip 20 + include Wonka_operator_skipUntil 21 + include Wonka_operator_skipWhile 22 + include Wonka_operator_switchMap 23 + include Wonka_operator_take 24 + include Wonka_operator_takeLast 25 + include Wonka_operator_takeUntil 26 + include Wonka_operator_takeWhile 27 + include Wonka_operator_tap 28 + 29 + (* sinks *) 30 + include Wonka_sink_publish 31 + include Wonka_sink_subscribe 32 + 33 + #if BS_NATIVE then 34 + #if BSB_BACKEND = "js" then 35 + include WonkaJs 36 + #end 37 + #end
-913
src/wonka.re
··· 1 - open Wonka_types; 2 - open Wonka_helpers; 3 - 4 - module Types = Wonka_types; 5 - 6 - type subjectState('a) = { 7 - mutable sinks: Rebel.Array.t(sinkT('a)), 8 - mutable ended: bool 9 - }; 10 - 11 - let makeSubject = () => { 12 - let state: subjectState('a) = { 13 - sinks: Rebel.Array.makeEmpty(), 14 - ended: false, 15 - }; 16 - 17 - let source = sink => { 18 - state.sinks = Rebel.Array.append(state.sinks, sink); 19 - sink(.Start((.signal) => { 20 - if (signal === Close) { 21 - state.sinks = Rebel.Array.filter(state.sinks, x => x !== sink); 22 - } 23 - })); 24 - }; 25 - 26 - let next = value => 27 - if (!state.ended) { 28 - Rebel.Array.forEach(state.sinks, sink => sink(.Push(value))); 29 - }; 30 - 31 - let complete = () => 32 - if (!state.ended) { 33 - state.ended = true; 34 - Rebel.Array.forEach(state.sinks, sink => sink(.End)); 35 - }; 36 - 37 - { source, next, complete } 38 - }; 39 - 40 - let make = f => curry(sink => { 41 - let teardown = f(.{ 42 - next: value => sink(.Push(value)), 43 - complete: () => sink(.End) 44 - }); 45 - 46 - sink(.Start((.signal) => { 47 - switch (signal) { 48 - | Close => teardown(.) 49 - | Pull => () 50 - } 51 - })); 52 - }); 53 - 54 - type fromListState('a) = { 55 - mutable value: 'a, 56 - mutable ended: bool, 57 - mutable looping: bool, 58 - mutable pull: bool 59 - }; 60 - 61 - let fromList = ls => curry(sink => { 62 - let state = { 63 - value: ls, 64 - ended: false, 65 - looping: false, 66 - pull: false 67 - }; 68 - 69 - sink(.Start((.signal) => { 70 - switch (signal, state.looping) { 71 - | (Pull, false) => { 72 - state.pull = true; 73 - state.looping = true; 74 - 75 - while (state.pull && !state.ended) { 76 - switch (state.value) { 77 - | [x, ...rest] => { 78 - state.value = rest; 79 - state.pull = false; 80 - sink(.Push(x)); 81 - } 82 - | [] => { 83 - state.ended = true; 84 - sink(.End); 85 - } 86 - } 87 - }; 88 - 89 - state.looping = false; 90 - } 91 - | (Pull, true) => state.pull = true 92 - | (Close, _) => state.ended = true 93 - } 94 - })); 95 - }); 96 - 97 - type fromArrayState('a) = { 98 - mutable index: int, 99 - mutable ended: bool, 100 - mutable looping: bool, 101 - mutable pull: bool 102 - }; 103 - 104 - let fromArray = arr => curry(sink => { 105 - let size = Rebel.Array.size(arr); 106 - let state = { 107 - index: 0, 108 - ended: false, 109 - looping: false, 110 - pull: false 111 - }; 112 - 113 - sink(.Start((.signal) => { 114 - switch (signal, state.looping) { 115 - | (Pull, false) => { 116 - state.pull = true; 117 - state.looping = true; 118 - 119 - while (state.pull && !state.ended) { 120 - let index = state.index; 121 - if (index < size) { 122 - let x = Rebel.Array.getUnsafe(arr, index); 123 - state.index = index + 1; 124 - state.pull = false; 125 - sink(.Push(x)); 126 - } else { 127 - state.ended = true; 128 - sink(.End); 129 - } 130 - }; 131 - 132 - state.looping = false; 133 - } 134 - | (Pull, true) => state.pull = true 135 - | (Close, _) => state.ended = true 136 - } 137 - })); 138 - }); 139 - 140 - let fromValue = x => curry(sink => { 141 - let ended = ref(false); 142 - 143 - sink(.Start((.signal) => { 144 - switch (signal) { 145 - | Pull when !ended^ => { 146 - ended := true; 147 - sink(.Push(x)); 148 - sink(.End); 149 - } 150 - | _ => () 151 - } 152 - })); 153 - }); 154 - 155 - let empty = sink => { 156 - sink(.Start(talkbackPlaceholder)); 157 - sink(.End); 158 - }; 159 - 160 - let never = sink => { 161 - sink(.Start(talkbackPlaceholder)); 162 - }; 163 - 164 - let tap = f => curry(source => curry(sink => { 165 - source((.signal) => { 166 - switch (signal) { 167 - | Push(x) => f(.x) 168 - | _ => () 169 - }; 170 - 171 - sink(.signal); 172 - }); 173 - })); 174 - 175 - let map = f => curry(source => curry(sink => { 176 - source((.signal) => sink(. 177 - switch (signal) { 178 - | Start(x) => Start(x) 179 - | Push(x) => Push(f(.x)) 180 - | End => End 181 - } 182 - )); 183 - })); 184 - 185 - let filter = f => curry(source => curry(sink => { 186 - captureTalkback(source, (.signal, talkback) => { 187 - switch (signal) { 188 - | Push(x) when !f(.x) => talkback(.Pull) 189 - | _ => sink(.signal) 190 - } 191 - }); 192 - })); 193 - 194 - let scan = (f, seed) => curry(source => curry(sink => { 195 - let acc = ref(seed); 196 - 197 - source((.signal) => sink(. 198 - switch (signal) { 199 - | Push(x) => { 200 - acc := f(acc^, x); 201 - Push(acc^) 202 - } 203 - | Start(x) => Start(x) 204 - | End => End 205 - } 206 - )); 207 - })); 208 - 209 - type mergeMapStateT = { 210 - mutable outerTalkback: (.talkbackT) => unit, 211 - mutable innerTalkbacks: Rebel.Array.t((.talkbackT) => unit), 212 - mutable ended: bool 213 - }; 214 - 215 - let mergeMap = f => curry(source => curry(sink => { 216 - let state: mergeMapStateT = { 217 - outerTalkback: talkbackPlaceholder, 218 - innerTalkbacks: Rebel.Array.makeEmpty(), 219 - ended: false 220 - }; 221 - 222 - let applyInnerSource = innerSource => { 223 - let talkback = ref(talkbackPlaceholder); 224 - 225 - innerSource((.signal) => { 226 - switch (signal) { 227 - | End => { 228 - state.innerTalkbacks = Rebel.Array.filter(state.innerTalkbacks, x => x !== talkback^); 229 - if (state.ended && Rebel.Array.size(state.innerTalkbacks) === 0) { 230 - sink(.End); 231 - } 232 - } 233 - | Start(tb) => { 234 - talkback := tb; 235 - state.innerTalkbacks = Rebel.Array.append(state.innerTalkbacks, tb); 236 - tb(.Pull); 237 - } 238 - | Push(x) when Rebel.Array.size(state.innerTalkbacks) !== 0 => { 239 - sink(.Push(x)); 240 - talkback^(.Pull); 241 - } 242 - | Push(_) => () 243 - } 244 - }); 245 - }; 246 - 247 - source((.signal) => { 248 - switch (signal) { 249 - | End when !state.ended => { 250 - state.ended = true; 251 - if (Rebel.Array.size(state.innerTalkbacks) === 0) { 252 - sink(.End); 253 - } 254 - } 255 - | End => () 256 - | Start(tb) => { 257 - state.outerTalkback = tb; 258 - tb(.Pull); 259 - } 260 - | Push(x) when !state.ended => { 261 - applyInnerSource(f(.x)); 262 - state.outerTalkback(.Pull); 263 - } 264 - | Push(_) => () 265 - } 266 - }); 267 - 268 - sink(.Start((.signal) => { 269 - switch (signal) { 270 - | Close when !state.ended => { 271 - state.ended = true; 272 - state.outerTalkback(.Close); 273 - Rebel.Array.forEach(state.innerTalkbacks, talkback => talkback(.Close)); 274 - state.innerTalkbacks = Rebel.Array.makeEmpty(); 275 - } 276 - | Close => () 277 - | Pull when !state.ended => 278 - Rebel.Array.forEach(state.innerTalkbacks, talkback => talkback(.Pull)); 279 - | Pull => () 280 - } 281 - })); 282 - })); 283 - 284 - let merge = sources => mergeMap((.x) => x, fromArray(sources)); 285 - let mergeAll = source => mergeMap((.x) => x, source); 286 - let flatten = mergeAll; 287 - 288 - type concatMapStateT('a) = { 289 - inputQueue: Rebel.MutableQueue.t('a), 290 - mutable outerTalkback: (.talkbackT) => unit, 291 - mutable innerTalkback: (.talkbackT) => unit, 292 - mutable innerActive: bool, 293 - mutable closed: bool, 294 - mutable ended: bool 295 - }; 296 - 297 - let concatMap = f => curry(source => curry(sink => { 298 - let state: concatMapStateT('a) = { 299 - inputQueue: Rebel.MutableQueue.make(), 300 - outerTalkback: talkbackPlaceholder, 301 - innerTalkback: talkbackPlaceholder, 302 - innerActive: false, 303 - closed: false, 304 - ended: false 305 - }; 306 - 307 - let rec applyInnerSource = innerSource => 308 - innerSource((.signal) => { 309 - switch (signal) { 310 - | End => { 311 - state.innerActive = false; 312 - state.innerTalkback = talkbackPlaceholder; 313 - 314 - switch (Rebel.MutableQueue.pop(state.inputQueue)) { 315 - | Some(input) => applyInnerSource(f(.input)) 316 - | None when state.ended => sink(.End) 317 - | None => () 318 - }; 319 - } 320 - | Start(tb) => { 321 - state.innerActive = true; 322 - state.innerTalkback = tb; 323 - tb(.Pull); 324 - } 325 - | Push(x) when !state.closed => { 326 - sink(.Push(x)); 327 - state.innerTalkback(.Pull); 328 - } 329 - | Push(_) => () 330 - } 331 - }); 332 - 333 - source((.signal) => { 334 - switch (signal) { 335 - | End when !state.ended => { 336 - state.ended = true; 337 - if (!state.innerActive && Rebel.MutableQueue.isEmpty(state.inputQueue)) { 338 - sink(.End); 339 - } 340 - } 341 - | End => () 342 - | Start(tb) => { 343 - state.outerTalkback = tb; 344 - tb(.Pull); 345 - } 346 - | Push(x) when !state.ended => { 347 - if (state.innerActive) { 348 - Rebel.MutableQueue.add(state.inputQueue, x); 349 - } else { 350 - applyInnerSource(f(.x)); 351 - } 352 - 353 - state.outerTalkback(.Pull); 354 - } 355 - | Push(_) => () 356 - } 357 - }); 358 - 359 - sink(.Start((.signal) => { 360 - switch (signal) { 361 - | Pull => if (!state.ended) state.innerTalkback(.Pull) 362 - | Close when !state.ended => { 363 - state.ended = true; 364 - state.closed = true; 365 - state.outerTalkback(.Close); 366 - state.innerTalkback(.Close); 367 - } 368 - | Close => () 369 - } 370 - })); 371 - })); 372 - 373 - let concatAll = source => concatMap((.x) => x, source); 374 - let concat = sources => concatMap((.x) => x, fromArray(sources)); 375 - 376 - type switchMapStateT('a) = { 377 - mutable outerTalkback: (.talkbackT) => unit, 378 - mutable innerTalkback: (.talkbackT) => unit, 379 - mutable innerActive: bool, 380 - mutable closed: bool, 381 - mutable ended: bool 382 - }; 383 - 384 - let switchMap = f => curry(source => curry(sink => { 385 - let state: switchMapStateT('a) = { 386 - outerTalkback: talkbackPlaceholder, 387 - innerTalkback: talkbackPlaceholder, 388 - innerActive: false, 389 - closed: false, 390 - ended: false 391 - }; 392 - 393 - let applyInnerSource = innerSource => 394 - innerSource((.signal) => { 395 - switch (signal) { 396 - | End => { 397 - state.innerActive = false; 398 - state.innerTalkback = talkbackPlaceholder; 399 - if (state.ended) sink(.End); 400 - } 401 - | Start(tb) => { 402 - state.innerActive = true; 403 - state.innerTalkback = tb; 404 - tb(.Pull); 405 - } 406 - | Push(x) when !state.closed => { 407 - sink(.Push(x)); 408 - state.innerTalkback(.Pull); 409 - } 410 - | Push(_) => () 411 - } 412 - }); 413 - 414 - source((.signal) => { 415 - switch (signal) { 416 - | End when !state.ended => { 417 - state.ended = true; 418 - if (!state.innerActive) sink(.End); 419 - } 420 - | End => () 421 - | Start(tb) => { 422 - state.outerTalkback = tb; 423 - tb(.Pull); 424 - } 425 - | Push(x) when !state.ended => { 426 - if (state.innerActive) { 427 - state.innerTalkback(.Close); 428 - state.innerTalkback = talkbackPlaceholder; 429 - } 430 - applyInnerSource(f(.x)); 431 - state.outerTalkback(.Pull); 432 - } 433 - | Push(_) => () 434 - } 435 - }); 436 - 437 - sink(.Start((.signal) => { 438 - switch (signal) { 439 - | Pull => state.innerTalkback(.Pull) 440 - | Close when !state.ended => { 441 - state.ended = true; 442 - state.closed = true; 443 - state.outerTalkback(.Close); 444 - state.innerTalkback(.Close); 445 - state.innerTalkback = talkbackPlaceholder; 446 - } 447 - | Close => () 448 - } 449 - })); 450 - })); 451 - 452 - type shareStateT('a) = { 453 - mutable sinks: Rebel.Array.t(sinkT('a)), 454 - mutable talkback: (.talkbackT) => unit, 455 - mutable gotSignal: bool 456 - }; 457 - 458 - let share = source => { 459 - let state = { 460 - sinks: Rebel.Array.makeEmpty(), 461 - talkback: talkbackPlaceholder, 462 - gotSignal: false 463 - }; 464 - 465 - sink => { 466 - state.sinks = Rebel.Array.append(state.sinks, sink); 467 - 468 - if (Rebel.Array.size(state.sinks) === 1) { 469 - source((.signal) => { 470 - switch (signal) { 471 - | Push(_) => { 472 - state.gotSignal = false; 473 - Rebel.Array.forEach(state.sinks, sink => sink(.signal)); 474 - } 475 - | Start(x) => state.talkback = x 476 - | End => { 477 - Rebel.Array.forEach(state.sinks, sink => sink(.End)); 478 - state.sinks = Rebel.Array.makeEmpty(); 479 - } 480 - } 481 - }); 482 - }; 483 - 484 - sink(.Start((.signal) => { 485 - switch (signal) { 486 - | Close => { 487 - state.sinks = Rebel.Array.filter(state.sinks, x => x !== sink); 488 - if (Rebel.Array.size(state.sinks) === 0) { 489 - state.talkback(.Close); 490 - }; 491 - } 492 - | Pull when !state.gotSignal => { 493 - state.gotSignal = true; 494 - state.talkback(.signal); 495 - } 496 - | Pull => () 497 - } 498 - })); 499 - } 500 - }; 501 - 502 - type combineStateT('a, 'b) = { 503 - mutable talkbackA: (.talkbackT) => unit, 504 - mutable talkbackB: (.talkbackT) => unit, 505 - mutable lastValA: option('a), 506 - mutable lastValB: option('b), 507 - mutable gotSignal: bool, 508 - mutable endCounter: int, 509 - mutable ended: bool, 510 - }; 511 - 512 - let combine = (sourceA, sourceB) => curry(sink => { 513 - let state = { 514 - talkbackA: talkbackPlaceholder, 515 - talkbackB: talkbackPlaceholder, 516 - lastValA: None, 517 - lastValB: None, 518 - gotSignal: false, 519 - endCounter: 0, 520 - ended: false 521 - }; 522 - 523 - sourceA((.signal) => { 524 - switch (signal, state.lastValB) { 525 - | (Start(tb), _) => state.talkbackA = tb 526 - | (Push(a), None) => { 527 - state.lastValA = Some(a); 528 - state.gotSignal = false; 529 - } 530 - | (Push(a), Some(b)) when !state.ended => { 531 - state.lastValA = Some(a); 532 - state.gotSignal = false; 533 - sink(.Push((a, b))); 534 - } 535 - | (End, _) when state.endCounter < 1 => 536 - state.endCounter = state.endCounter + 1 537 - | (End, _) when !state.ended => { 538 - state.ended = true; 539 - sink(.End); 540 - } 541 - | _ => () 542 - } 543 - }); 544 - 545 - sourceB((.signal) => { 546 - switch (signal, state.lastValA) { 547 - | (Start(tb), _) => state.talkbackB = tb 548 - | (Push(b), None) => { 549 - state.lastValB = Some(b); 550 - state.gotSignal = false; 551 - } 552 - | (Push(b), Some(a)) when !state.ended => { 553 - state.lastValB = Some(b); 554 - state.gotSignal = false; 555 - sink(.Push((a, b))); 556 - } 557 - | (End, _) when state.endCounter < 1 => 558 - state.endCounter = state.endCounter + 1 559 - | (End, _) when !state.ended => { 560 - state.ended = true; 561 - sink(.End); 562 - } 563 - | _ => () 564 - } 565 - }); 566 - 567 - sink(.Start((.signal) => { 568 - if (!state.ended) { 569 - switch (signal) { 570 - | Close => { 571 - state.ended = true; 572 - state.talkbackA(.Close); 573 - state.talkbackB(.Close); 574 - } 575 - | Pull when !state.gotSignal => { 576 - state.gotSignal = true; 577 - state.talkbackA(.signal); 578 - state.talkbackB(.signal); 579 - } 580 - | Pull => () 581 - } 582 - }; 583 - })); 584 - }); 585 - 586 - type takeStateT = { 587 - mutable taken: int, 588 - mutable talkback: (.talkbackT) => unit 589 - }; 590 - 591 - let take = max => curry(source => curry(sink => { 592 - let state: takeStateT = { 593 - taken: 0, 594 - talkback: talkbackPlaceholder 595 - }; 596 - 597 - source((.signal) => { 598 - switch (signal) { 599 - | Start(tb) => state.talkback = tb; 600 - | Push(_) when state.taken < max => { 601 - state.taken = state.taken + 1; 602 - sink(.signal); 603 - 604 - if (state.taken === max) { 605 - sink(.End); 606 - state.talkback(.Close); 607 - }; 608 - } 609 - | Push(_) => () 610 - | End when state.taken < max => { 611 - state.taken = max; 612 - sink(.End) 613 - } 614 - | End => () 615 - } 616 - }); 617 - 618 - sink(.Start((.signal) => { 619 - if (state.taken < max) { 620 - switch (signal) { 621 - | Pull => state.talkback(.Pull); 622 - | Close => { 623 - state.taken = max; 624 - state.talkback(.Close); 625 - } 626 - } 627 - }; 628 - })); 629 - })); 630 - 631 - let takeLast = max => curry(source => curry(sink => { 632 - open Rebel; 633 - let queue = MutableQueue.make(); 634 - 635 - captureTalkback(source, (.signal, talkback) => { 636 - switch (signal) { 637 - | Start(_) => talkback(.Pull) 638 - | Push(x) => { 639 - let size = MutableQueue.size(queue); 640 - if (size >= max && max > 0) { 641 - ignore(MutableQueue.pop(queue)); 642 - }; 643 - 644 - MutableQueue.add(queue, x); 645 - talkback(.Pull); 646 - } 647 - | End => makeTrampoline(sink, (.) => MutableQueue.pop(queue)) 648 - } 649 - }); 650 - })); 651 - 652 - let takeWhile = f => curry(source => curry(sink => { 653 - let ended = ref(false); 654 - let talkback = ref(talkbackPlaceholder); 655 - 656 - source((.signal) => { 657 - switch (signal) { 658 - | Start(tb) => { 659 - talkback := tb; 660 - sink(.signal); 661 - } 662 - | End when !ended^ => { 663 - ended := true; 664 - sink(.End); 665 - } 666 - | End => () 667 - | Push(x) when !ended^ => { 668 - if (!f(.x)) { 669 - ended := true; 670 - sink(.End); 671 - talkback^(.Close); 672 - } else { 673 - sink(.signal); 674 - }; 675 - } 676 - | Push(_) => () 677 - } 678 - }); 679 - 680 - sink(.Start((.signal) => { 681 - if (!ended^) { 682 - switch (signal) { 683 - | Pull => talkback^(.Pull); 684 - | Close => { 685 - ended := true; 686 - talkback^(.Close); 687 - } 688 - } 689 - }; 690 - })); 691 - })); 692 - 693 - type takeUntilStateT = { 694 - mutable ended: bool, 695 - mutable sourceTalkback: (.talkbackT) => unit, 696 - mutable notifierTalkback: (.talkbackT) => unit 697 - }; 698 - 699 - let takeUntil = notifier => curry(source => curry(sink => { 700 - let state: takeUntilStateT = { 701 - ended: false, 702 - sourceTalkback: talkbackPlaceholder, 703 - notifierTalkback: talkbackPlaceholder 704 - }; 705 - 706 - source((.signal) => { 707 - switch (signal) { 708 - | Start(tb) => { 709 - state.sourceTalkback = tb; 710 - 711 - notifier((.signal) => { 712 - switch (signal) { 713 - | Start(innerTb) => { 714 - state.notifierTalkback = innerTb; 715 - innerTb(.Pull); 716 - } 717 - | Push(_) => { 718 - state.ended = true; 719 - state.notifierTalkback(.Close); 720 - state.sourceTalkback(.Close); 721 - sink(.End); 722 - } 723 - | End => () 724 - } 725 - }); 726 - } 727 - | End when !state.ended => { 728 - state.notifierTalkback(.Close); 729 - state.ended = true; 730 - sink(.End); 731 - } 732 - | End => () 733 - | Push(_) when !state.ended => sink(.signal) 734 - | Push(_) => () 735 - } 736 - }); 737 - 738 - sink(.Start((.signal) => { 739 - if (!state.ended) { 740 - switch (signal) { 741 - | Close => { 742 - state.sourceTalkback(.Close); 743 - state.notifierTalkback(.Close); 744 - } 745 - | Pull => state.sourceTalkback(.Pull) 746 - } 747 - }; 748 - })); 749 - })); 750 - 751 - let skip = wait => curry(source => curry(sink => { 752 - let rest = ref(wait); 753 - 754 - captureTalkback(source, (.signal, talkback) => { 755 - switch (signal) { 756 - | Push(_) when rest^ > 0 => { 757 - rest := rest^ - 1; 758 - talkback(.Pull); 759 - } 760 - | _ => sink(.signal) 761 - } 762 - }); 763 - })); 764 - 765 - let skipWhile = f => curry(source => curry(sink => { 766 - let skip = ref(true); 767 - 768 - captureTalkback(source, (.signal, talkback) => { 769 - switch (signal) { 770 - | Push(x) when skip^ => { 771 - if (f(.x)) { 772 - talkback(.Pull); 773 - } else { 774 - skip := false; 775 - sink(.signal); 776 - }; 777 - } 778 - | _ => sink(.signal) 779 - } 780 - }); 781 - })); 782 - 783 - type skipUntilStateT = { 784 - mutable skip: bool, 785 - mutable ended: bool, 786 - mutable gotSignal: bool, 787 - mutable sourceTalkback: (.talkbackT) => unit, 788 - mutable notifierTalkback: (.talkbackT) => unit 789 - }; 790 - 791 - let skipUntil = notifier => curry(source => curry(sink => { 792 - let state: skipUntilStateT = { 793 - skip: true, 794 - ended: false, 795 - gotSignal: false, 796 - sourceTalkback: talkbackPlaceholder, 797 - notifierTalkback: talkbackPlaceholder 798 - }; 799 - 800 - source((.signal) => { 801 - switch (signal) { 802 - | Start(tb) => { 803 - state.sourceTalkback = tb; 804 - 805 - notifier((.signal) => { 806 - switch (signal) { 807 - | Start(innerTb) => { 808 - state.notifierTalkback = innerTb; 809 - innerTb(.Pull); 810 - tb(.Pull); 811 - } 812 - | Push(_) => { 813 - state.skip = false; 814 - state.notifierTalkback(.Close); 815 - } 816 - | End => () 817 - } 818 - }); 819 - } 820 - | Push(_) when state.skip && !state.ended => state.sourceTalkback(.Pull) 821 - | Push(_) when !state.ended => { 822 - state.gotSignal = false; 823 - sink(.signal) 824 - } 825 - | Push(_) => () 826 - | End => { 827 - if (state.skip) state.notifierTalkback(.Close); 828 - state.ended = true; 829 - sink(.End) 830 - } 831 - } 832 - }); 833 - 834 - sink(.Start((.signal) => { 835 - switch (signal) { 836 - | Close => { 837 - if (state.skip) state.notifierTalkback(.Close); 838 - state.ended = true; 839 - state.sourceTalkback(.Close); 840 - } 841 - | Pull when !state.gotSignal && !state.ended => { 842 - state.gotSignal = true; 843 - state.sourceTalkback(.Pull); 844 - } 845 - | Pull => () 846 - } 847 - })); 848 - })); 849 - 850 - type publishStateT = { 851 - mutable talkback: (.talkbackT) => unit, 852 - mutable ended: bool 853 - }; 854 - 855 - let publish = source => { 856 - let state: publishStateT = { 857 - talkback: talkbackPlaceholder, 858 - ended: false 859 - }; 860 - 861 - source((.signal) => { 862 - switch (signal) { 863 - | Start(x) => { 864 - state.talkback = x; 865 - x(.Pull); 866 - } 867 - | Push(_) => if (!state.ended) state.talkback(.Pull); 868 - | End => state.ended = true; 869 - } 870 - }); 871 - 872 - { 873 - unsubscribe: () => 874 - if (!state.ended) { 875 - state.ended = true; 876 - state.talkback(.Close); 877 - } 878 - } 879 - }; 880 - 881 - let subscribe = f => curry(source => { 882 - let state: publishStateT = { 883 - talkback: talkbackPlaceholder, 884 - ended: false 885 - }; 886 - 887 - source((.signal) => { 888 - switch (signal) { 889 - | Start(x) => { 890 - state.talkback = x; 891 - x(.Pull); 892 - } 893 - | Push(x) when !state.ended => { 894 - f(.x); 895 - state.talkback(.Pull); 896 - } 897 - | Push(_) => () 898 - | End => state.ended = true; 899 - } 900 - }); 901 - 902 - { 903 - unsubscribe: () => 904 - if (!state.ended) { 905 - state.ended = true; 906 - state.talkback(.Close); 907 - } 908 - } 909 - }); 910 - 911 - let forEach = f => curry(source => { 912 - ignore(subscribe(f, source)); 913 - });
-175
src/wonka.rei
··· 1 - open Wonka_types; 2 - 3 - module Types = Wonka_types; 4 - 5 - /* -- subject factory */ 6 - 7 - let makeSubject: unit => subjectT('a); 8 - 9 - /* -- source factories */ 10 - 11 - /* When constructed, calls a function that receives an observer 12 - and creates a push-based stream of events. This is useful 13 - for constructing any kind of asynchronous stream. The return 14 - callback from the passed observer function will be called when 15 - the stream is closed or ends */ 16 - let make: ((.observerT('a)) => teardownT, sinkT('a)) => unit; 17 - 18 - /* Accepts a list and creates a pullable source for that list. 19 - The source will emit events when being pulled until the list 20 - is exhausted and it completes */ 21 - let fromList: (list('a), sinkT('a)) => unit; 22 - 23 - /* Accepts an array and creates a pullable source for that array. 24 - The source will emit events when being pulled until the array 25 - is exhausted and it completes */ 26 - let fromArray: (array('a), sinkT('a)) => unit; 27 - 28 - /* Accepts a value and creates a pullable source emitting just 29 - that single value. */ 30 - let fromValue: ('a, sinkT('a)) => unit; 31 - 32 - /* A source that ends immediately */ 33 - let empty: (sinkT('a)) => unit; 34 - 35 - /* A source that never ends or emits a value */ 36 - let never: (sinkT('a)) => unit; 37 - 38 - /* -- operators */ 39 - 40 - /* Takes a callback and a source, and creates a sink & source. 41 - The callback will be called for each value that it receives */ 42 - let tap: ((.'a) => unit, sourceT('a), sinkT('a)) => unit; 43 - 44 - /* Takes a mapping function from one type to another, and a source, 45 - and creates a sink & source. 46 - All values that it receives will be transformed using the mapping 47 - function and emitted on the new source */ 48 - let map: ((.'a) => 'b, sourceT('a), sinkT('b)) => unit; 49 - 50 - /* Takes a predicate function returning a boolean, and a source, 51 - and creates a sink & source. 52 - All values that it receives will be filtered using the predicate, 53 - and only truthy values will be passed on to the new source. 54 - The sink will attempt to pull a new value when one was filtered. */ 55 - let filter: ((.'a) => bool, sourceT('a), sinkT('a)) => unit; 56 - 57 - /* Takes a reducer function, a seed value, and a source, and creates 58 - a sink & source. 59 - The last returned value from the reducer function (or the seed value 60 - initially) will be passed to the reducer together with the value 61 - that the sink receives. All return values of the reducer function 62 - are emitted on the new source. */ 63 - let scan: (('b, 'a) => 'b, 'b, sourceT('a), sinkT('b)) => unit; 64 - 65 - /* Takes a mapping function from one types to a source output, 66 - and a source, and creates a sink & source. 67 - The mapping function is called with each value it receives and 68 - the resulting inner source is merged into the output source. */ 69 - let mergeMap: ((.'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 70 - 71 - /* Takes a mapping function from one types to a source output, 72 - and a source, and creates a sink & source. 73 - The mapping function is called with each value it receives and 74 - the latest inner source is merged into the output source. When 75 - a new value comes in the previous source is dicarded. */ 76 - let switchMap: ((.'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 77 - 78 - /* Takes a mapping function from one types to a source output, 79 - and a source, and creates a sink & source. 80 - The mapping function is called with each value it receives and 81 - the resulting inner sources are subscribed to and piped through 82 - to the output source in order. */ 83 - let concatMap: ((.'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 84 - 85 - /* Takes an array of sources and creates a sink & source. 86 - All values that the sink receives from all sources will be passed through 87 - to the new source. */ 88 - let merge: (array(sourceT('a)), sinkT('a)) => unit; 89 - 90 - /* Takes an array of sources and creates a sink & source. 91 - The values from each sources will be emitted on the sink, one after another. 92 - When one source ends, the next one will start. */ 93 - let concat: (array(sourceT('a)), sinkT('a)) => unit; 94 - 95 - /* Works the same as mergeMap but as an operator on a source 96 - of nested sources. */ 97 - let mergeAll: (sourceT(sourceT('a)), sinkT('a)) => unit; 98 - let flatten: (sourceT(sourceT('a)), sinkT('a)) => unit; 99 - 100 - /* Works the same as concatMap but as an operator on a source 101 - of nested sources. */ 102 - let concatAll: (sourceT(sourceT('a)), sinkT('a)) => unit; 103 - 104 - /* Takes a listenable or a pullable source and creates a new source that 105 - will ensure that the source is shared between all sinks that follow. 106 - Essentially the original source will only be created once. */ 107 - let share: (sourceT('a), sinkT('a)) => unit; 108 - 109 - /* Takes two sources and creates a new source & sink. 110 - All latest values from both sources will be passed through as a 111 - tuple of the last values that have been observed */ 112 - let combine: (sourceT('a), sourceT('b), sinkT(('a, 'b))) => unit; 113 - 114 - /* Takes a max number and a source, and creates a sink & source. 115 - It will emit values that the sink receives until the passed maximum number 116 - of values is reached, at which point it will end the source and the 117 - returned, new source. */ 118 - let take: (int, sourceT('a), sinkT('a)) => unit; 119 - 120 - /* Takes a max number and a source, and creates a sink & source. 121 - It will pull values and add them to a queue limiting its size to the passed 122 - number until the source ends. It will then proceed to emit 123 - the cached values on the new source as a pullable. */ 124 - let takeLast: (int, sourceT('a), sinkT('a)) => unit; 125 - 126 - /* Takes a predicate and a source, and creates a sink & source. 127 - It will emit values that the sink receives until the predicate returns false 128 - for a value, at which point it will end the source and the returned, new 129 - source. */ 130 - let takeWhile: ((.'a) => bool, sourceT('a), sinkT('a)) => unit; 131 - 132 - /* Takes a notifier source and an input source, and creates a sink & source. 133 - It will not emit values that the sink receives until the notifier source 134 - It will emit values that the sink receives until the notifier source 135 - emits a value, at which point it will end the source and the returned, new 136 - source. */ 137 - let takeUntil: ( 138 - sourceT('a), 139 - sourceT('b), 140 - sinkT('b) 141 - ) => unit; 142 - 143 - /* Takes a number and a source, and creates a sink & source. 144 - It will not emit values that the sink receives until the passed number 145 - of values is reached, at which point it will start acting like a noop 146 - operator, passing through every signal. */ 147 - let skip: (int, sourceT('a), sinkT('a)) => unit; 148 - 149 - /* Takes a predicate and a source, and creates a sink & source. 150 - It will not emit values that the sink receives until the passed predicate 151 - returns false for a value, at which point it will start acting like a noop 152 - operator, passing through every signal. */ 153 - let skipWhile: ((.'a) => bool, sourceT('a), sinkT('a)) => unit; 154 - 155 - /* Takes a notifier source and an input source, and creates a sink & source. 156 - It will not emit values that the sink receives until the notifier source 157 - emits a value, at which point it will start acting like a noop 158 - operator, passing through every signal. */ 159 - let skipUntil: (sourceT('a), sourceT('b), sinkT('b)) => unit; 160 - 161 - /* -- sink factories */ 162 - 163 - /* Accepts a source and returns a subscription, but does otherwise not surface values */ 164 - let publish: sourceT('a) => subscriptionT; 165 - 166 - /* Takes a function and a source, and creates a sink. 167 - The function will be called for each value that the sink receives. 168 - The sink will attempt to pull new values as values come in, until 169 - the source ends. */ 170 - let forEach: ((.'a) => unit, sourceT('a)) => unit; 171 - 172 - /* Similar to the `forEach` sink factory, but returns an anonymous function 173 - that when called will end the stream immediately. 174 - Ending the stream will propagate an End signal upwards to the root source. */ 175 - let subscribe: ((.'a) => unit, sourceT('a)) => subscriptionT;