git.iko.soy/purescript-stream
on a50a246 help sign in
49 files changed+2940−2151
since splitsnapshots
unifiedsplit
.eslintignore+1 .gitignore−1 CHANGELOG.md−28 README.md−28 bower.json+1−2 ffi/Control/Stream/LinkedList.js+47 ffi/Control/Stream/Stream.js+5 ffi/Control/Stream/combinators/combine.js+97 ffi/Control/Stream/combinators/concat.js+56 ffi/Control/Stream/combinators/delay.js+41 ffi/Control/Stream/combinators/drain.js+4 ffi/Control/Stream/combinators/index.js+8 ffi/Control/Stream/combinators/merge.js+74 ffi/Control/Stream/combinators/mergeConcurrently.js+126 ffi/Control/Stream/combinators/skipRepeatsWith.js+40 ffi/Control/Stream/combinators/switch.js+99 ffi/Control/Stream/disposables/Disposable.js+13 ffi/Control/Stream/disposables/MemoizedDisposable.js+17 ffi/Control/Stream/disposables/SettableDisposable.js+29 ffi/Control/Stream/disposables/disposeSafely.js+3 ffi/Control/Stream/disposables/index.js+12 ffi/Control/Stream/index.js+5 ffi/Control/Stream/multicast/HoldSource.js+45 ffi/Control/Stream/multicast/MulticastDisposable.js+16 ffi/Control/Stream/multicast/MulticastSource.js+62 ffi/Control/Stream/multicast/dispose.js+5 ffi/Control/Stream/multicast/index.js+14 ffi/Control/Stream/runEffects.js+30 ffi/Control/Stream/scheduler/ClockTimer.js+48 ffi/Control/Stream/scheduler/PropagateTask.js+31 ffi/Control/Stream/scheduler/ScheduledTask.js+19 ffi/Control/Stream/scheduler/Scheduler.js+101 ffi/Control/Stream/scheduler/Timeline.js+124 ffi/Control/Stream/scheduler/index.js+16 ffi/Control/Stream/sink/IndexSink.js+24 ffi/Control/Stream/sink/index.js+1 package.json+10−3 rollup.config.js+14 src/Control/Disposable/Disposable.js−32 src/Control/Disposable/Disposable.purs−10 src/Control/Scheduler/Scheduler.js−370 src/Control/Scheduler/Scheduler.purs−32 src/Control/Sink/Sink.purs−9 src/Control/Stream.js+1384 src/Control/Stream.purs+318−40 src/Control/Stream/Stream.js−1244 src/Control/Stream/Stream.purs−340 src/Control/Time.purs−3 test/Main.purs−9
.eslintignore+1
@@ -1 +1,2 @@
11output/
2+src/
.gitignore−1
@@ -6,4 +6,3 @@
66/.psc*
77/.psa*
88src/Main.purs
9−.npm-debug.log*
CHANGELOG.mddeleted−28
@@ -1,28 +0,0 @@
1−<a name="0.2.0"></a>
2−# [0.2.0](https://github.com/TylorS/purescript-stream/compare/v0.1.0...v0.2.0) (2017-03-21)
3−
4−
5−### Bug Fixes
6−
7−* **Stream:** add missing filter import ([d4e1c8e](https://github.com/TylorS/purescript-stream/commit/d4e1c8e))
8−
9−
10−
11−<a name="0.1.0"></a>
12−# [0.1.0](https://github.com/TylorS/purescript-stream/compare/6b75d2f...v0.1.0) (2017-03-16)
13−
14−
15−### Bug Fixes
16−
17−* **Stream:** add missing exports ([13c18b7](https://github.com/TylorS/purescript-stream/commit/13c18b7))
18−
19−
20−### Features
21−
22−* **stream:** implement more helpers and combinators ([8e8b516](https://github.com/TylorS/purescript-stream/commit/8e8b516))
23−* **stream:** more combinators ([a50a246](https://github.com/TylorS/purescript-stream/commit/a50a246))
24−* **stream:** reimplement ([0813a54](https://github.com/TylorS/purescript-stream/commit/0813a54))
25−* **stream:** start of a stream library ([6b75d2f](https://github.com/TylorS/purescript-stream/commit/6b75d2f))
26−
27−
28−
README.mddeleted−28
@@ -1,28 +0,0 @@
1−# Purescript Stream
2−
3−> An ultra-fast reactive stream library for purescript
4−
5−## Let me have it
6−```sh
7−bower install --save purescript-stream
8−```
9−
10−## Basic usage
11−```purescript
12−module Main where
13−
14−import Prelude
15−import Control.Monad.Eff (Eff)
16−import Control.Monad.Eff.Console (CONSOLE, logShow, log)
17−import Control.Stream (STREAM, periodic, constant, scan, tapEvent, tapEnd, drain)
18−import Data.Unit (Unit)
19−
20−main :: Eff (stream :: STREAM, console :: CONSOLE) Unit
21−main = do
22− periodic 1000.0 -- Stream Unit
23− # constant 1 -- Stream Int
24− # scan (+) 0 -- Stream Int
25− # tapEvent logShow -- Perform side-effects on events
26− # tapEnd (log "done") -- Perform a side-effect on stream completion
27− # drain -- activate your stream
28−```
bower.json+1−2
@@ -10,8 +10,7 @@
1010 "purescript-eff": "^2.0.0",
1111 "purescript-prelude": "^2.5.0",
1212 "purescript-refs": "^2.0.0",
13− "purescript-maybe": "^2.1.1",
14− "purescript-partial": "^1.2.0"
13+ "purescript-maybe": "^2.1.1"
1514 },
1615 "devDependencies": {
1716 "purescript-console": "^2.0.0",
ffi/Control/Stream/LinkedList.jsnew file+47
@@ -0,0 +1,47 @@
1+export class LinkedList {
2+ constructor () {
3+ this.head = null
4+ this.length = 0
5+ }
6+
7+ add (x) {
8+ if (this.head !== null) {
9+ this.head.prev = x
10+ x.next = this.head
11+ }
12+ this.head = x
13+ ++this.length
14+ }
15+
16+ remove (x) { // eslint-disable-line complexity
17+ --this.length
18+ if (x === this.head) {
19+ this.head = this.head.next
20+ }
21+ if (x.next !== null) {
22+ x.next.prev = x.prev
23+ x.next = null
24+ }
25+ if (x.prev !== null) {
26+ x.prev.next = x.next
27+ x.prev = null
28+ }
29+ }
30+
31+ isEmpty () {
32+ return this.length === 0
33+ }
34+
35+ dispose () {
36+ if (this.isEmpty()) return
37+
38+ var x = this.head
39+ this.head = null
40+ this.length = 0
41+
42+ while (x !== null) {
43+ x.dispose()
44+ x = x.next
45+ }
46+ }
47+}
ffi/Control/Stream/Stream.jsnew file+5
@@ -0,0 +1,5 @@
1+export class Stream {
2+ constructor (source) {
3+ this.source = source
4+ }
5+}
ffi/Control/Stream/combinators/combine.jsnew file+97
@@ -0,0 +1,97 @@
1+/** @license MIT License (c) copyright 2010-2016 original author or authors */
2+/** @author Brian Cavalier */
3+/** @author John Hann */
4+
5+import { map, tail } from '@most/prelude'
6+
7+import { IndexSink } from '../sink/IndexSink'
8+import { Stream } from '../Stream'
9+import { disposeAll } from '../disposables'
10+
11+export const combine2 = f => s1 => s2 => combineArray(f, [s1, s2])
12+export const combine3 = f => s1 => s2 => s3 => combineArray(f, [s1, s2, s3])
13+export const combine4 = f => s1 => s2 => s3 => s4 => combineArray(f, [s1, s2, s3, s4])
14+export const combine5 = f => s1 => s2 => s3 => s4 => s5 => combineArray(f, [s1, s2, s3, s4, s5])
15+
16+function combineArray (f, streams) {
17+ return new Stream(combineSources(f, streams))
18+}
19+
20+function combineSources (f, streams) {
21+ return new Combine(f, map(getSource, streams))
22+}
23+
24+function getSource (stream) {
25+ return stream.source
26+}
27+
28+function Combine (f, sources) {
29+ this.f = f
30+ this.sources = sources
31+}
32+
33+Combine.prototype.run = function (sink) {
34+ return scheduler => {
35+ var l = this.sources.length
36+ var disposables = new Array(l)
37+ var sinks = new Array(l)
38+
39+ var mergeSink = new CombineSink(disposables, sinks, sink, this.f)
40+
41+ for (var indexSink, i = 0; i < l; ++i) {
42+ indexSink = sinks[i] = new IndexSink(i, mergeSink)
43+ disposables[i] = this.sources[i].run(indexSink)(scheduler)
44+ }
45+
46+ return disposeAll(disposables)
47+ }
48+}
49+
50+function CombineSink (disposables, sinks, sink, f) {
51+ this.sink = sink
52+ this.disposables = disposables
53+ this.sinks = sinks
54+ this.f = f
55+
56+ var l = sinks.length
57+ this.awaiting = l
58+ this.values = new Array(l)
59+ this.hasValue = new Array(l)
60+
61+ for (var i = 0; i < l; ++i) {
62+ this.hasValue[i] = false
63+ }
64+
65+ this.activeCount = sinks.length
66+}
67+
68+CombineSink.prototype.event = function (t) {
69+ return indexedValue => {
70+ var i = indexedValue.index
71+ var awaiting = this._updateReady(i)
72+
73+ this.values[i] = indexedValue.value
74+ if (awaiting === 0) {
75+ const value = tail(this.values).reduce((f, x) => f(x), this.f(this.values[0]))
76+ this.sink.event(t)(value)
77+ }
78+ }
79+}
80+
81+CombineSink.prototype._updateReady = function (index) {
82+ if (this.awaiting > 0) {
83+ if (!this.hasValue[index]) {
84+ this.hasValue[index] = true
85+ this.awaiting -= 1
86+ }
87+ }
88+ return this.awaiting
89+}
90+
91+CombineSink.prototype.end = function (t, indexedValue) {
92+ this.disposables[indexedValue.index].dispose()
93+
94+ if (--this.activeCount === 0) {
95+ this.sink.end(t)
96+ }
97+}
ffi/Control/Stream/combinators/concat.jsnew file+56
@@ -0,0 +1,56 @@
1+import { MemoizedDisposable } from '../disposables/MemoizedDisposable'
2+import { Stream } from '../Stream'
3+
4+export const concat = s1 => s2 => continueWith(() => s2)(s1)
5+
6+export const continueWith = f => stream => new Stream(new ContinueWith(f, stream.source))
7+
8+function ContinueWith (f, source) {
9+ this.f = f
10+ this.source = source
11+}
12+
13+ContinueWith.prototype.run = function (sink) {
14+ return scheduler => {
15+ return new ContinueWithSink(this.f, this.source, sink, scheduler)
16+ }
17+}
18+
19+function ContinueWithSink (f, source, sink, scheduler) {
20+ this.f = f
21+ this.sink = sink
22+ this.scheduler = scheduler
23+ this.active = true
24+ this.disposable = new MemoizedDisposable(source.run(this)(scheduler))
25+}
26+
27+ContinueWithSink.prototype.event = function (t) {
28+ return x => {
29+ if (!this.active) {
30+ return
31+ }
32+ this.sink.event(t)(x)
33+ }
34+}
35+
36+ContinueWithSink.prototype.end = function (t, x) {
37+ if (!this.active) {
38+ return
39+ }
40+
41+ this.disposable.dispose()
42+ this._startNext(t, x, this.sink)
43+}
44+
45+ContinueWithSink.prototype._startNext = function (t, x, sink) {
46+ this._continue(this.f, x, sink)
47+}
48+
49+ContinueWithSink.prototype._continue = function (f, x, sink) {
50+ return f(x).source.run(sink)(this.scheduler)
51+}
52+
53+ContinueWithSink.prototype.dispose = function () {
54+ this.active = false
55+ return this.disposable.dispose()
56+}
ffi/Control/Stream/combinators/delay.jsnew file+41
@@ -0,0 +1,41 @@
1+import { endTask, eventTask } from '../scheduler'
2+
3+import { Stream } from '../Stream'
4+import { disposeAll } from '../disposables'
5+
6+export const delay = delayTime => stream =>
7+ delayTime <= 0 ? stream : new Stream(new Delay(delayTime, stream.source))
8+
9+class Delay {
10+ constructor (dt, source) {
11+ this.dt = dt
12+ this.source = source
13+ }
14+
15+ run (sink) {
16+ return scheduler => {
17+ const delaySink = new DelaySink(this.dt, sink, scheduler)
18+ return disposeAll([delaySink, this.source.run(delaySink)(scheduler)])
19+ }
20+ }
21+}
22+
23+class DelaySink {
24+ constructor (dt, sink, scheduler) {
25+ this.dt = dt
26+ this.sink = sink
27+ this.scheduler = scheduler
28+ }
29+
30+ dispose () {
31+ this.scheduler.cancelAll(task => task.sink === this.sink)
32+ }
33+
34+ event (t) {
35+ return x => this.scheduler.delay(this.dt)(eventTask(x)(this.sink))
36+ }
37+
38+ end (t) {
39+ this.scheduler.delay(this.dt)(endTask(this.sink))
40+ }
41+}
ffi/Control/Stream/combinators/drain.jsnew file+4
@@ -0,0 +1,4 @@
1+import { defaultScheduler } from '../scheduler'
2+import { runEffects } from '../runEffects'
3+
4+export const drain = stream => () => runEffects(stream, defaultScheduler)
ffi/Control/Stream/combinators/index.jsnew file+8
@@ -0,0 +1,8 @@
1+export * from './drain'
2+export * from './mergeConcurrently'
3+export * from './combine'
4+export * from './merge'
5+export * from './concat'
6+export * from './switch'
7+export * from './skipRepeatsWith'
8+export * from './delay'
ffi/Control/Stream/combinators/merge.jsnew file+74
@@ -0,0 +1,74 @@
1+/** @license MIT License (c) copyright 2010-2016 original author or authors */
2+/** @author Brian Cavalier */
3+/** @author John Hann */
4+
5+import { IndexSink } from '../sink/IndexSink'
6+import { Stream } from '../Stream'
7+import { disposeAll } from '../disposables'
8+import { reduce } from '@most/prelude'
9+
10+/**
11+ * @param {Array} streams array of stream to merge
12+ * @returns {Stream} stream containing events from all input observables
13+ * in time order. If two events are simultaneous they will be merged in
14+ * arbitrary order.
15+ */
16+export function merge (streams) {
17+ return new Stream(mergeSources(streams))
18+}
19+
20+/**
21+ * This implements fusion/flattening for merge. It will
22+ * fuse adjacent merge operations. For example:
23+ * - a.merge(b).merge(c) effectively becomes merge(a, b, c)
24+ * - merge(a, merge(b, c)) effectively becomes merge(a, b, c)
25+ * It does this by concatenating the sources arrays of
26+ * any nested Merge sources, in effect "flattening" nested
27+ * merge operations into a single merge.
28+ */
29+function mergeSources (streams) {
30+ return new Merge(reduce(appendSources, [], streams))
31+}
32+
33+function appendSources (sources, stream) {
34+ var source = stream.source
35+ return source instanceof Merge
36+ ? sources.concat(source.sources)
37+ : sources.concat(source)
38+}
39+
40+function Merge (sources) {
41+ this.sources = sources
42+}
43+
44+Merge.prototype.run = function (sink, scheduler) {
45+ var l = this.sources.length
46+ var disposables = new Array(l)
47+ var sinks = new Array(l)
48+
49+ var mergeSink = new MergeSink(disposables, sinks, sink)
50+
51+ for (var indexSink, i = 0; i < l; ++i) {
52+ indexSink = sinks[i] = new IndexSink(i, mergeSink)
53+ disposables[i] = this.sources[i].run(indexSink, scheduler)
54+ }
55+
56+ return disposeAll(disposables)
57+}
58+
59+function MergeSink (disposables, sinks, sink) {
60+ this.sink = sink
61+ this.disposables = disposables
62+ this.activeCount = sinks.length
63+}
64+
65+MergeSink.prototype.event = function (t, indexValue) {
66+ this.sink.event(t, indexValue.value)
67+}
68+
69+MergeSink.prototype.end = function (t, indexedValue) {
70+ dispose.tryDispose(t, this.disposables[indexedValue.index], this.sink)
71+ if (--this.activeCount === 0) {
72+ this.sink.end(t, indexedValue.value)
73+ }
74+}
ffi/Control/Stream/combinators/mergeConcurrently.jsnew file+126
@@ -0,0 +1,126 @@
1+/** @license MIT License (c) copyright 2010-2016 original author or authors */
2+/** @author Brian Cavalier */
3+/** @author John Hann */
4+
5+import { curry2, curry3, id as identity } from '@most/prelude'
6+
7+import { LinkedList } from '../LinkedList'
8+import { MemoizedDisposable } from '../disposables/MemoizedDisposable'
9+import { Stream } from '../Stream'
10+
11+export const flatMap =
12+ curry2((stream, f) => mergeMapConcurrently(f, Infinity, stream))
13+
14+export const mergeConcurrently = curry2((concurrency, stream) =>
15+ mergeMapConcurrently(identity, concurrency, stream))
16+
17+export const join =
18+ mergeConcurrently(Infinity)
19+
20+export const mergeMapConcurrently = curry3((f, concurrency, stream) =>
21+ new Stream(new MergeConcurrently(f, concurrency, stream.source)))
22+
23+class MergeConcurrently {
24+ constructor (f, concurrency, source) {
25+ this.f = f
26+ this.concurrency = concurrency
27+ this.source = source
28+ }
29+
30+ run (sink) {
31+ return scheduler => new Outer(this.f, this.concurrency, this.source, sink, scheduler)
32+ }
33+}
34+
35+class Outer {
36+ constructor (f, concurrency, source, sink, scheduler) {
37+ this.f = f
38+ this.concurrency = concurrency
39+ this.sink = sink
40+ this.scheduler = scheduler
41+ this.pending = []
42+ this.current = new LinkedList()
43+ this.disposable = new MemoizedDisposable(source.run(this)(scheduler))
44+ this.active = true
45+ }
46+
47+ event (t) {
48+ return x => this._addInner(t, x)
49+ }
50+
51+ _addInner (t, x) {
52+ if (this.current.length < this.concurrency) {
53+ this._startInner(t, x)
54+ } else {
55+ this.pending.push(x)
56+ }
57+ }
58+
59+ _startInner (t, x) {
60+ try {
61+ this._initInner(t, x)
62+ } catch (e) {
63+ this.error(t, e)
64+ }
65+ }
66+
67+ _initInner (t, x) {
68+ const innerSink = new Inner(t, this, this.sink)
69+ innerSink.disposable = mapAndRun(this.f, x, innerSink, this.scheduler)
70+ this.current.add(innerSink)
71+ }
72+
73+ end (t) {
74+ this.active = false
75+ this.disposable.dispose()
76+ this._checkEnd(t)
77+ }
78+
79+ dispose () {
80+ this.active = false
81+ this.pending.length = 0
82+ this.disposable.dispose()
83+ this.current.dispose()
84+ }
85+
86+ _endInner (t, inner) {
87+ this.current.remove(inner)
88+ inner.dispose()
89+
90+ if (this.pending.length === 0) {
91+ this._checkEnd(t)
92+ } else {
93+ this._startInner(t, this.pending.shift())
94+ }
95+ }
96+
97+ _checkEnd (t) {
98+ if (!this.active && this.current.isEmpty()) {
99+ this.sink.end(t)
100+ }
101+ }
102+}
103+
104+const mapAndRun = (f, x, sink, scheduler) => f(x).source.run(sink)(scheduler)
105+
106+class Inner {
107+ constructor (time, outer, sink) {
108+ this.prev = this.next = null
109+ this.time = time
110+ this.outer = outer
111+ this.sink = sink
112+ this.disposable = void 0
113+ }
114+
115+ event (t) {
116+ return x => this.sink.event(Math.max(t, this.time))(x)
117+ }
118+
119+ end (t) {
120+ this.outer._endInner(Math.max(t, this.time), this)
121+ }
122+
123+ dispose () {
124+ return this.disposable.dispose()
125+ }
126+}
ffi/Control/Stream/combinators/skipRepeatsWith.jsnew file+40
@@ -0,0 +1,40 @@
1+import { Stream } from '../Stream'
2+
3+export const skipRepeatsWith = equals => stream =>
4+ new Stream(new SkipRepeats(equals, stream))
5+
6+class SkipRepeats {
7+ constructor (equals, source) {
8+ this.equals = equals
9+ this.source = source
10+ }
11+
12+ run (sink) {
13+ return scheduler => this.source.run(new SkipRepeatsSink(this.equals, sink), scheduler)
14+ }
15+}
16+
17+class SkipRepeatsSink {
18+ constructor (equals, sink) {
19+ this.equals = equals
20+ this.value = void 0
21+ this.init = true
22+ }
23+
24+ event (t) {
25+ return x => {
26+ if (this.init) {
27+ this.init = false
28+ this.value = x
29+ this.sink.event(t, x)
30+ } else if (!this.equals(this.value)(x)) {
31+ this.value = x
32+ this.sink.event(t)(x)
33+ }
34+ }
35+ }
36+
37+ end (t) {
38+ this.sink.end(t)
39+ }
40+}
ffi/Control/Stream/combinators/switch.jsnew file+99
@@ -0,0 +1,99 @@
1+import { disposeAll, emptyDisposable } from '../disposables'
2+
3+import { Stream } from '../Stream'
4+
5+/**
6+ * Given a stream of streams, return a new stream that adopts the behavior
7+ * of the most recent inner stream.
8+ * @param {Stream} stream of streams on which to switch
9+ * @returns {Stream} switching stream
10+ */
11+function switchLatest (stream) {
12+ return new Stream(new Switch(stream.source))
13+}
14+
15+export { switchLatest as switch }
16+
17+function Switch (source) {
18+ this.source = source
19+}
20+
21+Switch.prototype.run = function (sink) {
22+ return scheduler => {
23+ const switchSink = new SwitchSink(sink, scheduler)
24+ return disposeAll([switchSink, this.source.run(switchSink)(scheduler)])
25+ }
26+}
27+
28+function SwitchSink (sink, scheduler) {
29+ this.sink = sink
30+ this.scheduler = scheduler
31+ this.current = null
32+ this.ended = false
33+}
34+
35+SwitchSink.prototype.event = function (t) {
36+ return stream => {
37+ this._disposeCurrent(t) // TODO: capture the result of this dispose
38+ this.current = new Segment(t, Infinity, this, this.sink)
39+ this.current.disposable = stream.source.run(this.current)(this.scheduler)
40+ }
41+}
42+
43+SwitchSink.prototype.end = function (t, x) {
44+ this.ended = true
45+ this._checkEnd(t, x)
46+}
47+
48+SwitchSink.prototype.dispose = function () {
49+ return this._disposeCurrent(this.scheduler.now())
50+}
51+
52+SwitchSink.prototype._disposeCurrent = function (t) {
53+ if (this.current !== null) {
54+ return this.current._dispose(t)
55+ }
56+}
57+
58+SwitchSink.prototype._disposeInner = function (t, inner) {
59+ inner._dispose(t) // TODO: capture the result of this dispose
60+ if (inner === this.current) {
61+ this.current = null
62+ }
63+}
64+
65+SwitchSink.prototype._checkEnd = function (t, x) {
66+ if (this.ended && this.current === null) {
67+ this.sink.end(t, x)
68+ }
69+}
70+
71+SwitchSink.prototype._endInner = function (t, x, inner) {
72+ this._disposeInner(t, inner)
73+ this._checkEnd(t, x)
74+}
75+
76+function Segment (min, max, outer, sink) {
77+ this.min = min
78+ this.max = max
79+ this.outer = outer
80+ this.sink = sink
81+ this.disposable = emptyDisposable
82+}
83+
84+Segment.prototype.event = function (t) {
85+ return x => {
86+ if (t < this.max) {
87+ this.sink.event(Math.max(t, this.min))(x)
88+ }
89+ }
90+}
91+
92+Segment.prototype.end = function (t, x) {
93+ this.outer._endInner(Math.max(t, this.min), x, this)
94+}
95+
96+Segment.prototype._dispose = function (t) {
97+ this.max = t
98+ this.disposable.dispose()
99+}
ffi/Control/Stream/disposables/Disposable.jsnew file+13
@@ -0,0 +1,13 @@
1+export class Disposable {
2+ /**
3+ * Create a new Disposable which will dispose its underlying resource.
4+ * @param {function} dispose function
5+ * @param {*?} data any data to be passed to disposer function
6+ */
7+ constructor (dispose, data) {
8+ this._dispose = dispose
9+ this._data = data
10+
11+ this.dispose = () => dispose(data)
12+ }
13+}
ffi/Control/Stream/disposables/MemoizedDisposable.jsnew file+17
@@ -0,0 +1,17 @@
1+export class MemoizedDisposable {
2+ constructor (disposable) {
3+ this.disposed = false
4+ this.value = undefined
5+ this.disposable = disposable
6+ }
7+
8+ dispose () {
9+ if (!this.disposed) {
10+ this.disposed = true
11+ this.value = this.disposable.dispose()
12+ this.disposable = undefined
13+ }
14+
15+ return this.value
16+ }
17+}
ffi/Control/Stream/disposables/SettableDisposable.jsnew file+29
@@ -0,0 +1,29 @@
1+export class SettableDisposable {
2+ constructor () {
3+ this.disposable = void 0
4+ this.disposed = false
5+ this.result = void 0
6+ }
7+
8+ setDisposable (disposable) {
9+ this.disposable = disposable
10+
11+ if (this.disposed) {
12+ this.result = disposable.dispose()
13+ }
14+ }
15+
16+ dispose () {
17+ if (this.disposed) {
18+ return this.result
19+ }
20+
21+ this.disposed = true
22+
23+ if (this.disposable !== void 0) {
24+ this.result = this.disposable.dispose()
25+ }
26+
27+ return this.result
28+ }
29+}
ffi/Control/Stream/disposables/disposeSafely.jsnew file+3
@@ -0,0 +1,3 @@
1+export function disposeSafely (disposable) {
2+ disposable.dispose()
3+}
ffi/Control/Stream/disposables/index.jsnew file+12
@@ -0,0 +1,12 @@
1+import { curry2, id, map } from '@most/prelude'
2+
3+import { Disposable } from './Disposable'
4+import { MemoizedDisposable } from './MemoizedDisposable'
5+import { disposeSafely } from './disposeSafely'
6+
7+export const createDisposable = curry2((dispose, data) => new MemoizedDisposable(new Disposable(dispose, data)))
8+
9+export const emptyDisposable = new Disposable(id, undefined)
10+
11+export const disposeAll = disposables =>
12+ createDisposable(curry2(map)(disposeSafely), disposables)
ffi/Control/Stream/index.jsnew file+5
@@ -0,0 +1,5 @@
1+/* @flow */
2+export * from './disposables'
3+export * from './scheduler'
4+export * from './combinators'
5+export * from './multicast'
ffi/Control/Stream/multicast/HoldSource.jsnew file+45
@@ -0,0 +1,45 @@
1+import { append, drop } from '@most/prelude'
2+
3+import { MulticastSource } from './MulticastSource'
4+
5+export class HoldSource extends MulticastSource {
6+ constructor (source, bufferSize) {
7+ super(source)
8+ this.bufferSize = bufferSize
9+ this.has = false
10+ this.buffer = []
11+ }
12+
13+ add (sink, scheduler) {
14+ if (this.has) {
15+ pushEvents(this.buffer, sink, scheduler)
16+ }
17+
18+ return super.add(sink, scheduler)
19+ }
20+
21+ event (time) {
22+ return value => {
23+ this.has = true
24+ this.buffer = dropAndAppend(value, this.buffer, this.bufferSize)
25+
26+ return super.event(time)(value)
27+ }
28+ }
29+}
30+
31+function pushEvents (buffer, sink, scheduler) {
32+ const length = buffer.length
33+
34+ for (let i = 0; i < length; ++i) {
35+ sink.event(scheduler.now(), buffer[i])
36+ }
37+}
38+
39+export function dropAndAppend (value, buffer, bufferSize) {
40+ if (buffer.length === bufferSize) {
41+ return append(value, drop(1, buffer))
42+ }
43+
44+ return append(value, buffer)
45+}
ffi/Control/Stream/multicast/MulticastDisposable.jsnew file+16
@@ -0,0 +1,16 @@
1+export class MulticastDisposable {
2+ constructor (source, sink) {
3+ this.source = source
4+ this.sink = sink
5+ this.disposed = false
6+ }
7+
8+ dispose () {
9+ if (this.disposed) {
10+ return
11+ }
12+ this.disposed = true
13+ const remaining = this.source.remove(this.sink)
14+ return remaining === 0 && this.source._dispose()
15+ }
16+}
ffi/Control/Stream/multicast/MulticastSource.jsnew file+62
@@ -0,0 +1,62 @@
1+import { append, findIndex, remove } from '@most/prelude'
2+import { dispose, emptyDisposable } from './dispose'
3+
4+import { MulticastDisposable } from './MulticastDisposable'
5+
6+export class MulticastSource {
7+ constructor (source) {
8+ this.source = source
9+ this.sinks = []
10+ this._disposable = emptyDisposable
11+ }
12+
13+ run (sink) {
14+ return scheduler => {
15+ const n = this.add(sink, scheduler)
16+ if (n === 1) {
17+ this._disposable = this.source.run(this)(scheduler)
18+ }
19+ return new MulticastDisposable(this, sink)
20+ }
21+ }
22+
23+ _dispose () {
24+ const disposable = this._disposable
25+ this._disposable = emptyDisposable
26+ return Promise.resolve(disposable).then(dispose)
27+ }
28+
29+ add (sink) {
30+ this.sinks = append(sink, this.sinks)
31+ return this.sinks.length
32+ }
33+
34+ remove (sink) {
35+ const i = findIndex(sink, this.sinks)
36+ // istanbul ignore next
37+ if (i >= 0) {
38+ this.sinks = remove(i, this.sinks)
39+ }
40+
41+ return this.sinks.length
42+ }
43+
44+ event (time) {
45+ return value => {
46+ const s = this.sinks
47+ if (s.length === 1) {
48+ return s[0].event(time)(value)
49+ }
50+ for (let i = 0; i < s.length; ++i) {
51+ s[i].event(time)(value)
52+ }
53+ }
54+ }
55+
56+ end (time) {
57+ const s = this.sinks
58+ for (let i = 0; i < s.length; ++i) {
59+ s[i].end(time)
60+ }
61+ }
62+}
ffi/Control/Stream/multicast/dispose.jsnew file+5
@@ -0,0 +1,5 @@
1+export const dispose = disposable => disposable.dispose()
2+
3+export const emptyDisposable = {
4+ dispose () {}
5+}
ffi/Control/Stream/multicast/index.jsnew file+14
@@ -0,0 +1,14 @@
1+import { HoldSource } from './HoldSource'
2+import { MulticastSource } from './MulticastSource'
3+import { Stream } from '../Stream'
4+
5+export function multicast (stream) {
6+ const source = stream.source
7+
8+ return source instanceof MulticastSource
9+ ? stream
10+ : new Stream(new MulticastSource(source))
11+}
12+
13+export const hold = bufferSize => stream =>
14+ new Stream(new HoldSource(stream.source, bufferSize))
ffi/Control/Stream/runEffects.jsnew file+30
@@ -0,0 +1,30 @@
1+import { SettableDisposable } from './disposables/SettableDisposable'
2+
3+export function runEffects (stream, scheduler) {
4+ return runSourceEffects(stream.source, scheduler)
5+}
6+
7+const runSourceEffects = (source, scheduler) => runSource(source, scheduler)
8+
9+function runSource (source, scheduler) {
10+ const disposable = new SettableDisposable()
11+ const observer = new RunEffectsSink(disposable)
12+
13+ disposable.setDisposable(source.run(observer)(scheduler))
14+
15+ return {}
16+}
17+
18+var RunEffectsSink = function RunEffectsSink (disposable) {
19+ this._disposable = disposable
20+ this.active = true
21+}
22+
23+RunEffectsSink.prototype.event = function event (t) {
24+ return function (x) {}
25+}
26+
27+RunEffectsSink.prototype.end = function end (t) {
28+ this.active = false
29+ Promise.resolve(this._disposable).then(d => d.dispose())
30+}
ffi/Control/Stream/scheduler/ClockTimer.jsnew file+48
@@ -0,0 +1,48 @@
1+/** @license MIT License (c) copyright 2010-2016 original author or authors */
2+/** @author Brian Cavalier */
3+/** @author John Hann */
4+
5+/*global setTimeout, clearTimeout*/
6+
7+export function defer (task) {
8+ return Promise.resolve(task).then(runTask)
9+}
10+
11+export function runTask (task) {
12+ return task.run()
13+}
14+
15+export class ClockTimer {
16+ constructor () {
17+ this.now = Date.now
18+ }
19+
20+ setTimer (f, dt) {
21+ return dt <= 0 ? runAsap(f) : setTimeout(f, dt)
22+ }
23+
24+ clearTimer (t) {
25+ return t instanceof Asap ? t.cancel() : clearTimeout(t)
26+ }
27+}
28+
29+class Asap {
30+ constructor (f) {
31+ this.f = f
32+ this.active = true
33+ }
34+
35+ run () {
36+ return this.active && this.f()
37+ }
38+
39+ cancel () {
40+ this.active = false
41+ }
42+}
43+
44+function runAsap (f) {
45+ const task = new Asap(f)
46+ defer(task)
47+ return task
48+}
ffi/Control/Stream/scheduler/PropagateTask.jsnew file+31
@@ -0,0 +1,31 @@
1+import { curry2, curry3 } from '@most/prelude'
2+
3+const propagateTask =
4+ curry3((run, value, sink) => new PropagateTask(run, value, sink))
5+
6+export const eventTask =
7+ curry2((value, sink) => propagateTask(runEvent, value, sink))
8+
9+export const endTask = sink => propagateTask(runEnd, void 0, sink)
10+
11+class PropagateTask {
12+ constructor (run, value, sink) {
13+ let active = true
14+ this.sink = sink
15+
16+ this.dispose = () => { active = false }
17+ this.run = t => {
18+ if (!active) return
19+
20+ run(t, value, sink)
21+ }
22+ }
23+}
24+
25+function runEvent (time, value, sink) {
26+ sink.event(time)(value)
27+}
28+
29+function runEnd (time, value, sink) {
30+ sink.end(time, value)
31+}
ffi/Control/Stream/scheduler/ScheduledTask.jsnew file+19
@@ -0,0 +1,19 @@
1+/* @flow */
2+export class ScheduledTask {
3+ constructor (delay, period, task, scheduler) {
4+ this.time = delay
5+ this.period = period
6+ this.task = task
7+ this.scheduler = scheduler
8+ this.active = true
9+ }
10+
11+ run () {
12+ this.task.run(this.time)
13+ }
14+
15+ dispose () {
16+ this.scheduler.cancel(this)
17+ this.task.dispose()
18+ }
19+}
ffi/Control/Stream/scheduler/Scheduler.jsnew file+101
@@ -0,0 +1,101 @@
1+/* @flow */
2+import { ScheduledTask } from './ScheduledTask'
3+
4+function runTask (task) {
5+ try {
6+ return task.run()
7+ } catch (e) {
8+ console.error(e)
9+ }
10+}
11+
12+export class Scheduler {
13+ constructor (timer, timeline) {
14+ this.timer = timer
15+ this.timeline = timeline
16+
17+ this._timer = null
18+ this._nextArrival = Infinity
19+
20+ this._runReadyTasksBound = () => this._runReadyTasks(this.now())
21+ }
22+
23+ now () {
24+ return this.timer.now()
25+ }
26+
27+ asap (task) {
28+ return this.schedule(0)(-1)(task)
29+ }
30+
31+ delay (delay) {
32+ return task => this.schedule(delay)(-1)(task)
33+ }
34+
35+ periodic (period) {
36+ return task => this.schedule(0)(period)(task)
37+ }
38+
39+ schedule (delay) {
40+ return period => task => {
41+ const now = this.now()
42+ const st = new ScheduledTask(now + Math.max(0, delay), period, task, this)
43+
44+ this.timeline.add(st)
45+ this._scheduleNextRun(now)
46+ return st
47+ }
48+ }
49+
50+ cancel (task) {
51+ task.active = false
52+ if (this.timeline.remove(task)) {
53+ this._reschedule()
54+ }
55+ }
56+
57+ cancelAll (f) {
58+ this.timeline.removeAll(f)
59+ this._reschedule()
60+ }
61+
62+ _reschedule () {
63+ if (this.timeline.isEmpty()) {
64+ this._unschedule()
65+ } else {
66+ this._scheduleNextRun(this.now())
67+ }
68+ }
69+
70+ _unschedule () {
71+ this.timer.clearTimer(this._timer)
72+ this._timer = null
73+ }
74+
75+ _scheduleNextRun (now) { // eslint-disable-line complexity
76+ if (this.timeline.isEmpty()) {
77+ return
78+ }
79+
80+ const nextArrival = this.timeline.nextArrival()
81+
82+ if (this._timer === null) {
83+ this._scheduleNextArrival(nextArrival, now)
84+ } else if (nextArrival < this._nextArrival) {
85+ this._unschedule()
86+ this._scheduleNextArrival(nextArrival, now)
87+ }
88+ }
89+
90+ _scheduleNextArrival (nextArrival, now) {
91+ this._nextArrival = nextArrival
92+ const delay = Math.max(0, nextArrival - now)
93+ this._timer = this.timer.setTimer(this._runReadyTasksBound, delay)
94+ }
95+
96+ _runReadyTasks (now) {
97+ this._timer = null
98+ this.timeline.runTasks(now, runTask)
99+ this._scheduleNextRun(this.now())
100+ }
101+}
ffi/Control/Stream/scheduler/Timeline.jsnew file+124
@@ -0,0 +1,124 @@
1+/** @license MIT License (c) copyright 2010-2016 original author or authors */
2+/** @author Brian Cavalier */
3+/** @author John Hann */
4+
5+import * as base from '@most/prelude'
6+
7+export class Timeline {
8+ constructor () {
9+ this.tasks = []
10+ }
11+
12+ nextArrival () {
13+ return this.isEmpty() ? Infinity : this.tasks[0].time
14+ }
15+
16+ isEmpty () {
17+ return this.tasks.length === 0
18+ }
19+
20+ add (st) {
21+ insertByTime(st, this.tasks)
22+ }
23+
24+ remove (st) {
25+ const i = binarySearch(st.time, this.tasks)
26+
27+ if (i >= 0 && i < this.tasks.length) {
28+ const at = base.findIndex(st, this.tasks[i].events)
29+ if (at >= 0) {
30+ this.tasks[i].events.splice(at, 1)
31+ return true
32+ }
33+ }
34+
35+ return false
36+ }
37+
38+ removeAll (f) {
39+ for (let i = 0; i < this.tasks.length; ++i) {
40+ removeAllFrom(f, this.tasks[i])
41+ }
42+ }
43+
44+ runTasks (t, runTask) {
45+ const tasks = this.tasks
46+ const l = tasks.length
47+ let i = 0
48+
49+ while (i < l && tasks[i].time <= t) {
50+ ++i
51+ }
52+
53+ this.tasks = tasks.slice(i)
54+
55+ // Run all ready tasks
56+ for (let j = 0; j < i; ++j) {
57+ this.tasks = runReadyTasks(runTask, tasks[j].events, this.tasks)
58+ }
59+ }
60+}
61+
62+function runReadyTasks (runTask, events, tasks) { // eslint-disable-line complexity
63+ for (let i = 0; i < events.length; ++i) {
64+ const task = events[i]
65+
66+ if (task.active) {
67+ runTask(task)
68+
69+ // Reschedule periodic repeating tasks
70+ // Check active again, since a task may have canceled itself
71+ if (task.period >= 0 && task.active) {
72+ task.time = task.time + task.period
73+ insertByTime(task, tasks)
74+ }
75+ }
76+ }
77+
78+ return tasks
79+}
80+
81+function insertByTime (task, timeslots) { // eslint-disable-line complexity
82+ const l = timeslots.length
83+
84+ if (l === 0) {
85+ timeslots.push(newTimeslot(task.time, [task]))
86+ return
87+ }
88+
89+ const i = binarySearch(task.time, timeslots)
90+
91+ if (i >= l) {
92+ timeslots.push(newTimeslot(task.time, [task]))
93+ } else if (task.time === timeslots[i].time) {
94+ timeslots[i].events.push(task)
95+ } else {
96+ timeslots.splice(i, 0, newTimeslot(task.time, [task]))
97+ }
98+}
99+
100+function removeAllFrom (f, timeslot) {
101+ timeslot.events = base.removeAll(f, timeslot.events)
102+}
103+
104+function binarySearch (t, sortedArray) { // eslint-disable-line complexity
105+ let lo = 0
106+ let hi = sortedArray.length
107+ let mid, y
108+
109+ while (lo < hi) {
110+ mid = Math.floor((lo + hi) / 2)
111+ y = sortedArray[mid]
112+
113+ if (t === y.time) {
114+ return mid
115+ } else if (t < y.time) {
116+ hi = mid
117+ } else {
118+ lo = mid + 1
119+ }
120+ }
121+ return hi
122+}
123+
124+const newTimeslot = (t, events) => ({ time: t, events: events })
ffi/Control/Stream/scheduler/index.jsnew file+16
@@ -0,0 +1,16 @@
1+import { ClockTimer } from './ClockTimer'
2+import { Scheduler } from './Scheduler'
3+import { Timeline } from './Timeline'
4+import { curry2 } from '@most/prelude'
5+
6+export { endTask, eventTask } from './PropagateTask'
7+
8+export const defaultScheduler = new Scheduler(new ClockTimer(), new Timeline())
9+
10+export const scheduleTasks = curry2((tasks, scheduler) => {
11+ const scheduledTasks = tasks.map(task => scheduler.asap(task))
12+
13+ return {
14+ dispose: () => scheduledTasks.forEach(task => task.dispose())
15+ }
16+})
ffi/Control/Stream/sink/IndexSink.jsnew file+24
@@ -0,0 +1,24 @@
1+export class IndexSink {
2+ constructor (i, sink) {
3+ this.sink = sink
4+ this.index = i
5+ this.active = true
6+ this.value = void 0
7+ }
8+
9+ event (t) {
10+ return x => {
11+ if (!this.active) return
12+
13+ this.value = x
14+ this.sink.event(t)(this)
15+ }
16+ }
17+
18+ end (t) {
19+ if (!this.active) return
20+
21+ this.active = false
22+ this.sink.end(t, { index: this.index })
23+ }
24+}
ffi/Control/Stream/sink/index.jsnew file+1
@@ -0,0 +1 @@
1+export * from './IndexSink'
package.json+10−3
@@ -1,11 +1,11 @@
11{
2− "name": "purescript-stream",
3− "version": "0.2.0",
2+ "name": "purescript-tempest",
3+ "version": "0.0.0",
44 "description": "",
55 "main": "index.js",
66 "scripts": {
77 "start": "yarn build && pulp run",
8− "build": "pulp build",
8+ "build": "rollup -c && pulp build",
99 "changelog": "conventional-changelog -i CHANGELOG.md -s -r 0 -p angular",
1010 "clean": "rimraf lib lib.es2015",
1111 "commit": "git-cz",
@@ -32,7 +32,14 @@
3232 "husky": "^0.13.2",
3333 "pulp": "^10.0.4",
3434 "purescript": "^0.10.7",
35+ "rollup": "^0.41.4",
36+ "rollup-plugin-buble": "^0.15.0",
37+ "rollup-plugin-flow": "^1.1.1",
38+ "rollup-plugin-node-resolve": "^2.0.0",
3539 "uglify-js": "^2.8.11",
3640 "validate-commit-msg": "^2.11.2"
41+ },
42+ "dependencies": {
43+ "@most/prelude": "^1.5.0"
3744 }
3845}
rollup.config.jsnew file+14
@@ -0,0 +1,14 @@
1+import buble from 'rollup-plugin-buble'
2+import flow from 'rollup-plugin-flow'
3+import resolve from 'rollup-plugin-node-resolve'
4+
5+export default {
6+ entry: 'ffi/Control/Stream/index.js',
7+ dest: 'src/Control/Stream.js',
8+ format: 'cjs',
9+ plugins: [
10+ flow(),
11+ buble(),
12+ resolve({ module: true, jsnext: true })
13+ ]
14+}
src/Control/Disposable/Disposable.jsdeleted−32
@@ -1,32 +0,0 @@
1−exports.emptyDisposable = { dispose: function () { return {} } }
2−
3−exports.disposeAll = function (disposables) {
4− var disposed = false
5−
6− function dispose () {
7− if (disposed) return
8−
9− disposables.forEach(function (disposable) {
10− disposable.dispose()
11− })
12−
13− disposed = true
14− }
15−
16− return { dispose: dispose }
17−}
18−
19−exports.lazyDisposable = function (f) {
20− var disposed = false
21−
22− function dispose () {
23− if (disposed) return
24− var disposable = f()
25−
26− disposable.dispose()
27−
28− disposed = true
29− }
30−
31− return { dispose: dispose }
32−}
src/Control/Disposable/Disposable.pursdeleted−10
@@ -1,10 +0,0 @@
1−module Control.Stream.Disposable where
2−
3−import Control.Monad.Eff (Pure)
4−import Data.Unit (Unit)
5−
6−type Disposable = { dispose :: Pure Unit }
7−
8−foreign import emptyDisposable :: Disposable
9−foreign import disposeAll :: Array Disposable -> Disposable
10−foreign import lazyDisposable :: (Unit -> Disposable) -> Disposable
src/Control/Scheduler/Scheduler.jsdeleted−370
@@ -1,370 +0,0 @@
1−exports.scheduleTasks = function (f) {
2− return function (tasks) {
3− var scheduledTasks = tasks.map(f.bind(scheduler))
4−
5− function dispose () {
6− scheduledTasks.forEach(function (task) {
7− task.dispose()
8− })
9− }
10−
11− return { dispose: dispose }
12− }
13−}
14−
15−exports.eventTask = function (sink) {
16− return function (value) {
17− return new PropagateTask(runEvent, value, sink)
18− }
19−}
20−
21−exports.endTask = function (sink) {
22− return new PropagateTask(runEnd, void 0, sink)
23−}
24−
25−function PropagateTask (run, value, sink) {
26− this.active = true
27− this._run = run
28− this.value = value
29− this.sink = sink
30−}
31−
32−PropagateTask.prototype.dispose = function () {
33− this.active = false
34−}
35−
36−PropagateTask.prototype.run = function (time) {
37− if (!this.active) return
38−
39− this._run(time, this.value, this.sink)
40−}
41−
42−function runEvent (time, value, sink) {
43− sink.event(time)(value)
44−}
45−
46−function runEnd (time, value, sink) {
47− sink.end(time)
48−}
49−
50−function defer (task) {
51− return Promise.resolve(task).then(runTask)
52−}
53−
54−function runTask (task) {
55− return task.run()
56−}
57−
58−var ClockTimer = function ClockTimer () {
59− this.now = Date.now
60−}
61−
62−ClockTimer.prototype.setTimer = function setTimer (f, dt) {
63− return dt <= 0 ? runAsap(f) : setTimeout(f, dt)
64−}
65−
66−ClockTimer.prototype.clearTimer = function clearTimer (t) {
67− return t instanceof Asap ? t.cancel() : clearTimeout(t)
68−}
69−
70−var Asap = function Asap (f) {
71− this.f = f
72− this.active = true
73−}
74−
75−Asap.prototype.run = function run () {
76− return this.active && this.f()
77−}
78−
79−Asap.prototype.cancel = function cancel () {
80− this.active = false
81−}
82−
83−function runAsap (f) {
84− var task = new Asap(f)
85− defer(task)
86− return task
87−}
88−
89−var ScheduledTask = function ScheduledTask (delay, period, task, scheduler) {
90− this.time = delay
91− this.period = period
92− this.task = task
93− this.scheduler = scheduler
94− this.active = true
95−}
96−
97−ScheduledTask.prototype.run = function run () {
98− this.task.run(this.time)
99−}
100−
101−ScheduledTask.prototype.dispose = function dispose () {
102− this.scheduler.cancel(this)
103− this.task.dispose()
104−}
105−
106−function runTask$1 (task) {
107− try {
108− return task.run()
109− } catch (e) {
110− console.error(e)
111− }
112−}
113−
114−var Scheduler = function Scheduler (timer, timeline) {
115− var this$1 = this
116−
117− this.timer = timer
118− this.timeline = timeline
119−
120− this._timer = null
121− this._nextArrival = Infinity
122−
123− this._runReadyTasksBound = function () { return this$1._runReadyTasks(this$1.now()) }
124−}
125−
126−Scheduler.prototype.now = function now () {
127− return this.timer.now()
128−}
129−
130−Scheduler.prototype.asap = function asap (task) {
131− return this.schedule(0)(-1)(task)
132−}
133−
134−Scheduler.prototype.delay = function delay (delay$1) {
135− var this$1 = this
136−
137− return function (task) { return this$1.schedule(delay$1)(-1)(task) }
138−}
139−
140−Scheduler.prototype.periodic = function periodic (period) {
141− var this$1 = this
142−
143− return function (task) { return this$1.schedule(0)(period)(task) }
144−}
145−
146−Scheduler.prototype.schedule = function schedule (delay) {
147− var this$1 = this
148−
149− return function (period) {
150− return function (task) {
151− var now = this$1.now()
152− var st = new ScheduledTask(now + Math.max(0, delay), period, task, this$1)
153−
154− st.run = st.run.bind(st)
155− st.dispose = st.dispose.bind(st)
156−
157− this$1.timeline.add(st)
158− this$1._scheduleNextRun(now)
159− return st
160− }
161− }
162−}
163−
164−Scheduler.prototype.cancel = function cancel (task) {
165− task.active = false
166− if (this.timeline.remove(task)) {
167− this._reschedule()
168− }
169−}
170−
171−Scheduler.prototype.cancelAll = function cancelAll (f) {
172− this.timeline.removeAll(f)
173− this._reschedule()
174−}
175−
176−Scheduler.prototype._reschedule = function _reschedule () {
177− if (this.timeline.isEmpty()) {
178− this._unschedule()
179− } else {
180− this._scheduleNextRun(this.now())
181− }
182−}
183−
184−Scheduler.prototype._unschedule = function _unschedule () {
185− this.timer.clearTimer(this._timer)
186− this._timer = null
187−}
188−
189−Scheduler.prototype._scheduleNextRun = function _scheduleNextRun (now) { // eslint-disable-line complexity
190− if (this.timeline.isEmpty()) {
191− return
192− }
193−
194− var nextArrival = this.timeline.nextArrival()
195−
196− if (this._timer === null) {
197− this._scheduleNextArrival(nextArrival, now)
198− } else if (nextArrival < this._nextArrival) {
199− this._unschedule()
200− this._scheduleNextArrival(nextArrival, now)
201− }
202−}
203−
204−Scheduler.prototype._scheduleNextArrival = function _scheduleNextArrival (nextArrival, now) {
205− this._nextArrival = nextArrival
206− var delay = Math.max(0, nextArrival - now)
207− this._timer = this.timer.setTimer(this._runReadyTasksBound, delay)
208−}
209−
210−Scheduler.prototype._runReadyTasks = function _runReadyTasks (now) {
211− this._timer = null
212− this.timeline.runTasks(now, runTask$1)
213− this._scheduleNextRun(this.now())
214−}
215−
216−/** @license MIT License (c) copyright 2010-2016 original author or authors */
217−/** @author Brian Cavalier */
218−/** @author John Hann */
219−
220−var Timeline = function Timeline () {
221− this.tasks = []
222−}
223−
224−Timeline.prototype.nextArrival = function nextArrival () {
225− return this.isEmpty() ? Infinity : this.tasks[0].time
226−}
227−
228−Timeline.prototype.isEmpty = function isEmpty () {
229− return this.tasks.length === 0
230−}
231−
232−Timeline.prototype.add = function add (st) {
233− insertByTime(st, this.tasks)
234−}
235−
236−Timeline.prototype.remove = function remove$$1 (st) {
237− var i = binarySearch(st.time, this.tasks)
238−
239− if (i >= 0 && i < this.tasks.length) {
240− var at = findIndex(st, this.tasks[i].events)
241− if (at >= 0) {
242− this.tasks[i].events.splice(at, 1)
243− return true
244− }
245− }
246−
247− return false
248−}
249−
250−Timeline.prototype.removeAll = function removeAll$$1 (f) {
251− var this$1 = this
252−
253− for (var i = 0; i < this.tasks.length; ++i) {
254− removeAllFrom(f, this$1.tasks[i])
255− }
256−}
257−
258−Timeline.prototype.runTasks = function runTasks (t, runTask) {
259− var this$1 = this
260−
261− var tasks = this.tasks
262− var l = tasks.length
263− var i = 0
264−
265− while (i < l && tasks[i].time <= t) {
266− ++i
267− }
268−
269− this.tasks = tasks.slice(i)
270−
271− // Run all ready tasks
272− for (var j = 0; j < i; ++j) {
273− this$1.tasks = runReadyTasks(runTask, tasks[j].events, this$1.tasks)
274− }
275−}
276−
277−function runReadyTasks (runTask, events, tasks) { // eslint-disable-line complexity
278− for (var i = 0; i < events.length; ++i) {
279− var task = events[i]
280−
281− if (task.active) {
282− runTask(task)
283−
284− // Reschedule periodic repeating tasks
285− // Check active again, since a task may have canceled itself
286− if (task.period >= 0 && task.active) {
287− task.time = task.time + task.period
288− insertByTime(task, tasks)
289− }
290− }
291− }
292−
293− return tasks
294−}
295−
296−function insertByTime (task, timeslots) { // eslint-disable-line complexity
297− var l = timeslots.length
298−
299− if (l === 0) {
300− timeslots.push(newTimeslot(task.time, [task]))
301− return
302− }
303−
304− var i = binarySearch(task.time, timeslots)
305−
306− if (i >= l) {
307− timeslots.push(newTimeslot(task.time, [task]))
308− } else if (task.time === timeslots[i].time) {
309− timeslots[i].events.push(task)
310− } else {
311− timeslots.splice(i, 0, newTimeslot(task.time, [task]))
312− }
313−}
314−
315−function removeAllFrom (f, timeslot) {
316− timeslot.events = removeAll(f, timeslot.events)
317−}
318−
319−function binarySearch (t, sortedArray) { // eslint-disable-line complexity
320− var lo = 0
321− var hi = sortedArray.length
322− var mid, y
323−
324− while (lo < hi) {
325− mid = Math.floor((lo + hi) / 2)
326− y = sortedArray[mid]
327−
328− if (t === y.time) {
329− return mid
330− } else if (t < y.time) {
331− hi = mid
332− } else {
333− lo = mid + 1
334− }
335− }
336− return hi
337−}
338−
339−var newTimeslot = function (t, events) { return ({ time: t, events: events }) }
340−
341−function removeAll (f, a) {
342− var l = a.length
343− var b = new Array(l)
344− var j = 0
345− for (var x = (void 0), i = 0; i < l; ++i) {
346− x = a[i]
347− if (!f(x)) {
348− b[j] = x
349− ++j
350− }
351− }
352−
353− b.length = j
354− return b
355−}
356−
357−// findIndex :: a -> [a] -> Int
358−// find index of x in a, from the left
359−function findIndex (x, a) {
360− for (var i = 0, l = a.length; i < l; ++i) {
361− if (x === a[i]) {
362− return i
363− }
364− }
365− return -1
366−}
367−
368−var scheduler = new Scheduler(new ClockTimer(), new Timeline())
369−
370−exports.scheduler = scheduler
src/Control/Scheduler/Scheduler.pursdeleted−32
@@ -1,32 +0,0 @@
1−module Control.Stream.Scheduler where
2−
3−import Control.Monad.Eff (Pure)
4−import Control.Stream.Disposable (Disposable)
5−import Control.Stream.Sink (Sink)
6−import Control.Stream.Time (Time)
7−import Data.Unit (Unit)
8−
9−newtype Scheduler = Scheduler
10− { now :: Pure Time
11− , asap :: Task -> ScheduledTask
12− , delay :: Number -> Task -> ScheduledTask
13− , periodic :: Number -> Task -> ScheduledTask
14− , schedule :: Number -> Number -> Task -> ScheduledTask
15− , cancel :: ScheduledTask -> Unit
16− , cancelAll :: (ScheduledTask -> Boolean) -> Unit
17− }
18−
19−type Task =
20− { run :: Time -> Unit
21− , dispose :: Pure Unit
22− }
23−
24−type ScheduledTask =
25− { run :: Pure Unit
26− , dispose :: Pure Unit
27− }
28−
29−foreign import scheduler :: Scheduler
30−foreign import scheduleTasks :: (Task -> ScheduledTask) -> Array Task -> Disposable
31−foreign import eventTask :: forall a. Sink a -> a -> Task
32−foreign import endTask :: forall a. Sink a -> Task
src/Control/Sink/Sink.pursdeleted−9
@@ -1,9 +0,0 @@
1−module Control.Stream.Sink (Sink(..)) where
2−
3−import Control.Stream.Time (Time)
4−import Data.Unit (Unit)
5−
6−newtype Sink a = Sink
7− { event :: Time -> a -> Unit
8− , end :: Time -> Unit
9− }
src/Control/Stream.jsnew file+1384
@@ -0,0 +1,1384 @@
1+'use strict';
2+
3+Object.defineProperty(exports, '__esModule', { value: true });
4+
5+/** @license MIT License (c) copyright 2010-2016 original author or authors */
6+
7+// Non-mutating array operations
8+
9+// cons :: a -> [a] -> [a]
10+// a with x prepended
11+
12+
13+// append :: a -> [a] -> [a]
14+// a with x appended
15+function append (x, a) {
16+ var l = a.length;
17+ var b = new Array(l + 1);
18+ for (var i = 0; i < l; ++i) {
19+ b[i] = a[i];
20+ }
21+
22+ b[l] = x;
23+ return b
24+}
25+
26+// drop :: Int -> [a] -> [a]
27+// drop first n elements
28+function drop (n, a) { // eslint-disable-line complexity
29+ if (n < 0) {
30+ throw new TypeError('n must be >= 0')
31+ }
32+
33+ var l = a.length;
34+ if (n === 0 || l === 0) {
35+ return a
36+ }
37+
38+ if (n >= l) {
39+ return []
40+ }
41+
42+ return unsafeDrop(n, a, l - n)
43+}
44+
45+// unsafeDrop :: Int -> [a] -> Int -> [a]
46+// Internal helper for drop
47+function unsafeDrop (n, a, l) {
48+ var b = new Array(l);
49+ for (var i = 0; i < l; ++i) {
50+ b[i] = a[n + i];
51+ }
52+ return b
53+}
54+
55+// tail :: [a] -> [a]
56+// drop head element
57+function tail (a) {
58+ return drop(1, a)
59+}
60+
61+// copy :: [a] -> [a]
62+// duplicate a (shallow duplication)
63+
64+
65+// map :: (a -> b) -> [a] -> [b]
66+// transform each element with f
67+function map (f, a) {
68+ var l = a.length;
69+ var b = new Array(l);
70+ for (var i = 0; i < l; ++i) {
71+ b[i] = f(a[i]);
72+ }
73+ return b
74+}
75+
76+// reduce :: (a -> b -> a) -> a -> [b] -> a
77+// accumulate via left-fold
78+function reduce (f, z, a) {
79+ var r = z;
80+ for (var i = 0, l = a.length; i < l; ++i) {
81+ r = f(r, a[i], i);
82+ }
83+ return r
84+}
85+
86+// replace :: a -> Int -> [a]
87+// replace element at index
88+
89+
90+// remove :: Int -> [a] -> [a]
91+// remove element at index
92+function remove (i, a) { // eslint-disable-line complexity
93+ if (i < 0) {
94+ throw new TypeError('i must be >= 0')
95+ }
96+
97+ var l = a.length;
98+ if (l === 0 || i >= l) { // exit early if index beyond end of array
99+ return a
100+ }
101+
102+ if (l === 1) { // exit early if index in bounds and length === 1
103+ return []
104+ }
105+
106+ return unsafeRemove(i, a, l - 1)
107+}
108+
109+// unsafeRemove :: Int -> [a] -> Int -> [a]
110+// Internal helper to remove element at index
111+function unsafeRemove (i, a, l) {
112+ var b = new Array(l);
113+ var j;
114+ for (j = 0; j < i; ++j) {
115+ b[j] = a[j];
116+ }
117+ for (j = i; j < l; ++j) {
118+ b[j] = a[j + 1];
119+ }
120+
121+ return b
122+}
123+
124+// removeAll :: (a -> boolean) -> [a] -> [a]
125+// remove all elements matching a predicate
126+function removeAll (f, a) {
127+ var l = a.length;
128+ var b = new Array(l);
129+ var j = 0;
130+ for (var x = (void 0), i = 0; i < l; ++i) {
131+ x = a[i];
132+ if (!f(x)) {
133+ b[j] = x;
134+ ++j;
135+ }
136+ }
137+
138+ b.length = j;
139+ return b
140+}
141+
142+// findIndex :: a -> [a] -> Int
143+// find index of x in a, from the left
144+function findIndex (x, a) {
145+ for (var i = 0, l = a.length; i < l; ++i) {
146+ if (x === a[i]) {
147+ return i
148+ }
149+ }
150+ return -1
151+}
152+
153+// isArrayLike :: * -> boolean
154+// Return true iff x is array-like
155+
156+/** @license MIT License (c) copyright 2010-2016 original author or authors */
157+
158+// id :: a -> a
159+var id = function (x) { return x; };
160+
161+// compose :: (b -> c) -> (a -> b) -> (a -> c)
162+
163+
164+// apply :: (a -> b) -> a -> b
165+
166+
167+// curry2 :: ((a, b) -> c) -> (a -> b -> c)
168+function curry2 (f) {
169+ function curried (a, b) {
170+ switch (arguments.length) {
171+ case 0: return curried
172+ case 1: return function (b) { return f(a, b); }
173+ default: return f(a, b)
174+ }
175+ }
176+ return curried
177+}
178+
179+// curry3 :: ((a, b, c) -> d) -> (a -> b -> c -> d)
180+function curry3 (f) {
181+ function curried (a, b, c) { // eslint-disable-line complexity
182+ switch (arguments.length) {
183+ case 0: return curried
184+ case 1: return curry2(function (b, c) { return f(a, b, c); })
185+ case 2: return function (c) { return f(a, b, c); }
186+ default:return f(a, b, c)
187+ }
188+ }
189+ return curried
190+}
191+
192+// curry4 :: ((a, b, c, d) -> e) -> (a -> b -> c -> d -> e)
193+
194+/** @license MIT License (c) copyright 2016 original author or authors */
195+
196+var Disposable = function Disposable (dispose, data) {
197+ this._dispose = dispose;
198+ this._data = data;
199+
200+ this.dispose = function () { return dispose(data); };
201+};
202+
203+var MemoizedDisposable = function MemoizedDisposable (disposable) {
204+ this.disposed = false;
205+ this.value = undefined;
206+ this.disposable = disposable;
207+};
208+
209+MemoizedDisposable.prototype.dispose = function dispose () {
210+ if (!this.disposed) {
211+ this.disposed = true;
212+ this.value = this.disposable.dispose();
213+ this.disposable = undefined;
214+ }
215+
216+ return this.value
217+};
218+
219+function disposeSafely (disposable) {
220+ disposable.dispose();
221+}
222+
223+var createDisposable = curry2(function (dispose, data) { return new MemoizedDisposable(new Disposable(dispose, data)); });
224+
225+var emptyDisposable = new Disposable(id, undefined);
226+
227+var disposeAll = function (disposables) { return createDisposable(curry2(map)(disposeSafely), disposables); };
228+
229+/** @license MIT License (c) copyright 2010-2016 original author or authors */
230+/** @author Brian Cavalier */
231+/** @author John Hann */
232+
233+/*global setTimeout, clearTimeout*/
234+
235+function defer (task) {
236+ return Promise.resolve(task).then(runTask)
237+}
238+
239+function runTask (task) {
240+ return task.run()
241+}
242+
243+var ClockTimer = function ClockTimer () {
244+ this.now = Date.now;
245+};
246+
247+ClockTimer.prototype.setTimer = function setTimer (f, dt) {
248+ return dt <= 0 ? runAsap(f) : setTimeout(f, dt)
249+};
250+
251+ClockTimer.prototype.clearTimer = function clearTimer (t) {
252+ return t instanceof Asap ? t.cancel() : clearTimeout(t)
253+};
254+
255+var Asap = function Asap (f) {
256+ this.f = f;
257+ this.active = true;
258+};
259+
260+Asap.prototype.run = function run () {
261+ return this.active && this.f()
262+};
263+
264+Asap.prototype.cancel = function cancel () {
265+ this.active = false;
266+};
267+
268+function runAsap (f) {
269+ var task = new Asap(f);
270+ defer(task);
271+ return task
272+}
273+
274+/* */
275+var ScheduledTask = function ScheduledTask (delay, period, task, scheduler) {
276+ this.time = delay;
277+ this.period = period;
278+ this.task = task;
279+ this.scheduler = scheduler;
280+ this.active = true;
281+};
282+
283+ScheduledTask.prototype.run = function run () {
284+ this.task.run(this.time);
285+};
286+
287+ScheduledTask.prototype.dispose = function dispose () {
288+ this.scheduler.cancel(this);
289+ this.task.dispose();
290+};
291+
292+/* */
293+function runTask$1 (task) {
294+ try {
295+ return task.run()
296+ } catch (e) {
297+ console.error(e);
298+ }
299+}
300+
301+var Scheduler = function Scheduler (timer, timeline) {
302+ var this$1 = this;
303+
304+ this.timer = timer;
305+ this.timeline = timeline;
306+
307+ this._timer = null;
308+ this._nextArrival = Infinity;
309+
310+ this._runReadyTasksBound = function () { return this$1._runReadyTasks(this$1.now()); };
311+};
312+
313+Scheduler.prototype.now = function now () {
314+ return this.timer.now()
315+};
316+
317+Scheduler.prototype.asap = function asap (task) {
318+ return this.schedule(0)(-1)(task)
319+};
320+
321+Scheduler.prototype.delay = function delay (delay$1) {
322+ var this$1 = this;
323+
324+ return function (task) { return this$1.schedule(delay$1)(-1)(task); }
325+};
326+
327+Scheduler.prototype.periodic = function periodic (period) {
328+ var this$1 = this;
329+
330+ return function (task) { return this$1.schedule(0)(period)(task); }
331+};
332+
333+Scheduler.prototype.schedule = function schedule (delay) {
334+ var this$1 = this;
335+
336+ return function (period) { return function (task) {
337+ var now = this$1.now();
338+ var st = new ScheduledTask(now + Math.max(0, delay), period, task, this$1);
339+
340+ this$1.timeline.add(st);
341+ this$1._scheduleNextRun(now);
342+ return st
343+ }; }
344+};
345+
346+Scheduler.prototype.cancel = function cancel (task) {
347+ task.active = false;
348+ if (this.timeline.remove(task)) {
349+ this._reschedule();
350+ }
351+};
352+
353+Scheduler.prototype.cancelAll = function cancelAll (f) {
354+ this.timeline.removeAll(f);
355+ this._reschedule();
356+};
357+
358+Scheduler.prototype._reschedule = function _reschedule () {
359+ if (this.timeline.isEmpty()) {
360+ this._unschedule();
361+ } else {
362+ this._scheduleNextRun(this.now());
363+ }
364+};
365+
366+Scheduler.prototype._unschedule = function _unschedule () {
367+ this.timer.clearTimer(this._timer);
368+ this._timer = null;
369+};
370+
371+Scheduler.prototype._scheduleNextRun = function _scheduleNextRun (now) { // eslint-disable-line complexity
372+ if (this.timeline.isEmpty()) {
373+ return
374+ }
375+
376+ var nextArrival = this.timeline.nextArrival();
377+
378+ if (this._timer === null) {
379+ this._scheduleNextArrival(nextArrival, now);
380+ } else if (nextArrival < this._nextArrival) {
381+ this._unschedule();
382+ this._scheduleNextArrival(nextArrival, now);
383+ }
384+};
385+
386+Scheduler.prototype._scheduleNextArrival = function _scheduleNextArrival (nextArrival, now) {
387+ this._nextArrival = nextArrival;
388+ var delay = Math.max(0, nextArrival - now);
389+ this._timer = this.timer.setTimer(this._runReadyTasksBound, delay);
390+};
391+
392+Scheduler.prototype._runReadyTasks = function _runReadyTasks (now) {
393+ this._timer = null;
394+ this.timeline.runTasks(now, runTask$1);
395+ this._scheduleNextRun(this.now());
396+};
397+
398+/** @license MIT License (c) copyright 2010-2016 original author or authors */
399+/** @author Brian Cavalier */
400+/** @author John Hann */
401+
402+var Timeline = function Timeline () {
403+ this.tasks = [];
404+};
405+
406+Timeline.prototype.nextArrival = function nextArrival () {
407+ return this.isEmpty() ? Infinity : this.tasks[0].time
408+};
409+
410+Timeline.prototype.isEmpty = function isEmpty () {
411+ return this.tasks.length === 0
412+};
413+
414+Timeline.prototype.add = function add (st) {
415+ insertByTime(st, this.tasks);
416+};
417+
418+Timeline.prototype.remove = function remove$$1 (st) {
419+ var i = binarySearch(st.time, this.tasks);
420+
421+ if (i >= 0 && i < this.tasks.length) {
422+ var at = findIndex(st, this.tasks[i].events);
423+ if (at >= 0) {
424+ this.tasks[i].events.splice(at, 1);
425+ return true
426+ }
427+ }
428+
429+ return false
430+};
431+
432+Timeline.prototype.removeAll = function removeAll$$1 (f) {
433+ var this$1 = this;
434+
435+ for (var i = 0; i < this.tasks.length; ++i) {
436+ removeAllFrom(f, this$1.tasks[i]);
437+ }
438+};
439+
440+Timeline.prototype.runTasks = function runTasks (t, runTask) {
441+ var this$1 = this;
442+
443+ var tasks = this.tasks;
444+ var l = tasks.length;
445+ var i = 0;
446+
447+ while (i < l && tasks[i].time <= t) {
448+ ++i;
449+ }
450+
451+ this.tasks = tasks.slice(i);
452+
453+ // Run all ready tasks
454+ for (var j = 0; j < i; ++j) {
455+ this$1.tasks = runReadyTasks(runTask, tasks[j].events, this$1.tasks);
456+ }
457+};
458+
459+function runReadyTasks (runTask, events, tasks) { // eslint-disable-line complexity
460+ for (var i = 0; i < events.length; ++i) {
461+ var task = events[i];
462+
463+ if (task.active) {
464+ runTask(task);
465+
466+ // Reschedule periodic repeating tasks
467+ // Check active again, since a task may have canceled itself
468+ if (task.period >= 0 && task.active) {
469+ task.time = task.time + task.period;
470+ insertByTime(task, tasks);
471+ }
472+ }
473+ }
474+
475+ return tasks
476+}
477+
478+function insertByTime (task, timeslots) { // eslint-disable-line complexity
479+ var l = timeslots.length;
480+
481+ if (l === 0) {
482+ timeslots.push(newTimeslot(task.time, [task]));
483+ return
484+ }
485+
486+ var i = binarySearch(task.time, timeslots);
487+
488+ if (i >= l) {
489+ timeslots.push(newTimeslot(task.time, [task]));
490+ } else if (task.time === timeslots[i].time) {
491+ timeslots[i].events.push(task);
492+ } else {
493+ timeslots.splice(i, 0, newTimeslot(task.time, [task]));
494+ }
495+}
496+
497+function removeAllFrom (f, timeslot) {
498+ timeslot.events = removeAll(f, timeslot.events);
499+}
500+
501+function binarySearch (t, sortedArray) { // eslint-disable-line complexity
502+ var lo = 0;
503+ var hi = sortedArray.length;
504+ var mid, y;
505+
506+ while (lo < hi) {
507+ mid = Math.floor((lo + hi) / 2);
508+ y = sortedArray[mid];
509+
510+ if (t === y.time) {
511+ return mid
512+ } else if (t < y.time) {
513+ hi = mid;
514+ } else {
515+ lo = mid + 1;
516+ }
517+ }
518+ return hi
519+}
520+
521+var newTimeslot = function (t, events) { return ({ time: t, events: events }); };
522+
523+var propagateTask =
524+ curry3(function (run, value, sink) { return new PropagateTask(run, value, sink); });
525+
526+var eventTask =
527+ curry2(function (value, sink) { return propagateTask(runEvent, value, sink); });
528+
529+var endTask = function (sink) { return propagateTask(runEnd, void 0, sink); };
530+
531+var PropagateTask = function PropagateTask (run, value, sink) {
532+ var active = true;
533+ this.sink = sink;
534+
535+ this.dispose = function () { active = false; };
536+ this.run = function (t) {
537+ if (!active) { return }
538+
539+ run(t, value, sink);
540+ };
541+};
542+
543+function runEvent (time, value, sink) {
544+ sink.event(time)(value);
545+}
546+
547+function runEnd (time, value, sink) {
548+ sink.end(time, value);
549+}
550+
551+var defaultScheduler = new Scheduler(new ClockTimer(), new Timeline());
552+
553+var scheduleTasks = curry2(function (tasks, scheduler) {
554+ var scheduledTasks = tasks.map(function (task) { return scheduler.asap(task); });
555+
556+ return {
557+ dispose: function () { return scheduledTasks.forEach(function (task) { return task.dispose(); }); }
558+ }
559+});
560+
561+var SettableDisposable = function SettableDisposable () {
562+ this.disposable = void 0;
563+ this.disposed = false;
564+ this.result = void 0;
565+};
566+
567+SettableDisposable.prototype.setDisposable = function setDisposable (disposable) {
568+ this.disposable = disposable;
569+
570+ if (this.disposed) {
571+ this.result = disposable.dispose();
572+ }
573+};
574+
575+SettableDisposable.prototype.dispose = function dispose () {
576+ if (this.disposed) {
577+ return this.result
578+ }
579+
580+ this.disposed = true;
581+
582+ if (this.disposable !== void 0) {
583+ this.result = this.disposable.dispose();
584+ }
585+
586+ return this.result
587+};
588+
589+function runEffects (stream, scheduler) {
590+ return runSourceEffects(stream.source, scheduler)
591+}
592+
593+var runSourceEffects = function (source, scheduler) { return runSource(source, scheduler); };
594+
595+function runSource (source, scheduler) {
596+ var disposable = new SettableDisposable();
597+ var observer = new RunEffectsSink(disposable);
598+
599+ disposable.setDisposable(source.run(observer)(scheduler));
600+
601+ return {}
602+}
603+
604+var RunEffectsSink = function RunEffectsSink (disposable) {
605+ this._disposable = disposable;
606+ this.active = true;
607+};
608+
609+RunEffectsSink.prototype.event = function event (t) {
610+ return function (x) {}
611+};
612+
613+RunEffectsSink.prototype.end = function end (t) {
614+ this.active = false;
615+ Promise.resolve(this._disposable).then(function (d) { return d.dispose(); });
616+};
617+
618+var drain = function (stream) { return function () { return runEffects(stream, defaultScheduler); }; };
619+
620+var LinkedList = function LinkedList () {
621+ this.head = null;
622+ this.length = 0;
623+};
624+
625+LinkedList.prototype.add = function add (x) {
626+ if (this.head !== null) {
627+ this.head.prev = x;
628+ x.next = this.head;
629+ }
630+ this.head = x;
631+ ++this.length;
632+};
633+
634+LinkedList.prototype.remove = function remove (x) { // eslint-disable-linecomplexity
635+ --this.length;
636+ if (x === this.head) {
637+ this.head = this.head.next;
638+ }
639+ if (x.next !== null) {
640+ x.next.prev = x.prev;
641+ x.next = null;
642+ }
643+ if (x.prev !== null) {
644+ x.prev.next = x.next;
645+ x.prev = null;
646+ }
647+};
648+
649+LinkedList.prototype.isEmpty = function isEmpty () {
650+ return this.length === 0
651+};
652+
653+LinkedList.prototype.dispose = function dispose () {
654+ if (this.isEmpty()) { return }
655+
656+ var x = this.head;
657+ this.head = null;
658+ this.length = 0;
659+
660+ while (x !== null) {
661+ x.dispose();
662+ x = x.next;
663+ }
664+};
665+
666+var Stream = function Stream (source) {
667+ this.source = source;
668+};
669+
670+/** @license MIT License (c) copyright 2010-2016 original author or authors */
671+/** @author Brian Cavalier */
672+/** @author John Hann */
673+
674+var flatMap =
675+ curry2(function (stream, f) { return mergeMapConcurrently(f, Infinity, stream); });
676+
677+var mergeConcurrently = curry2(function (concurrency, stream) { return mergeMapConcurrently(id, concurrency, stream); });
678+
679+var join =
680+ mergeConcurrently(Infinity);
681+
682+var mergeMapConcurrently = curry3(function (f, concurrency, stream) { return new Stream(new MergeConcurrently(f, concurrency, stream.source)); });
683+
684+var MergeConcurrently = function MergeConcurrently (f, concurrency, source) {
685+ this.f = f;
686+ this.concurrency = concurrency;
687+ this.source = source;
688+};
689+
690+MergeConcurrently.prototype.run = function run (sink) {
691+ var this$1 = this;
692+
693+ return function (scheduler) { return new Outer(this$1.f, this$1.concurrency, this$1.source, sink, scheduler); }
694+};
695+
696+var Outer = function Outer (f, concurrency, source, sink, scheduler) {
697+ this.f = f;
698+ this.concurrency = concurrency;
699+ this.sink = sink;
700+ this.scheduler = scheduler;
701+ this.pending = [];
702+ this.current = new LinkedList();
703+ this.disposable = new MemoizedDisposable(source.run(this)(scheduler));
704+ this.active = true;
705+};
706+
707+Outer.prototype.event = function event (t) {
708+ var this$1 = this;
709+
710+ return function (x) { return this$1._addInner(t, x); }
711+};
712+
713+Outer.prototype._addInner = function _addInner (t, x) {
714+ if (this.current.length < this.concurrency) {
715+ this._startInner(t, x);
716+ } else {
717+ this.pending.push(x);
718+ }
719+};
720+
721+Outer.prototype._startInner = function _startInner (t, x) {
722+ try {
723+ this._initInner(t, x);
724+ } catch (e) {
725+ this.error(t, e);
726+ }
727+};
728+
729+Outer.prototype._initInner = function _initInner (t, x) {
730+ var innerSink = new Inner(t, this, this.sink);
731+ innerSink.disposable = mapAndRun(this.f, x, innerSink, this.scheduler);
732+ this.current.add(innerSink);
733+};
734+
735+Outer.prototype.end = function end (t) {
736+ this.active = false;
737+ this.disposable.dispose();
738+ this._checkEnd(t);
739+};
740+
741+Outer.prototype.dispose = function dispose () {
742+ this.active = false;
743+ this.pending.length = 0;
744+ this.disposable.dispose();
745+ this.current.dispose();
746+};
747+
748+Outer.prototype._endInner = function _endInner (t, inner) {
749+ this.current.remove(inner);
750+ inner.dispose();
751+
752+ if (this.pending.length === 0) {
753+ this._checkEnd(t);
754+ } else {
755+ this._startInner(t, this.pending.shift());
756+ }
757+};
758+
759+Outer.prototype._checkEnd = function _checkEnd (t) {
760+ if (!this.active && this.current.isEmpty()) {
761+ this.sink.end(t);
762+ }
763+};
764+
765+var mapAndRun = function (f, x, sink, scheduler) { return f(x).source.run(sink)(scheduler); };
766+
767+var Inner = function Inner (time, outer, sink) {
768+ this.prev = this.next = null;
769+ this.time = time;
770+ this.outer = outer;
771+ this.sink = sink;
772+ this.disposable = void 0;
773+};
774+
775+Inner.prototype.event = function event (t) {
776+ var this$1 = this;
777+
778+ return function (x) { return this$1.sink.event(Math.max(t, this$1.time))(x); }
779+};
780+
781+Inner.prototype.end = function end (t) {
782+ this.outer._endInner(Math.max(t, this.time), this);
783+};
784+
785+Inner.prototype.dispose = function dispose () {
786+ return this.disposable.dispose()
787+};
788+
789+var IndexSink = function IndexSink (i, sink) {
790+ this.sink = sink;
791+ this.index = i;
792+ this.active = true;
793+ this.value = void 0;
794+};
795+
796+IndexSink.prototype.event = function event (t) {
797+ var this$1 = this;
798+
799+ return function (x) {
800+ if (!this$1.active) { return }
801+
802+ this$1.value = x;
803+ this$1.sink.event(t)(this$1);
804+ }
805+};
806+
807+IndexSink.prototype.end = function end (t) {
808+ if (!this.active) { return }
809+
810+ this.active = false;
811+ this.sink.end(t, { index: this.index });
812+};
813+
814+/** @license MIT License (c) copyright 2010-2016 original author or authors */
815+/** @author Brian Cavalier */
816+/** @author John Hann */
817+
818+var combine2 = function (f) { return function (s1) { return function (s2) { return combineArray(f, [s1, s2]); }; }; };
819+var combine3 = function (f) { return function (s1) { return function (s2) { return function (s3) { return combineArray(f, [s1, s2, s3]); }; }; }; };
820+var combine4 = function (f) { return function (s1) { return function (s2) { return function (s3) { return function (s4) { return combineArray(f, [s1, s2, s3, s4]); }; }; }; }; };
821+var combine5 = function (f) { return function (s1) { return function (s2) { return function (s3) { return function (s4) { return function (s5) { return combineArray(f, [s1, s2, s3, s4, s5]); }; }; }; }; }; };
822+
823+function combineArray (f, streams) {
824+ return new Stream(combineSources(f, streams))
825+}
826+
827+function combineSources (f, streams) {
828+ return new Combine(f, map(getSource, streams))
829+}
830+
831+function getSource (stream) {
832+ return stream.source
833+}
834+
835+function Combine (f, sources) {
836+ this.f = f;
837+ this.sources = sources;
838+}
839+
840+Combine.prototype.run = function (sink) {
841+ var this$1 = this;
842+
843+ return function (scheduler) {
844+ var l = this$1.sources.length;
845+ var disposables = new Array(l);
846+ var sinks = new Array(l);
847+
848+ var mergeSink = new CombineSink(disposables, sinks, sink, this$1.f);
849+
850+ for (var indexSink, i = 0; i < l; ++i) {
851+ indexSink = sinks[i] = new IndexSink(i, mergeSink);
852+ disposables[i] = this$1.sources[i].run(indexSink)(scheduler);
853+ }
854+
855+ return disposeAll(disposables)
856+ }
857+};
858+
859+function CombineSink (disposables, sinks, sink, f) {
860+ var this$1 = this;
861+
862+ this.sink = sink;
863+ this.disposables = disposables;
864+ this.sinks = sinks;
865+ this.f = f;
866+
867+ var l = sinks.length;
868+ this.awaiting = l;
869+ this.values = new Array(l);
870+ this.hasValue = new Array(l);
871+
872+ for (var i = 0; i < l; ++i) {
873+ this$1.hasValue[i] = false;
874+ }
875+
876+ this.activeCount = sinks.length;
877+}
878+
879+CombineSink.prototype.event = function (t) {
880+ var this$1 = this;
881+
882+ return function (indexedValue) {
883+ var i = indexedValue.index;
884+ var awaiting = this$1._updateReady(i);
885+
886+ this$1.values[i] = indexedValue.value;
887+ if (awaiting === 0) {
888+ var value = tail(this$1.values).reduce(function (f, x) { return f(x); }, this$1.f(this$1.values[0]));
889+ this$1.sink.event(t)(value);
890+ }
891+ }
892+};
893+
894+CombineSink.prototype._updateReady = function (index) {
895+ if (this.awaiting > 0) {
896+ if (!this.hasValue[index]) {
897+ this.hasValue[index] = true;
898+ this.awaiting -= 1;
899+ }
900+ }
901+ return this.awaiting
902+};
903+
904+CombineSink.prototype.end = function (t, indexedValue) {
905+ this.disposables[indexedValue.index].dispose();
906+
907+ if (--this.activeCount === 0) {
908+ this.sink.end(t);
909+ }
910+};
911+
912+/** @license MIT License (c) copyright 2010-2016 original author or authors */
913+/** @author Brian Cavalier */
914+/** @author John Hann */
915+
916+/**
917+ * @param {Array} streams array of stream to merge
918+ * @returns {Stream} stream containing events from all input observables
919+ * in time order. If two events are simultaneous they will be merged in
920+ * arbitrary order.
921+ */
922+function merge (streams) {
923+ return new Stream(mergeSources(streams))
924+}
925+
926+/**
927+ * This implements fusion/flattening for merge. It will
928+ * fuse adjacent merge operations. For example:
929+ * - a.merge(b).merge(c) effectively becomes merge(a, b, c)
930+ * - merge(a, merge(b, c)) effectively becomes merge(a, b, c)
931+ * It does this by concatenating the sources arrays of
932+ * any nested Merge sources, in effect "flattening" nested
933+ * merge operations into a single merge.
934+ */
935+function mergeSources (streams) {
936+ return new Merge(reduce(appendSources, [], streams))
937+}
938+
939+function appendSources (sources, stream) {
940+ var source = stream.source;
941+ return source instanceof Merge
942+ ? sources.concat(source.sources)
943+ : sources.concat(source)
944+}
945+
946+function Merge (sources) {
947+ this.sources = sources;
948+}
949+
950+Merge.prototype.run = function (sink, scheduler) {
951+ var this$1 = this;
952+
953+ var l = this.sources.length;
954+ var disposables = new Array(l);
955+ var sinks = new Array(l);
956+
957+ var mergeSink = new MergeSink(disposables, sinks, sink);
958+
959+ for (var indexSink, i = 0; i < l; ++i) {
960+ indexSink = sinks[i] = new IndexSink(i, mergeSink);
961+ disposables[i] = this$1.sources[i].run(indexSink, scheduler);
962+ }
963+
964+ return disposeAll(disposables)
965+};
966+
967+function MergeSink (disposables, sinks, sink) {
968+ this.sink = sink;
969+ this.disposables = disposables;
970+ this.activeCount = sinks.length;
971+}
972+
973+MergeSink.prototype.event = function (t, indexValue) {
974+ this.sink.event(t, indexValue.value);
975+};
976+
977+MergeSink.prototype.end = function (t, indexedValue) {
978+ dispose.tryDispose(t, this.disposables[indexedValue.index], this.sink);
979+ if (--this.activeCount === 0) {
980+ this.sink.end(t, indexedValue.value);
981+ }
982+};
983+
984+var concat = function (s1) { return function (s2) { return continueWith(function () { return s2; })(s1); }; };
985+
986+var continueWith = function (f) { return function (stream) { return new Stream(new ContinueWith(f, stream.source)); }; };
987+
988+function ContinueWith (f, source) {
989+ this.f = f;
990+ this.source = source;
991+}
992+
993+ContinueWith.prototype.run = function (sink) {
994+ var this$1 = this;
995+
996+ return function (scheduler) {
997+ return new ContinueWithSink(this$1.f, this$1.source, sink, scheduler)
998+ }
999+};
1000+
1001+function ContinueWithSink (f, source, sink, scheduler) {
1002+ this.f = f;
1003+ this.sink = sink;
1004+ this.scheduler = scheduler;
1005+ this.active = true;
1006+ this.disposable = new MemoizedDisposable(source.run(this)(scheduler));
1007+}
1008+
1009+ContinueWithSink.prototype.event = function (t) {
1010+ var this$1 = this;
1011+
1012+ return function (x) {
1013+ if (!this$1.active) {
1014+ return
1015+ }
1016+ this$1.sink.event(t)(x);
1017+ }
1018+};
1019+
1020+ContinueWithSink.prototype.end = function (t, x) {
1021+ if (!this.active) {
1022+ return
1023+ }
1024+
1025+ this.disposable.dispose();
1026+ this._startNext(t, x, this.sink);
1027+};
1028+
1029+ContinueWithSink.prototype._startNext = function (t, x, sink) {
1030+ this._continue(this.f, x, sink);
1031+};
1032+
1033+ContinueWithSink.prototype._continue = function (f, x, sink) {
1034+ return f(x).source.run(sink)(this.scheduler)
1035+};
1036+
1037+ContinueWithSink.prototype.dispose = function () {
1038+ this.active = false;
1039+ return this.disposable.dispose()
1040+};
1041+
1042+/**
1043+ * Given a stream of streams, return a new stream that adopts the behavior
1044+ * of the most recent inner stream.
1045+ * @param {Stream} stream of streams on which to switch
1046+ * @returns {Stream} switching stream
1047+ */
1048+function switchLatest (stream) {
1049+ return new Stream(new Switch(stream.source))
1050+}
1051+
1052+function Switch (source) {
1053+ this.source = source;
1054+}
1055+
1056+Switch.prototype.run = function (sink) {
1057+ var this$1 = this;
1058+
1059+ return function (scheduler) {
1060+ var switchSink = new SwitchSink(sink, scheduler);
1061+ return disposeAll([switchSink, this$1.source.run(switchSink)(scheduler)])
1062+ }
1063+};
1064+
1065+function SwitchSink (sink, scheduler) {
1066+ this.sink = sink;
1067+ this.scheduler = scheduler;
1068+ this.current = null;
1069+ this.ended = false;
1070+}
1071+
1072+SwitchSink.prototype.event = function (t) {
1073+ var this$1 = this;
1074+
1075+ return function (stream) {
1076+ this$1._disposeCurrent(t); // TODO: capture the result of this dispose
1077+ this$1.current = new Segment(t, Infinity, this$1, this$1.sink);
1078+ this$1.current.disposable = stream.source.run(this$1.current)(this$1.scheduler);
1079+ }
1080+};
1081+
1082+SwitchSink.prototype.end = function (t, x) {
1083+ this.ended = true;
1084+ this._checkEnd(t, x);
1085+};
1086+
1087+SwitchSink.prototype.dispose = function () {
1088+ return this._disposeCurrent(this.scheduler.now())
1089+};
1090+
1091+SwitchSink.prototype._disposeCurrent = function (t) {
1092+ if (this.current !== null) {
1093+ return this.current._dispose(t)
1094+ }
1095+};
1096+
1097+SwitchSink.prototype._disposeInner = function (t, inner) {
1098+ inner._dispose(t); // TODO: capture the result of this dispose
1099+ if (inner === this.current) {
1100+ this.current = null;
1101+ }
1102+};
1103+
1104+SwitchSink.prototype._checkEnd = function (t, x) {
1105+ if (this.ended && this.current === null) {
1106+ this.sink.end(t, x);
1107+ }
1108+};
1109+
1110+SwitchSink.prototype._endInner = function (t, x, inner) {
1111+ this._disposeInner(t, inner);
1112+ this._checkEnd(t, x);
1113+};
1114+
1115+function Segment (min, max, outer, sink) {
1116+ this.min = min;
1117+ this.max = max;
1118+ this.outer = outer;
1119+ this.sink = sink;
1120+ this.disposable = emptyDisposable;
1121+}
1122+
1123+Segment.prototype.event = function (t) {
1124+ var this$1 = this;
1125+
1126+ return function (x) {
1127+ if (t < this$1.max) {
1128+ this$1.sink.event(Math.max(t, this$1.min))(x);
1129+ }
1130+ }
1131+};
1132+
1133+Segment.prototype.end = function (t, x) {
1134+ this.outer._endInner(Math.max(t, this.min), x, this);
1135+};
1136+
1137+Segment.prototype._dispose = function (t) {
1138+ this.max = t;
1139+ this.disposable.dispose();
1140+};
1141+
1142+var skipRepeatsWith = function (equals) { return function (stream) { return new Stream(new SkipRepeats(equals, stream)); }; };
1143+
1144+var SkipRepeats = function SkipRepeats (equals, source) {
1145+ this.equals = equals;
1146+ this.source = source;
1147+};
1148+
1149+SkipRepeats.prototype.run = function run (sink) {
1150+ var this$1 = this;
1151+
1152+ return function (scheduler) { return this$1.source.run(new SkipRepeatsSink(this$1.equals, sink), scheduler); }
1153+};
1154+
1155+var SkipRepeatsSink = function SkipRepeatsSink (equals, sink) {
1156+ this.equals = equals;
1157+ this.value = void 0;
1158+ this.init = true;
1159+};
1160+
1161+SkipRepeatsSink.prototype.event = function event (t) {
1162+ var this$1 = this;
1163+
1164+ return function (x) {
1165+ if (this$1.init) {
1166+ this$1.init = false;
1167+ this$1.value = x;
1168+ this$1.sink.event(t, x);
1169+ } else if (!this$1.equals(this$1.value)(x)) {
1170+ this$1.value = x;
1171+ this$1.sink.event(t)(x);
1172+ }
1173+ }
1174+};
1175+
1176+SkipRepeatsSink.prototype.end = function end (t) {
1177+ this.sink.end(t);
1178+};
1179+
1180+var delay = function (delayTime) { return function (stream) { return delayTime <= 0 ? stream : new Stream(new Delay(delayTime, stream.source)); }; };
1181+
1182+var Delay = function Delay (dt, source) {
1183+ this.dt = dt;
1184+ this.source = source;
1185+};
1186+
1187+Delay.prototype.run = function run (sink) {
1188+ var this$1 = this;
1189+
1190+ return function (scheduler) {
1191+ var delaySink = new DelaySink(this$1.dt, sink, scheduler);
1192+ return disposeAll([delaySink, this$1.source.run(delaySink)(scheduler)])
1193+ }
1194+};
1195+
1196+var DelaySink = function DelaySink (dt, sink, scheduler) {
1197+ this.dt = dt;
1198+ this.sink = sink;
1199+ this.scheduler = scheduler;
1200+};
1201+
1202+DelaySink.prototype.dispose = function dispose () {
1203+ var this$1 = this;
1204+
1205+ this.scheduler.cancelAll(function (task) { return task.sink === this$1.sink; });
1206+};
1207+
1208+DelaySink.prototype.event = function event (t) {
1209+ var this$1 = this;
1210+
1211+ return function (x) { return this$1.scheduler.delay(this$1.dt)(eventTask(x)(this$1.sink)); }
1212+};
1213+
1214+DelaySink.prototype.end = function end (t) {
1215+ this.scheduler.delay(this.dt)(endTask(this.sink));
1216+};
1217+
1218+var dispose$1 = function (disposable) { return disposable.dispose(); };
1219+
1220+var emptyDisposable$1 = {
1221+ dispose: function dispose () {}
1222+};
1223+
1224+var MulticastDisposable = function MulticastDisposable (source, sink) {
1225+ this.source = source;
1226+ this.sink = sink;
1227+ this.disposed = false;
1228+};
1229+
1230+MulticastDisposable.prototype.dispose = function dispose () {
1231+ if (this.disposed) {
1232+ return
1233+ }
1234+ this.disposed = true;
1235+ var remaining = this.source.remove(this.sink);
1236+ return remaining === 0 && this.source._dispose()
1237+};
1238+
1239+var MulticastSource = function MulticastSource (source) {
1240+ this.source = source;
1241+ this.sinks = [];
1242+ this._disposable = emptyDisposable$1;
1243+};
1244+
1245+MulticastSource.prototype.run = function run (sink) {
1246+ var this$1 = this;
1247+
1248+ return function (scheduler) {
1249+ var n = this$1.add(sink, scheduler);
1250+ if (n === 1) {
1251+ this$1._disposable = this$1.source.run(this$1)(scheduler);
1252+ }
1253+ return new MulticastDisposable(this$1, sink)
1254+ }
1255+};
1256+
1257+MulticastSource.prototype._dispose = function _dispose () {
1258+ var disposable = this._disposable;
1259+ this._disposable = emptyDisposable$1;
1260+ return Promise.resolve(disposable).then(dispose$1)
1261+};
1262+
1263+MulticastSource.prototype.add = function add (sink) {
1264+ this.sinks = append(sink, this.sinks);
1265+ return this.sinks.length
1266+};
1267+
1268+MulticastSource.prototype.remove = function remove$1 (sink) {
1269+ var i = findIndex(sink, this.sinks);
1270+ // istanbul ignore next
1271+ if (i >= 0) {
1272+ this.sinks = remove(i, this.sinks);
1273+ }
1274+
1275+ return this.sinks.length
1276+};
1277+
1278+MulticastSource.prototype.event = function event (time) {
1279+ var this$1 = this;
1280+
1281+ return function (value) {
1282+ var s = this$1.sinks;
1283+ if (s.length === 1) {
1284+ return s[0].event(time)(value)
1285+ }
1286+ for (var i = 0; i < s.length; ++i) {
1287+ s[i].event(time)(value);
1288+ }
1289+ }
1290+};
1291+
1292+MulticastSource.prototype.end = function end (time) {
1293+ var s = this.sinks;
1294+ for (var i = 0; i < s.length; ++i) {
1295+ s[i].end(time);
1296+ }
1297+};
1298+
1299+var HoldSource = (function (MulticastSource$$1) {
1300+ function HoldSource (source, bufferSize) {
1301+ MulticastSource$$1.call(this, source);
1302+ this.bufferSize = bufferSize;
1303+ this.has = false;
1304+ this.buffer = [];
1305+ }
1306+
1307+ if ( MulticastSource$$1 ) HoldSource.__proto__ = MulticastSource$$1;
1308+ HoldSource.prototype = Object.create( MulticastSource$$1 && MulticastSource$$1.prototype );
1309+ HoldSource.prototype.constructor = HoldSource;
1310+
1311+ HoldSource.prototype.add = function add (sink, scheduler) {
1312+ if (this.has) {
1313+ pushEvents(this.buffer, sink, scheduler);
1314+ }
1315+
1316+ return MulticastSource$$1.prototype.add.call(this, sink, scheduler)
1317+ };
1318+
1319+ HoldSource.prototype.event = function event (time) {
1320+ var this$1 = this;
1321+
1322+ return function (value) {
1323+ this$1.has = true;
1324+ this$1.buffer = dropAndAppend(value, this$1.buffer, this$1.bufferSize);
1325+
1326+ return MulticastSource$$1.prototype.event.call(this$1, time)(value)
1327+ }
1328+ };
1329+
1330+ return HoldSource;
1331+}(MulticastSource));
1332+
1333+function pushEvents (buffer, sink, scheduler) {
1334+ var length = buffer.length;
1335+
1336+ for (var i = 0; i < length; ++i) {
1337+ sink.event(scheduler.now(), buffer[i]);
1338+ }
1339+}
1340+
1341+function dropAndAppend (value, buffer, bufferSize) {
1342+ if (buffer.length === bufferSize) {
1343+ return append(value, drop(1, buffer))
1344+ }
1345+
1346+ return append(value, buffer)
1347+}
1348+
1349+function multicast (stream) {
1350+ var source = stream.source;
1351+
1352+ return source instanceof MulticastSource
1353+ ? stream
1354+ : new Stream(new MulticastSource(source))
1355+}
1356+
1357+var hold = function (bufferSize) { return function (stream) { return new Stream(new HoldSource(stream.source, bufferSize)); }; };
1358+
1359+/* */
1360+
1361+exports.createDisposable = createDisposable;
1362+exports.emptyDisposable = emptyDisposable;
1363+exports.disposeAll = disposeAll;
1364+exports.defaultScheduler = defaultScheduler;
1365+exports.scheduleTasks = scheduleTasks;
1366+exports.endTask = endTask;
1367+exports.eventTask = eventTask;
1368+exports.drain = drain;
1369+exports.flatMap = flatMap;
1370+exports.mergeConcurrently = mergeConcurrently;
1371+exports.join = join;
1372+exports.mergeMapConcurrently = mergeMapConcurrently;
1373+exports.combine2 = combine2;
1374+exports.combine3 = combine3;
1375+exports.combine4 = combine4;
1376+exports.combine5 = combine5;
1377+exports.merge = merge;
1378+exports.concat = concat;
1379+exports.continueWith = continueWith;
1380+exports.switch = switchLatest;
1381+exports.skipRepeatsWith = skipRepeatsWith;
1382+exports.delay = delay;
1383+exports.multicast = multicast;
1384+exports.hold = hold;
src/Control/Stream.purs+318−40
@@ -1,59 +1,337 @@
11module Control.Stream
2− ( module Control.Stream.Stream
3− , module Control.Stream.Disposable
4− , module Control.Stream.Scheduler
5− , module Control.Stream.Sink
6− , module Control.Stream.Time
7− ) where
8−
9−import Control.Stream.Stream
10− (STREAM
2+ ( STREAM
113 , EffStream
12− , Stream(..)
13− , just
14− , empty
15− , never
16− , periodic
4+ , Stream
5+ , Source
6+ , EventFn
7+ , EndFn
8+ , RunFn
9+ , Sink
10+ , Scheduler
11+ , Task
12+ , ScheduledTask
13+ , Disposable
14+ , Time
15+ -- Scheduler-related functions and values
16+ , defaultScheduler
17+ , eventTask
18+ , endTask
19+ , createDisposable
20+ , emptyDisposable
21+ , disposeAll
22+ , scheduleTasks
23+ -- Stream-related helpers
24+ , createStream
25+ , createSink
1726 , createCombinator
1827 , createEventCombinator
1928 , createEndCombinator
29+ , getSource
30+ , runSource
31+ -- Combinators
2032 , drain
2133 , tapEvent
2234 , tapEnd
23− , fromArray
2435 , filter
25− , take
26− , skip
27− , constant
28− , continueWith
29− , concat
30− , startWith
31− , scan
32− , loop
33− , chain
3436 , mergeConcurrently
35− , join
3637 , mergeMapConcurrently
37− , concatMap
38− , switch
38+ , join
3939 , combine2
4040 , combine3
4141 , combine4
4242 , combine5
43− , combineArray
43+ , continueWith
44+ , concat
4445 , merge
45− , skipRepeatsWith
46+ , switch
47+ , constant
48+ , scan
49+ , startWith
50+ , multicast
51+ , hold
4652 , skipRepeats
47− , until
48− , since
49− , during
50− , sample
51− , debounce
52− , throttle
53+ , skipRepeatsWith
5354 , delay
54− , multicast
55+ , sample
56+ -- Stream factories
57+ , just
58+ , fromArray
59+ , empty
60+ , never
61+ , periodic
5562 )
56−import Control.Stream.Disposable (Disposable, emptyDisposable)
57−import Control.Stream.Scheduler (Scheduler(..), Task, ScheduledTask, scheduler, scheduleTasks, eventTask, endTask)
58−import Control.Stream.Sink (Sink(..))
59−import Control.Stream.Time (Time)
63+ where
64+
65+import Control.Alt ((<|>))
66+import Control.Applicative (class Applicative)
67+import Control.Apply (class Apply)
68+import Control.Bind (class Bind)
69+import Control.Category (id)
70+import Control.Monad (class Monad)
71+import Control.Monad.Eff (Eff, Pure, runPure)
72+import Control.Monad.Eff.Ref (Ref, modifyRef', newRef, readRef)
73+import Control.Monad.Eff.Unsafe (unsafeCoerceEff, unsafePerformEff)
74+import Control.MonadPlus (class Alt, class Plus)
75+import Data.Eq (class Eq, eq)
76+import Data.Function (flip, ($))
77+import Data.Functor (class Functor, map)
78+import Data.Maybe (Maybe(Just, Nothing), fromJust, isJust)
79+import Data.Monoid (class Monoid)
80+import Data.Semigroup (class Semigroup)
81+import Data.Unit (Unit, unit)
82+import Partial.Unsafe (unsafePartial)
83+
84+newtype Time = Time Int
85+
86+foreign import data STREAM :: !
87+
88+type EffStream e a = Eff (stream :: STREAM | e) a
89+
90+newtype Stream a = Stream { source :: Source a }
91+
92+newtype Source a = Source { run :: RunFn a }
93+
94+type RunFn a = Sink a -> Scheduler -> Disposable
95+type EventFn a = Time -> a -> Unit
96+type EndFn = Time -> Unit
97+
98+newtype Sink a = Sink
99+ { event :: Time -> a -> Unit
100+ , end :: Time -> Unit
101+ }
102+
103+newtype Scheduler = Scheduler
104+ { now :: Pure Time
105+ , asap :: Task -> ScheduledTask
106+ , delay :: Number -> Task -> ScheduledTask
107+ , periodic :: Number -> Task -> ScheduledTask
108+ , schedule :: Number -> Number -> Task -> ScheduledTask
109+ , cancel :: ScheduledTask -> Unit
110+ , cancelAll :: (ScheduledTask -> Boolean) -> Unit
111+ }
112+
113+type Task =
114+ { run :: Time -> Unit
115+ , dispose :: Pure Unit
116+ }
117+
118+type ScheduledTask =
119+ { run :: Pure Unit
120+ , dispose :: Pure Unit
121+ }
122+
123+type Disposable = { dispose :: Pure Unit }
124+
125+instance functorStream :: Functor Stream where
126+ map = _map
127+
128+instance applyStream :: Apply Stream where
129+ apply = combine2 id
130+
131+instance applicativeStream :: Applicative Stream where
132+ pure = just
133+
134+instance bindStream :: Bind Stream where
135+ bind = flatMap
136+
137+instance monadStream :: Monad Stream
138+
139+instance semigroupStream :: Semigroup (Stream a) where
140+ append = concat
141+
142+instance altStream :: Alt Stream where
143+ alt = \s1 s2 -> merge [s1, s2]
144+
145+instance monoidStream :: Monoid (Stream a) where
146+ mempty = empty
147+
148+instance plusStream :: Plus Stream where
149+ empty = empty
150+
151+-- Stream-related helpers
152+createStream :: forall a. (Sink a -> Scheduler -> Disposable) -> Stream a
153+createStream run = Stream { source: Source { run } }
154+
155+getSource :: forall a. Stream a -> Source a
156+getSource (Stream stream) = stream.source
157+
158+runSource :: forall a. Source a -> Sink a -> Scheduler -> Disposable
159+runSource (Source source) sink scheduler = source.run sink scheduler
160+
161+runStream :: forall a. Stream a -> Sink a -> Scheduler -> Disposable
162+runStream stream sink scheduler = runSource (getSource stream) sink scheduler
163+
164+createSink :: forall a. (Time -> a -> Unit) -> (Time -> Unit) -> Sink a
165+createSink event end = Sink { event, end }
166+
167+createCombinator :: forall a b. (Sink b -> Scheduler -> EventFn a) -> (Sink b -> Scheduler -> EndFn) -> Stream a -> Stream b
168+createCombinator event end stream = createStream runCombinator
169+ where
170+ runCombinator :: Sink b -> Scheduler -> Disposable
171+ runCombinator sink scheduler =
172+ runStream stream (createSink (event sink scheduler) (end sink scheduler)) scheduler
173+
174+createEventCombinator :: forall a b. (Sink b -> Scheduler -> EventFn a) -> Stream a -> Stream b
175+createEventCombinator event stream = createCombinator event end stream
176+ where
177+ end (Sink sink) (Scheduler scheduler) time = sink.end time
178+
179+createEndCombinator :: forall a. (Sink a -> Scheduler -> EndFn) -> Stream a -> Stream a
180+createEndCombinator end stream = createCombinator event end stream
181+ where
182+ event :: Sink a -> Scheduler -> EventFn a
183+ event (Sink sink) scheduler time value = sink.event time value
184+
185+-- Stream factories
186+just :: forall a. a -> Stream a
187+just a = createStream (runJust a)
188+
189+runJust :: forall a. a -> Sink a -> Scheduler -> Disposable
190+runJust a sink scheduler =
191+ scheduleTasks [ eventTask a sink, endTask sink ] scheduler
192+
193+empty :: forall a. Stream a
194+empty = createStream \sink scheduler -> scheduleTasks [endTask sink] scheduler
195+
196+never :: forall a. Stream a
197+never = createStream \sink scheduler -> emptyDisposable
198+
199+-- TODO: remove fromArray because it's not a real event stream
200+-- replace with a fromArray combinator
201+fromArray :: forall a. Array a -> Stream a
202+fromArray arr = createStream (runFromArray arr)
203+
204+runFromArray :: forall a. Array a -> Sink a -> Scheduler -> Disposable
205+runFromArray arr sink scheduler = scheduleTasks tasks scheduler
206+ where
207+ tasks :: Array Task
208+ tasks = eventTasks <|> [ (endTask sink) ]
209+
210+ eventTasks :: Array Task
211+ eventTasks = map (flip eventTask sink) arr
212+
213+periodic :: Number -> Stream Unit
214+periodic period = createStream (runPeriodic period)
215+
216+runPeriodic :: Number -> Sink Unit -> Scheduler -> Disposable
217+runPeriodic period sink (Scheduler scheduler) = { dispose: scheduledTask.dispose }
218+ where
219+ scheduledTask = scheduler.periodic period (eventTask unit sink)
220+
221+-- combinators
222+_map :: forall a b. (a -> b) -> Stream a -> Stream b
223+_map f stream = createEventCombinator mapEvent stream
224+ where
225+ mapEvent (Sink sink) (Scheduler scheduler) time value = sink.event time (f value)
226+
227+filter :: forall a. (a -> Boolean) -> Stream a -> Stream a
228+filter predicate stream = createEventCombinator event stream
229+ where
230+ event (Sink sink) (Scheduler scheduler) time value = if predicate value
231+ then sink.event time value
232+ else unit
233+
234+tapEvent :: forall e a. (a -> EffStream e Unit) -> Stream a -> Stream a
235+tapEvent f stream = createEventCombinator event stream
236+ where
237+ event (Sink sink) (Scheduler scheduler) time value = sink.event time value
238+ where -- find a better way to perform these side effects
239+ x = unsafePerformEff (f value)
240+
241+tapEnd :: forall e a. EffStream e Unit -> Stream a -> Stream a
242+tapEnd f stream = createEndCombinator end stream
243+ where
244+ end (Sink sink) (Scheduler scheduler) time = sink.end time
245+ where -- find a better way to perform these side effects
246+ x = unsafePerformEff f
247+
248+startWith :: forall a. a -> Stream a -> Stream a
249+startWith value stream = concat (just value) stream
250+
251+constant :: forall a b. b -> Stream a -> Stream b
252+constant value stream = createEventCombinator constantEvent stream
253+ where
254+ constantEvent (Sink sink) (Scheduler scheduler) time x = sink.event time value
255+
256+scan :: forall a b. (b -> a -> b) -> b -> Stream a -> Stream b
257+scan f seed stream = startWith seed $ createEventCombinator scanEvent stream
258+ where
259+ state :: State b
260+ state = createState seed
261+
262+ scanEvent :: Sink b -> Scheduler -> Time -> a -> Unit
263+ scanEvent (Sink sink) (Scheduler scheduler) time value = sink.event time (state.set \acc -> f acc value)
264+
265+skipRepeats :: forall a. (Eq a) => Stream a -> Stream a
266+skipRepeats = skipRepeatsWith eq
267+
268+sample :: forall a b c. (a -> b -> c) -> Stream a -> Stream b -> Stream c
269+sample f sampler stream = createStream $ runSample (createState Nothing)
270+ where
271+ runSample :: State (Maybe b) -> Sink c -> Scheduler -> Disposable
272+ runSample state sink scheduler = disposeAll
273+ [ runStream stream (createHoldSink state) scheduler
274+ , runStream sampler (createSampleSink state sink f) scheduler
275+ ]
276+
277+createHoldSink :: forall a. State (Maybe a) -> Sink a
278+createHoldSink state = createSink event end
279+ where
280+ event time value = always unit (state.set \_ -> Just value)
281+ end time = unit
282+
283+createSampleSink :: forall a b c. State (Maybe b) -> Sink c -> (a -> b -> c) -> Sink a
284+createSampleSink state (Sink sink) f = createSink event end
285+ where
286+ end time = sink.end time
287+ event time value =
288+ if isJust (runPure state.get)
289+ then sink.event time $ f value (unsafePartial $ fromJust (runPure state.get))
290+ else unit
291+
292+always :: forall a b. a -> b -> a
293+always a b = a
294+
295+-- find a better way to perform these side effects
296+type State a = { get:: Pure a, set :: (a -> a) -> a }
297+
298+createState :: forall a. a -> State a
299+createState seed = { set, get }
300+ where
301+ ref :: Ref a
302+ ref = unsafePerformEff $ unsafeCoerceEff $ newRef seed
303+
304+ set :: (a -> a) -> a
305+ set f = unsafePerformEff $ unsafeCoerceEff $
306+ modifyRef' ref \x -> { state: (f x), value: (f x) }
307+
308+ get :: Pure a
309+ get = unsafeCoerceEff $ readRef ref
310+
311+-- Foreign imports
312+-- Scheduler-related
313+foreign import defaultScheduler :: Scheduler
314+foreign import eventTask :: forall a. a -> Sink a -> Task
315+foreign import endTask :: forall a. Sink a -> Task
316+foreign import createDisposable :: forall a. (a -> Unit) -> a -> Disposable
317+foreign import emptyDisposable :: Disposable
318+foreign import disposeAll :: Array Disposable -> Disposable
319+foreign import scheduleTasks :: Array Task -> Scheduler -> Disposable
320+-- combinators
321+foreign import drain :: forall e a. Stream a -> EffStream e Unit
322+foreign import mergeConcurrently :: forall a. Int -> Stream (Stream a) -> Stream a
323+foreign import mergeMapConcurrently :: forall a b. (a -> Stream b) -> Stream a -> Stream b
324+foreign import combine2 :: forall a b c. (a -> b -> c) -> Stream a -> Stream b -> Stream c
325+foreign import combine3 :: forall a b c d. (a -> b -> c -> d) -> Stream a -> Stream b -> Stream c -> Stream d
326+foreign import combine4 :: forall a b c d e. (a -> b -> c -> d -> e) -> Stream a -> Stream b -> Stream c -> Stream d -> Stream e
327+foreign import combine5 :: forall a b c d e f. (a -> b -> c -> d -> e -> f) -> Stream a -> Stream b -> Stream c -> Stream d -> Stream e -> Stream f
328+foreign import join :: forall a. Stream (Stream a) -> Stream a
329+foreign import flatMap :: forall a b. Stream a -> (a -> Stream b) -> Stream b
330+foreign import continueWith :: forall a. (Unit -> Stream a) -> Stream a -> Stream a
331+foreign import concat :: forall a. Stream a -> Stream a -> Stream a
332+foreign import merge :: forall a. Array (Stream a) -> Stream a
333+foreign import switch :: forall a. Stream (Stream a) -> Stream a
334+foreign import multicast :: forall a. Stream a -> Stream a
335+foreign import hold :: forall a. Int -> Stream a -> Stream a
336+foreign import skipRepeatsWith :: forall a. (a -> a -> Boolean) -> Stream a -> Stream a
337+foreign import delay :: forall a. Number -> Stream a -> Stream a
src/Control/Stream/Stream.jsdeleted−1244
@@ -1,1244 +0,0 @@
1−var ControlStreamScheduler = require('../Control.Stream.Scheduler')
2−var ControlStreamStream = require('../Control.Stream.Stream')
3−
4−exports.drain = function (stream) { return function () { return runSource(stream, ControlStreamScheduler.scheduler) } }
5−
6−exports.subscribe = function (event) {
7− return function (end) {
8− return function (stream) {
9− return function () {
10− var disposable = new SettableDisposable()
11−
12− var observer = { event: event, end: end }
13−
14− var d = stream.run(observer)(ControlStreamScheduler.scheduler)
15−
16− disposable.setDisposable(d)
17−
18− return {}
19− }
20− }
21− }
22−}
23−
24−function runSource (source, scheduler) {
25− var disposable = new SettableDisposable()
26−
27− function event (t) {
28− return function (x) {
29− return {}
30− }
31− }
32−
33− function end (t) {
34− disposable.dispose()
35− return {}
36− }
37−
38− var observer = { event: event, end: end }
39−
40− var d = source.run(observer)(scheduler)
41−
42− disposable.setDisposable(d)
43−
44− return {}
45−}
46−
47−var SettableDisposable = function SettableDisposable () {
48− this.disposable = void 0
49− this.disposed = false
50− this.result = void 0
51−}
52−
53−SettableDisposable.prototype.setDisposable = function setDisposable (disposable) {
54− this.disposable = disposable
55−
56− if (this.disposed) {
57− this.result = disposable.dispose()
58− }
59−}
60−
61−SettableDisposable.prototype.dispose = function dispose () {
62− if (this.disposed) {
63− return this.result
64− }
65−
66− this.disposed = true
67−
68− if (this.disposable !== void 0) {
69− this.result = this.disposable.dispose()
70− }
71−
72− return this.result
73−}
74−
75−exports.fromArray = function (array) {
76− return function (stream) {
77− return new FromArray(array, stream)
78− }
79−}
80−
81−function FromArray (array, stream) {
82− this.array = array
83− this.stream = stream
84−}
85−
86−FromArray.prototype.run = function (sink) {
87− var that = this
88−
89− return function (scheduler) {
90− return that.stream.run(new FromArraySink(sink, that.array))(scheduler)
91− }
92−}
93−
94−function FromArraySink (sink, array) {
95− this.sink = sink
96− this.array = array
97−}
98−
99−FromArraySink.prototype.event = function (time) {
100− var array = this.array
101− var sink = this.sink
102− return function (x) {
103− var value = array.shift()
104−
105− if (value) {
106− sink.event(time)(value)
107− } else {
108− sink.end(time)
109− }
110− }
111−}
112−
113−FromArraySink.prototype.end = function (time) {
114− this.sink.end(time)
115−}
116−
117−var LinkedList = function LinkedList () {
118− this.head = null
119− this.length = 0
120−}
121−
122−LinkedList.prototype.add = function add (x) {
123− if (this.head !== null) {
124− this.head.prev = x
125− x.next = this.head
126− }
127− this.head = x
128− ++this.length
129−}
130−
131−LinkedList.prototype.remove = function remove (x) { // eslint-disable-line complexity
132− --this.length
133− if (x === this.head) {
134− this.head = this.head.next
135− }
136− if (x.next !== null) {
137− x.next.prev = x.prev
138− x.next = null
139− }
140− if (x.prev !== null) {
141− x.prev.next = x.next
142− x.prev = null
143− }
144−}
145−
146−LinkedList.prototype.isEmpty = function isEmpty () {
147− return this.length === 0
148−}
149−
150−LinkedList.prototype.dispose = function dispose () {
151− if (this.isEmpty()) { return }
152−
153− var x = this.head
154− this.head = null
155− this.length = 0
156−
157− while (x !== null) {
158− x.dispose()
159− x = x.next
160− }
161−}
162−
163−exports.chain = function (f) {
164− return function (stream) {
165− return mergeMapConcurrently(f)(Infinity)(stream)
166− }
167−}
168−
169−exports.mergeConcurrently = mergeConcurrently
170−
171−function mergeConcurrently (concurrency) {
172− return function (stream) {
173− return mergeMapConcurrently(function (x) { return x })(concurrency)(stream)
174− }
175−}
176−
177−exports.join = mergeConcurrently(Infinity)
178−
179−exports.mergeMapConcurrently = mergeMapConcurrently
180−
181−function mergeMapConcurrently (f) {
182− return function (concurrency) {
183− return function (stream) {
184− var mstream = new MergeConcurrently(f, concurrency, stream)
185−
186− mstream.run.bind(mstream)
187−
188− return mstream
189− }
190− }
191−}
192−
193−function MergeConcurrently (f, concurrency, source) {
194− this.f = f
195− this.concurrency = concurrency
196− this.source = source
197−}
198−
199−MergeConcurrently.prototype.run = function run (sink) {
200− var this$1 = this
201−
202− return function (scheduler) { return new Outer(this$1.f, this$1.concurrency, this$1.source, sink, scheduler) }
203−}
204−
205−var Outer = function Outer (f, concurrency, source, sink, scheduler) {
206− this.f = f
207− this.concurrency = concurrency
208− this.sink = sink
209− this.scheduler = scheduler
210− this.pending = []
211− this.current = new LinkedList()
212−
213− var disposed = false
214− var disposable = source.run(this)(scheduler)
215−
216− this.disposable = {
217− dispose: function () {
218− if (disposed) return
219−
220− disposed = true
221− disposable.dispose()
222− }
223− }
224−
225− this.active = true
226−}
227−
228−Outer.prototype.event = function event (t) {
229− var this$1 = this
230−
231− return function (x) { return this$1._addInner(t, x) }
232−}
233−
234−Outer.prototype._addInner = function _addInner (t, x) {
235− if (this.current.length < this.concurrency) {
236− this._startInner(t, x)
237− } else {
238− this.pending.push(x)
239− }
240−}
241−
242−Outer.prototype._startInner = function _startInner (t, x) {
243− this._initInner(t, x)
244−}
245−
246−Outer.prototype._initInner = function _initInner (t, x) {
247− var innerSink = new Inner(t, this, this.sink)
248− innerSink.disposable = mapAndRun(this.f, x, innerSink, this.scheduler)
249− this.current.add(innerSink)
250−}
251−
252−Outer.prototype.end = function end (t) {
253− this.active = false
254− this.disposable.dispose()
255− this._checkEnd(t)
256−}
257−
258−Outer.prototype.dispose = function dispose () {
259− this.active = false
260− this.pending.length = 0
261− this.disposable.dispose()
262− this.current.dispose()
263−}
264−
265−Outer.prototype._endInner = function _endInner (t, inner) {
266− this.current.remove(inner)
267− inner.dispose()
268−
269− if (this.pending.length === 0) {
270− this._checkEnd(t)
271− } else {
272− this._startInner(t, this.pending.shift())
273− }
274−}
275−
276−Outer.prototype._checkEnd = function _checkEnd (t) {
277− if (!this.active && this.current.isEmpty()) {
278− this.sink.end(t)
279− }
280−}
281−
282−var mapAndRun = function (f, x, sink, scheduler) { return f(x).run(sink)(scheduler) }
283−
284−var Inner = function Inner (time, outer, sink) {
285− this.prev = this.next = null
286− this.time = time
287− this.outer = outer
288− this.sink = sink
289− this.disposable = void 0
290−}
291−
292−Inner.prototype.event = function event (t) {
293− var this$1 = this
294−
295− return function (x) { return this$1.sink.event(Math.max(t, this$1.time))(x) }
296−}
297−
298−Inner.prototype.end = function end (t) {
299− this.outer._endInner(Math.max(t, this.time), this)
300−}
301−
302−Inner.prototype.dispose = function dispose () {
303− return this.disposable.dispose()
304−}
305−
306−exports.switch = function switchLatest (stream) {
307− return new Switch(stream)
308−}
309−
310−function Switch (source) {
311− this.source = source
312−}
313−
314−Switch.prototype.run = function (sink) {
315− var this$1 = this
316−
317− return function (scheduler) {
318− var switchSink = new SwitchSink(sink, scheduler)
319− var disposable = this$1.source.run(switchSink)(scheduler)
320−
321− return {
322− dispose: function () {
323− switchSink.dispose()
324− disposable.dispose()
325− }
326− }
327− }
328−}
329−
330−function SwitchSink (sink, scheduler) {
331− this.sink = sink
332− this.scheduler = scheduler
333− this.current = null
334− this.ended = false
335−}
336−
337−SwitchSink.prototype.event = function (t) {
338− var this$1 = this
339−
340− return function (stream) {
341− this$1._disposeCurrent(t) // TODO: capture the result of this dispose
342− this$1.current = new Segment(t, Infinity, this$1, this$1.sink)
343− this$1.current.disposable = stream.run(this$1.current)(this$1.scheduler)
344− }
345−}
346−
347−SwitchSink.prototype.end = function (t, x) {
348− this.ended = true
349− this._checkEnd(t, x)
350−}
351−
352−SwitchSink.prototype.dispose = function () {
353− return this._disposeCurrent(this.scheduler.now())
354−}
355−
356−SwitchSink.prototype._disposeCurrent = function (t) {
357− if (this.current !== null) {
358− return this.current._dispose(t)
359− }
360−}
361−
362−SwitchSink.prototype._disposeInner = function (t, inner) {
363− inner._dispose(t) // TODO: capture the result of this dispose
364− if (inner === this.current) {
365− this.current = null
366− }
367−}
368−
369−SwitchSink.prototype._checkEnd = function (t, x) {
370− if (this.ended && this.current === null) {
371− this.sink.end(t, x)
372− }
373−}
374−
375−SwitchSink.prototype._endInner = function (t, x, inner) {
376− this._disposeInner(t, inner)
377− this._checkEnd(t, x)
378−}
379−
380−function Segment (min, max, outer, sink) {
381− this.min = min
382− this.max = max
383− this.outer = outer
384− this.sink = sink
385− this.disposable = { dispose: Function.prototype }
386−}
387−
388−Segment.prototype.event = function (t) {
389− var this$1 = this
390−
391− return function (x) {
392− if (t < this$1.max) {
393− this$1.sink.event(Math.max(t, this$1.min))(x)
394− }
395− }
396−}
397−
398−Segment.prototype.end = function (t, x) {
399− this.outer._endInner(Math.max(t, this.min), x, this)
400−}
401−
402−Segment.prototype._dispose = function (t) {
403− this.max = t
404− this.disposable.dispose()
405−}
406−
407−exports.continueWith = function continueWith (f) {
408− return function (stream) {
409− return new ContinueWith(f, stream)
410− }
411−}
412−
413−function ContinueWith (f, source) {
414− this.f = f
415− this.source = source
416−}
417−
418−ContinueWith.prototype.run = function (sink) {
419− var that = this
420− return function (scheduler) {
421− return new ContinueWithSink(that.f, that.source, sink, scheduler)
422− }
423−}
424−
425−function ContinueWithSink (f, source, sink, scheduler) {
426− this.f = f
427− this.sink = sink
428− this.scheduler = scheduler
429− this.active = true
430− this.disposable = source.run(this)(scheduler)
431−}
432−
433−ContinueWithSink.prototype.event = function (t) {
434− var that = this
435−
436− return function (x) {
437− if (!that.active) {
438− return
439− }
440− that.sink.event(t)(x)
441− }
442−}
443−
444−ContinueWithSink.prototype.end = function (t, x) {
445− if (!this.active) {
446− return
447− }
448−
449− this.disposable.dispose()
450−
451− this._startNext(t, x, this.sink)
452−}
453−
454−ContinueWithSink.prototype._startNext = function (t, x, sink) {
455− try {
456− this.disposable = this._continue(this.f, x, sink)
457− } catch (e) {
458− sink.error(t, e)
459− }
460−}
461−
462−ContinueWithSink.prototype._continue = function (f, x, sink) {
463− return f(x).run(sink)(this.scheduler)
464−}
465−
466−ContinueWithSink.prototype.dispose = function () {
467− this.active = false
468− return this.disposable.dispose()
469−}
470−
471−exports.combine2 = function (f) { return function (s1) { return function (s2) { return combineArray(f, [s1, s2]) } } }
472−exports.combine3 = function (f) { return function (s1) { return function (s2) { return function (s3) { return combineArray(f, [s1, s2, s3]) } } } }
473−exports.combine4 = function (f) { return function (s1) { return function (s2) { return function (s3) { return function (s4) { return combineArray(f, [s1, s2, s3, s4]) } } } } }
474−exports.combine5 = function (f) { return function (s1) { return function (s2) { return function (s3) { return function (s4) { return function (s5) { return combineArray(f, [s1, s2, s3, s4, s5]) } } } } } }
475−
476−exports.combineArray = function (streams) {
477− return combineArray(Array, streams)
478−}
479−
480−function combineArray (f, streams) {
481− return new Combine(f, streams)
482−}
483−
484−function Combine (f, sources) {
485− this.f = f
486− this.sources = sources
487−}
488−
489−Combine.prototype.run = function (sink) {
490− var this$1 = this
491−
492− return function (scheduler) {
493− var l = this$1.sources.length
494− var disposables = new Array(l)
495− var sinks = new Array(l)
496−
497− var mergeSink = new CombineSink(disposables, sinks, sink, this$1.f)
498−
499− for (var indexSink, i = 0; i < l; ++i) {
500− indexSink = sinks[i] = new IndexSink(i, mergeSink)
501− disposables[i] = this$1.sources[i].run(indexSink)(scheduler)
502− }
503−
504− return {
505− dispose: function () {
506− disposables.forEach(function (d) {
507− d.dispose()
508− })
509− }
510− }
511− }
512−}
513−
514−function CombineSink (disposables, sinks, sink, f) {
515− var this$1 = this
516−
517− this.sink = sink
518− this.disposables = disposables
519− this.sinks = sinks
520− this.f = f
521−
522− var l = sinks.length
523− this.awaiting = l
524− this.values = new Array(l)
525− this.hasValue = new Array(l)
526−
527− for (var i = 0; i < l; ++i) {
528− this$1.hasValue[i] = false
529− }
530−
531− this.activeCount = sinks.length
532−}
533−
534−CombineSink.prototype.event = function (t) {
535− var this$1 = this
536−
537− return function (indexedValue) {
538− var i = indexedValue.index
539− var awaiting = this$1._updateReady(i)
540−
541− this$1.values[i] = indexedValue.value
542− if (awaiting === 0) {
543− var value = tail(this$1.values).reduce(function (f, x) { return f(x) }, this$1.f(this$1.values[0]))
544− this$1.sink.event(t)(value)
545− }
546− }
547−}
548−
549−CombineSink.prototype._updateReady = function (index) {
550− if (this.awaiting > 0) {
551− if (!this.hasValue[index]) {
552− this.hasValue[index] = true
553− this.awaiting -= 1
554− }
555− }
556− return this.awaiting
557−}
558−
559−CombineSink.prototype.end = function (t, indexedValue) {
560− this.disposables[indexedValue.index].dispose()
561−
562− if (--this.activeCount === 0) {
563− this.sink.end(t)
564− }
565−}
566−
567−var IndexSink = function IndexSink (i, sink) {
568− this.sink = sink
569− this.index = i
570− this.active = true
571− this.value = void 0
572−}
573−
574−IndexSink.prototype.event = function event (t) {
575− var this$1 = this
576−
577− return function (x) {
578− if (!this$1.active) { return }
579−
580− this$1.value = x
581− this$1.sink.event(t)(this$1)
582− }
583−}
584−
585−IndexSink.prototype.end = function end (t) {
586− if (!this.active) { return }
587−
588− this.active = false
589− this.sink.end(t, { index: this.index })
590−}
591−
592−function drop (n, a) { // eslint-disable-line complexity
593− if (n < 0) {
594− throw new TypeError('n must be >= 0')
595− }
596−
597− var l = a.length
598− if (n === 0 || l === 0) {
599− return a
600− }
601−
602− if (n >= l) {
603− return []
604− }
605−
606− return unsafeDrop(n, a, l - n)
607−}
608−
609−// unsafeDrop :: Int -> [a] -> Int -> [a]
610−// Internal helper for drop
611−function unsafeDrop (n, a, l) {
612− var b = new Array(l)
613− for (var i = 0; i < l; ++i) {
614− b[i] = a[n + i]
615− }
616− return b
617−}
618−
619−// tail :: [a] -> [a]
620−// drop head element
621−function tail (a) {
622− return drop(1, a)
623−}
624−
625−exports.merge = function merge (streams) {
626− return mergeSources(streams)
627−}
628−
629−/**
630− * This implements fusion/flattening for merge. It will
631− * fuse adjacent merge operations. For example:
632− * - a.merge(b).merge(c) effectively becomes merge(a, b, c)
633− * - merge(a, merge(b, c)) effectively becomes merge(a, b, c)
634− * It does this by concatenating the sources arrays of
635− * any nested Merge sources, in effect "flattening" nested
636− * merge operations into a single merge.
637− */
638−function mergeSources (streams) {
639− return new Merge(reduce(appendSources, [], streams))
640−}
641−
642−function appendSources (sources, stream) {
643− return stream instanceof Merge
644− ? sources.concat(stream.sources)
645− : sources.concat(stream)
646−}
647−
648−function Merge (sources) {
649− this.sources = sources
650−}
651−
652−Merge.prototype.run = function (sink) {
653− var this$1 = this
654−
655− return function (scheduler) {
656− var l = this.sources.length
657− var disposables = new Array(l)
658− var sinks = new Array(l)
659−
660− var mergeSink = new MergeSink(disposables, sinks, sink)
661−
662− for (var indexSink, i = 0; i < l; ++i) {
663− indexSink = sinks[i] = new IndexSink(i, mergeSink)
664− disposables[i] = this$1.sources[i].run(indexSink, scheduler)
665− }
666−
667− return all(disposables)
668− }
669−}
670−
671−function all (disposables) {
672− return {
673− dispose: function () {
674− disposables.forEach(function (d) {
675− d.dispose()
676− })
677− }
678− }
679−}
680−
681−function MergeSink (disposables, sinks, sink) {
682− this.sink = sink
683− this.disposables = disposables
684− this.activeCount = sinks.length
685−}
686−
687−MergeSink.prototype.event = function (t) {
688− var that = this
689− return function (indexValue) {
690− that.sink.event(t)(indexValue.value)
691− }
692−}
693−
694−MergeSink.prototype.end = function (t, indexedValue) {
695− this.disposables[indexedValue.index].dispose()
696− if (--this.activeCount === 0) {
697− this.sink.end(t, indexedValue.value)
698− }
699−}
700−
701−function reduce (f, z, a) {
702− var r = z
703− for (var i = 0, l = a.length; i < l; ++i) {
704− r = f(r, a[i], i)
705− }
706− return r
707−}
708−
709−exports.until = function takeUntil (signal) {
710− return function (stream) {
711− return new Until(signal, stream)
712− }
713−}
714−
715−exports.since = function skipUntil (signal) {
716− return function (stream) {
717− return new Since(signal, stream)
718− }
719−}
720−
721−function Until (maxSignal, source) {
722− this.maxSignal = maxSignal
723− this.source = source
724−}
725−
726−Until.prototype.run = function (sink) {
727− var that = this
728− return function (scheduler) {
729− var min = new Bound(-Infinity, sink)
730− var max = new UpperBound(that.maxSignal, sink, scheduler)
731− var disposable = that.source.run(new TimeWindowSink(min, max, sink), scheduler)
732−
733− return all([min, max, disposable])
734− }
735−}
736−
737−function Since (minSignal, source) {
738− this.minSignal = minSignal
739− this.source = source
740−}
741−
742−Since.prototype.run = function (sink) {
743− var that = this
744− return function (scheduler) {
745− var min = new LowerBound(that.minSignal, sink, scheduler)
746− var max = new Bound(Infinity, sink)
747− var disposable = that.source.run(new TimeWindowSink(min, max, sink))(scheduler)
748−
749− return all([min, max, disposable])
750− }
751−}
752−
753−function Bound (value, sink) {
754− this.value = value
755− this.sink = sink
756−}
757−
758−Bound.prototype.event = noop
759−Bound.prototype.end = noop
760−Bound.prototype.dispose = noop
761−
762−function TimeWindowSink (min, max, sink) {
763− this.min = min
764− this.max = max
765− this.sink = sink
766−}
767−
768−TimeWindowSink.prototype.event = function (t, x) {
769− var that = this
770− return function (x) {
771− if (t >= that.min.value && t < that.max.value) {
772− that.sink.event(t)(x)
773− }
774− }
775−}
776−
777−TimeWindowSink.prototype.end = function (time) {
778− this.sink.end(time)
779−}
780−
781−function LowerBound (signal, sink, scheduler) {
782− this.value = Infinity
783− this.sink = sink
784− this.disposable = signal.run(this)(scheduler)
785−}
786−
787−LowerBound.prototype.event = function (t /*, x */) {
788− return function () {
789− if (t < this.value) {
790− this.value = t
791− }
792− }
793−}
794−
795−LowerBound.prototype.end = noop
796−
797−LowerBound.prototype.dispose = function () {
798− return this.disposable.dispose()
799−}
800−
801−function UpperBound (signal, sink, scheduler) {
802− this.value = Infinity
803− this.sink = sink
804− this.disposable = signal.run(this)(scheduler)
805−}
806−
807−UpperBound.prototype.event = function (t) {
808− var that = this
809−
810− return function (x) {
811− if (t < this.value) {
812− that.value = t
813− that.sink.end(t)
814− }
815− }
816−}
817−
818−UpperBound.prototype.end = noop
819−
820−UpperBound.prototype.dispose = function () {
821− return this.disposable.dispose()
822−}
823−
824−function noop () { }
825−
826−exports.throttle = function throttle (period) {
827− return function (stream) {
828− return throttleSource(period, stream)
829− }
830−}
831−
832−function throttleSource (period, source) {
833− return source instanceof Throttle
834− ? fuseThrottle(period, source)
835− : new Throttle(period, source)
836−}
837−
838−function fuseThrottle (period, source) {
839− return new Throttle(Math.max(period, source.period), source.source)
840−}
841−
842−function Throttle (period, source) {
843− this.period = period
844− this.source = source
845−}
846−
847−Throttle.prototype.run = function (sink) {
848− var that = this
849− return function (scheduler) {
850− return that.source.run(new ThrottleSink(that.period, sink), scheduler)
851− }
852−}
853−
854−function ThrottleSink (period, sink) {
855− this.time = 0
856− this.period = period
857− this.sink = sink
858−}
859−
860−ThrottleSink.prototype.event = function (t) {
861− var that = this
862− return function (x) {
863− if (t >= this.time) {
864− that.time = t + this.period
865− that.sink.event(t)(x)
866− }
867− }
868−}
869−
870−ThrottleSink.prototype.end = function (t) { this.sink.end(t) }
871−
872−exports.debounce = function debounce (period) {
873− return function (stream) {
874− return new Debounce(period, stream)
875− }
876−}
877−
878−function Debounce (dt, source) {
879− this.dt = dt
880− this.source = source
881−}
882−
883−Debounce.prototype.run = function (sink) {
884− var that = this
885− return function (scheduler) {
886− return new DebounceSink(that.dt, that.source, sink, scheduler)
887− }
888−}
889−
890−function DebounceSink (dt, source, sink, scheduler) {
891− this.dt = dt
892− this.sink = sink
893− this.scheduler = scheduler
894− this.value = void 0
895− this.timer = null
896−
897− var sourceDisposable = source.run(this)(scheduler)
898− this.disposable = all([this, sourceDisposable])
899−}
900−
901−DebounceSink.prototype.event = function (t) {
902− var that = this
903− return function (x) {
904− that._clearTimer()
905− that.value = x
906− var task = ControlStreamScheduler.eventTask(that.sink)(x)
907− that.timer = this.scheduler.delay(this.dt, task)
908− }
909−}
910−
911−DebounceSink.prototype.end = function (t, x) {
912− if (this._clearTimer()) {
913− this.sink.event(t, this.value)
914− this.value = void 0
915− }
916− this.sink.end(t, x)
917−}
918−
919−DebounceSink.prototype.dispose = function () {
920− this._clearTimer()
921−}
922−
923−DebounceSink.prototype._clearTimer = function () {
924− if (this.timer === null) {
925− return false
926− }
927− this.timer.dispose()
928− this.timer = null
929− return true
930−}
931−
932−exports.delay = function delay (delayTime) {
933− return function (stream) {
934− return delayTime <= 0 ? stream : new Delay(delayTime, stream)
935− }
936−}
937−
938−function Delay (dt, source) {
939− this.dt = dt
940− this.source = source
941−}
942−
943−Delay.prototype.run = function (sink) {
944− var that = this
945−
946− return function (scheduler) {
947− var delaySink = new DelaySink(that.dt, sink, scheduler)
948− return all([delaySink, that.source.run(delaySink)(scheduler)])
949− }
950−}
951−
952−function DelaySink (dt, sink, scheduler) {
953− this.dt = dt
954− this.sink = sink
955− this.scheduler = scheduler
956−}
957−
958−DelaySink.prototype.dispose = function () {
959− var self = this
960− this.scheduler.cancelAll(function (task) {
961− return task.sink === self.sink
962− })
963−}
964−
965−DelaySink.prototype.event = function (t) {
966− var that = this
967− return function (x) {
968− that.scheduler.delay(that.dt)(ControlStreamScheduler.eventTask(that.sink)(x))
969− }
970−}
971−
972−DelaySink.prototype.end = function (t, x) {
973− this.scheduler.delay(this.dt)(ControlStreamScheduler.endTask(this.sink))
974−}
975−
976−var MulticastDisposable = function MulticastDisposable (source, sink) {
977− this.source = source
978− this.sink = sink
979− this.disposed = false
980−}
981−
982−MulticastDisposable.prototype.dispose = function dispose () {
983− if (this.disposed) {
984− return
985− }
986− this.disposed = true
987− var remaining = this.source.remove(this.sink)
988− return remaining === 0 && this.source._dispose()
989−}
990−
991−var dispose = function (disposable) { return disposable.dispose() }
992−
993−var emptyDisposable = {
994− dispose: function dispose$1 () { }
995−}
996−
997−function MulticastSource (source) {
998− this.source = source
999− this.sinks = []
1000− this._disposable = emptyDisposable
1001−}
1002−
1003−MulticastSource.prototype.run = function run (sink) {
1004− var that = this
1005− return function (scheduler) {
1006− var n = that.add(sink)
1007− if (n === 1) {
1008− that._disposable = that.source.run(that)(scheduler)
1009− }
1010− return new MulticastDisposable(that, sink)
1011− }
1012−}
1013−
1014−MulticastSource.prototype._dispose = function _dispose () {
1015− var disposable = this._disposable
1016− this._disposable = emptyDisposable
1017− return Promise.resolve(disposable).then(dispose)
1018−}
1019−
1020−MulticastSource.prototype.add = function add (sink) {
1021− this.sinks = append(sink, this.sinks)
1022− return this.sinks.length
1023−}
1024−
1025−function append (x, a) {
1026− var l = a.length
1027− var b = new Array(l + 1)
1028− for (var i = 0; i < l; ++i) {
1029− b[i] = a[i]
1030− }
1031−
1032− b[l] = x
1033− return b
1034−}
1035−
1036−MulticastSource.prototype.remove = function remove$1 (sink) {
1037− var i = findIndex(sink, this.sinks)
1038− // istanbul ignore next
1039− if (i >= 0) {
1040− this.sinks = remove(i, this.sinks)
1041− }
1042−
1043− return this.sinks.length
1044−}
1045−
1046−function findIndex (x, a) {
1047− for (var i = 0, l = a.length; i < l; ++i) {
1048− if (x === a[i]) {
1049− return i
1050− }
1051− }
1052− return -1
1053−}
1054−
1055−function remove (i, a) { // eslint-disable-line complexity
1056− if (i < 0) {
1057− throw new TypeError('i must be >= 0')
1058− }
1059−
1060− var l = a.length
1061− if (l === 0 || i >= l) { // exit early if index beyond end of array
1062− return a
1063− }
1064−
1065− if (l === 1) { // exit early if index in bounds and length === 1
1066− return []
1067− }
1068−
1069− return unsafeRemove(i, a, l - 1)
1070−}
1071−
1072−// unsafeRemove :: Int -> [a] -> Int -> [a]
1073−// Internal helper to remove element at index
1074−function unsafeRemove (i, a, l) {
1075− var b = new Array(l)
1076− var j
1077− for (j = 0; j < i; ++j) {
1078− b[j] = a[j]
1079− }
1080− for (j = i; j < l; ++j) {
1081− b[j] = a[j + 1]
1082− }
1083−
1084− return b
1085−}
1086−
1087−MulticastSource.prototype.event = function event (time) {
1088− var that = this
1089− return function (value) {
1090− var s = that.sinks
1091− if (s.length === 1) {
1092− return s[0].event(time)(value)
1093− }
1094− for (var i = 0; i < s.length; ++i) {
1095− s[i].event(time)(value)
1096− }
1097− }
1098−}
1099−
1100−MulticastSource.prototype.end = function end (time) {
1101− var s = this.sinks
1102− for (var i = 0; i < s.length; ++i) {
1103− s[i].end(time)
1104− }
1105−}
1106−
1107−MulticastSource.prototype.until = function (signal) {
1108− return exports.until(signal)(this)
1109−}
1110−
1111−exports.multicast = function multicast (stream) {
1112− return new MulticastSource(stream)
1113−}
1114−
1115−function __extends (d, b) { // eslint-disable-line complexity
1116− for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]
1117− function __ () { this.constructor = d }
1118− d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __())
1119−}
1120−
1121−var HoldSubjectSource = (function (_super) {
1122− __extends(HoldSubjectSource, _super)
1123− function HoldSubjectSource (source, bufferSize) {
1124− var _this = _super.call(this, source) || this
1125− _this.has = false
1126− _this.buffer = []
1127− _this.bufferSize = bufferSize
1128− return _this
1129− }
1130− HoldSubjectSource.prototype.add = function (sink) {
1131− if (this.has) {
1132− pushEvents(this.buffer, sink)
1133− }
1134− return _super.prototype.add.call(this, sink)
1135− }
1136− HoldSubjectSource.prototype.event = function (time) {
1137− var that = this
1138− return function (value) {
1139− that.has = true
1140− that.buffer = dropAndAppend(value, that.buffer, that.bufferSize)
1141− return _super.prototype.event.call(that, time)(value)
1142− }
1143− }
1144− return HoldSubjectSource
1145−}(MulticastSource))
1146−
1147−function pushEvents (buffer, sink) {
1148− var length = buffer.length
1149− for (var i = 0; i < length; ++i) {
1150− sink.event(ControlStreamScheduler.scheduler.now(), buffer[i])
1151− }
1152−}
1153−
1154−function dropAndAppend (value, buffer, bufferSize) {
1155− if (buffer.length === bufferSize) {
1156− return append(value, drop(1, buffer))
1157− }
1158− return append(value, buffer)
1159−}
1160−
1161−exports.hold = function hold (bufferSize) {
1162− return function (stream) {
1163− return new HoldSubjectSource(stream, bufferSize)
1164− }
1165−}
1166−
1167−exports.toSubject = function (stream) {
1168− return exports.multicast(stream)
1169−}
1170−
1171−exports.toHoldSubject = exports.hold
1172−
1173−exports.fromSubject = function (subject) {
1174− return subject
1175−}
1176−
1177−exports.subjectEvent = function (value) {
1178− return function (subject) {
1179− ControlStreamScheduler.eventTask(subject)(value)
1180− return subject
1181− }
1182−}
1183−
1184−exports.subjectEnd = function (value) {
1185− return function (subject) {
1186− subject.end(Date.now())
1187− return subject
1188− }
1189−}
1190−
1191−exports.proxy = function (value) {
1192− var stream = new ProxyStream(value)
1193−
1194− function attach (original) {
1195− stream.attach(original)
1196− return original
1197− }
1198−
1199− return { attach: attach, stream: stream }
1200−}
1201−
1202−var ProxyStream = (function (_super) {
1203− __extends(ProxyStream, _super)
1204− function ProxyStream (value) {
1205− var _this = _super.call(this, ControlStreamStream.never, 1) || this
1206− _this.attached = false
1207− _this.running = false
1208− _this.buffer.push(value)
1209− return _this
1210− }
1211− ProxyStream.prototype.run = function (sink) {
1212− var that = this
1213−
1214− that.add(sink)
1215−
1216− return function (scheduler) {
1217− if (that.attached && !that.running) {
1218− that.running = true
1219− that._disposable = that.source.run(that)(scheduler)
1220− return that._disposable
1221− }
1222−
1223− return new MulticastDisposable(that, sink)
1224− }
1225− }
1226−
1227− ProxyStream.prototype.attach = function (source) {
1228− if (this.attached) throw new Error('Can only proxy 1 stream')
1229− this.attached = true
1230−
1231− this.source = source
1232−
1233− if (this.sinks.length) { this._disposable = source.run(this)(ControlStreamScheduler.scheduler) }
1234− }
1235−
1236− ProxyStream.prototype.end = function end (time) {
1237− this.attached = false
1238− this.running = false
1239−
1240− return _super.prototype.end.call(this, time)
1241− }
1242−
1243− return ProxyStream
1244−}(HoldSubjectSource))
src/Control/Stream/Stream.pursdeleted−340
@@ -1,340 +0,0 @@
1−module Control.Stream.Stream
2− ( STREAM
3− , EffStream
4− , Stream(..)
5− , just
6− , empty
7− , never
8− , periodic
9− , createCombinator
10− , createEventCombinator
11− , createEndCombinator
12− , drain
13− , tapEvent
14− , tapEnd
15− , fromArray
16− , filter
17− , take
18− , skip
19− , constant
20− , continueWith
21− , concat
22− , startWith
23− , scan
24− , loop
25− , chain
26− , mergeConcurrently
27− , join
28− , mergeMapConcurrently
29− , concatMap
30− , switch
31− , combine2
32− , combine3
33− , combine4
34− , combine5
35− , combineArray
36− , merge
37− , skipRepeatsWith
38− , skipRepeats
39− , until
40− , since
41− , during
42− , sample
43− , debounce
44− , throttle
45− , delay
46− , multicast
47− , hold
48− , Subject
49− , toSubject
50− , toHoldSubject
51− , fromSubject
52− , subjectEvent
53− , subjectEnd
54− , subscribe
55− ) where
56−
57−import Control.Alternative (class Apply)
58−import Control.Bind (class Bind)
59−import Control.Category (id)
60−import Control.Monad.Eff (Eff, Pure, runPure)
61−import Control.Monad.Eff.Ref (Ref, modifyRef', newRef, readRef)
62−import Control.Monad.Eff.Unsafe (unsafeCoerceEff, unsafePerformEff)
63−import Control.MonadPlus (class Alt, class Alternative, class MonadPlus, class Plus)
64−import Control.MonadZero (class Applicative, class MonadZero)
65−import Control.Stream.Disposable (Disposable, emptyDisposable, disposeAll)
66−import Control.Stream.Scheduler (Scheduler(..), endTask, eventTask, scheduleTasks)
67−import Control.Stream.Sink (Sink(..))
68−import Control.Stream.Stream (Stream(..), EffStream, empty, just)
69−import Control.Stream.Time (Time)
70−import Data.Eq ((==))
71−import Data.EuclideanRing ((-))
72−import Data.Functor (class Functor)
73−import Data.Maybe (Maybe(..), fromJust, isNothing)
74−import Data.Monoid (class Monoid)
75−import Data.Unit (Unit, unit)
76−import Partial.Unsafe (unsafePartial)
77−import Prelude (class Eq, class Monad, class Semigroup, eq)
78−
79−foreign import data STREAM :: !
80−
81−type EffStream e a = Eff (stream :: STREAM | e) a
82−
83−foreign import data Subject :: * -> *
84−
85−newtype Stream a = Stream { run :: Sink a -> Scheduler -> Disposable }
86−
87−instance functorStream :: Functor Stream where
88− map = mapStream
89−
90−instance applyStream :: Apply Stream where
91− apply = combine2 id
92−
93−instance applicativeStream :: Applicative Stream where
94− pure = just
95−
96−instance bindStream :: Bind Stream where
97− bind = chain
98−
99−instance monadStream :: Monad Stream
100−
101−instance semigroupStream :: Semigroup (Stream a) where
102− append = concat
103−
104−instance altStream :: Alt Stream where
105− alt = \s1 s2 -> merge [s1, s2]
106−
107−instance monoidStream :: Monoid (Stream a) where
108− mempty = empty
109−
110−instance plusStream :: Plus Stream where
111− empty = empty
112−
113−instance alternativeStream :: Alternative Stream
114−
115−instance monadZeroStream :: MonadZero Stream
116−
117−instance monadPlusStream :: MonadPlus Stream
118−
119−just :: forall a. a -> Stream a
120−just a = Stream { run } where
121− run :: Sink a -> Scheduler -> Disposable
122− run sink (Scheduler scheduler) =
123− scheduleTasks scheduler.asap [ (eventTask sink a), (endTask sink) ]
124−
125−empty :: forall a. Stream a
126−empty = Stream { run } where
127− run :: Sink a -> Scheduler -> Disposable
128− run sink (Scheduler scheduler) = scheduleTasks scheduler.asap [ endTask sink ]
129−
130−never :: forall a. Stream a
131−never = Stream { run: \sink scheduler -> emptyDisposable }
132−
133−periodic :: Number -> Stream Unit
134−periodic period = Stream { run } where
135− run :: Sink Unit -> Scheduler -> Disposable
136− run sink (Scheduler scheduler) = do
137− let task = eventTask sink unit
138− let scheduledTask = scheduler.periodic period task
139− { dispose : scheduledTask.dispose }
140−
141−createCombinator :: forall a b. (Sink b -> Time -> a -> Unit) -> (Sink b -> Time -> Unit) -> Stream a -> Stream b
142−createCombinator event end (Stream stream) = Stream { run } where
143− run :: Sink b -> Scheduler -> Disposable
144− run sink scheduler = stream.run (Sink { event: (event sink), end: (end sink) }) scheduler
145−
146−createEventCombinator :: forall a b. (Sink b -> Time -> a -> Unit) -> Stream a -> Stream b
147−createEventCombinator event stream = createCombinator event end stream where
148− end (Sink sink) time = sink.end time
149−
150−createEndCombinator :: forall a. (Sink a -> Time -> Unit) -> Stream a -> Stream a
151−createEndCombinator end stream = createCombinator event end stream where
152− event (Sink sink) time value = sink.event time value
153−
154−tapEvent :: forall e a. (a -> Eff e Unit) -> Stream a -> Stream a
155−tapEvent f stream = createEventCombinator event stream where
156− event :: Sink a -> Time -> a -> Unit
157− event (Sink sink) time value = sink.event time (always value (unsafePerformEff (f value)))
158−
159−tapEnd :: forall e a. Eff e Unit -> Stream a -> Stream a
160−tapEnd f stream = createEndCombinator end stream where
161− end :: Sink a -> Time -> Unit
162− end (Sink sink) time = sink.end (always time (unsafePerformEff f))
163−
164−take :: forall a. Int -> Stream a -> Stream a
165−take 0 stream = empty
166−take amount (Stream stream) = Stream { run } where
167− run (Sink sink) scheduler = disposable where
168− disposable = stream.run (Sink { event, end }) scheduler where
169− state :: State Int
170− state = createState amount
171−
172− event ::Time -> a -> Unit
173− event time value = do
174− let amountLeft = (getState state)
175− if amountLeft == 0
176− then unit
177− else do
178− let newAmountLeft = state.set \x -> x - 1
179− let x = sink.event time value
180− if newAmountLeft == 0
181− then sink.end (always time (runPure disposable.dispose))
182− else unit
183−
184− end time = sink.end time
185−
186−skip :: forall a. Int -> Stream a -> Stream a
187−skip 0 stream = stream
188−skip amount stream = createEventCombinator event stream where
189− state :: State Int
190− state = createState amount
191−
192− event :: Sink a -> Time -> a -> Unit
193− event (Sink sink) time value = do
194− let amountLeft = runPure state.get
195− if (amountLeft == 0)
196− then sink.event time value
197− else always unit (state.set \x -> x - 1)
198−
199−mapStream :: forall a b. (a -> b) -> Stream a -> Stream b
200−mapStream f stream = createEventCombinator event stream where
201− event :: Sink b -> Time -> a -> Unit
202− event (Sink sink) time value = sink.event time (f value)
203−
204−filter :: forall a. (a -> Boolean) -> Stream a -> Stream a
205−filter predicate stream = createEventCombinator event stream where
206− event (Sink sink) time value = if predicate value
207− then sink.event time value
208− else unit
209−
210−skipRepeatsWith :: forall a. (a -> a -> Boolean) -> Stream a -> Stream a
211−skipRepeatsWith compare stream = createEventCombinator event stream where
212− state :: State (Maybe a)
213− state = createState Nothing
214−
215− event (Sink sink) time value = do
216− let currentState = (getState state)
217− if (isNothing currentState)
218− then sink.event time value
219− else do
220− let currentValue = unsafePartial (fromJust currentState)
221− if (compare currentValue value)
222− then unit
223− else sink.event time value
224−
225−skipRepeats :: forall a. (Eq a) => Stream a -> Stream a
226−skipRepeats = skipRepeatsWith (eq)
227−
228−constant :: forall a b. b -> Stream a -> Stream b
229−constant b stream = createEventCombinator event stream where
230− event :: Sink b -> Time -> a -> Unit
231− event (Sink sink) time value = sink.event time b
232−
233−concat :: forall a. Stream a -> Stream a -> Stream a
234−concat s1 s2 = continueWith(\_ -> s2) s1
235−
236−startWith :: forall a. a -> Stream a -> Stream a
237−startWith seed stream = concat (just seed) stream
238−
239−scan :: forall a b. (b -> a -> b) -> b -> Stream a -> Stream b
240−scan f initial stream = startWith initial (createEventCombinator event stream) where
241− seed :: State b
242− seed = createState initial
243−
244− event :: Sink b -> Time -> a -> Unit
245− event (Sink sink) time value = sink.event time (seed.set \x -> f x value)
246−
247−loop :: forall a b c. (b -> a -> { seed :: b, value :: c }) -> b -> Stream a -> Stream c
248−loop f initial stream = createEventCombinator event stream where
249− seed :: State b
250− seed = createState initial
251−
252− event :: Sink c -> Time -> a -> Unit
253− event (Sink sink) time x = do
254− let seedValue = f (getState seed) x
255− sink.event time (always seedValue.value (seed.set \_ -> seedValue.seed))
256−
257−concatMap :: forall a b. (a -> Stream b) -> Stream a -> Stream b
258−concatMap f stream = mergeMapConcurrently f 1 stream
259−
260−ap :: forall a b. (Stream (a -> b)) -> Stream a -> Stream b
261−ap fs xs = combine2 (\f x -> f x) fs xs
262−
263−during :: forall a b. Stream (Stream b) -> Stream a -> Stream a
264−during timeWindow stream = until (join timeWindow) (since timeWindow stream)
265−
266−sample :: forall a b c. (a -> b -> c) -> Stream a -> Stream b -> Stream c
267−sample f (Stream sampler) (Stream stream) = Stream { run: runSample (createState Nothing) } where
268− runSample :: State (Maybe b) -> Sink c -> Scheduler -> Disposable
269− runSample state sink scheduler = disposeAll
270− [ stream.run (createHoldSink state) scheduler
271− , sampler.run (createSampleSink state sink f) scheduler
272− ]
273−
274−createHoldSink :: forall a. State (Maybe a) -> Sink a
275−createHoldSink state = Sink { event, end } where
276− event time value = always unit (state.set \_ -> Just value)
277− end time = unit
278−
279−createSampleSink :: forall a b c. State (Maybe b) -> Sink c -> (a -> b -> c) -> Sink a
280−createSampleSink state (Sink sink) f = Sink { event, end } where
281− end time = sink.end time
282− event time value =
283− if isNothing (runPure state.get)
284− then unit
285− else sink.event time (f value (unsafePartial (fromJust (runPure state.get))))
286−
287−sampleWith :: forall a b. Stream b -> Stream a -> Stream a
288−sampleWith signal stream = sample (\_ y -> y) signal stream
289−
290−-- find a better way to perform these side effects
291−always :: forall a b. a -> b -> a
292−always a b = a
293−
294−type State a = { get:: Pure a, set :: (a -> a) -> a }
295−
296−getState :: forall a. State a -> a
297−getState state = runPure state.get
298−
299−createState :: forall a. a -> State a
300−createState seed = { set, get }
301− where
302− ref :: Ref a
303− ref = unsafePerformEff (unsafeCoerceEff (newRef seed))
304−
305− set :: (a -> a) -> a
306− set f = unsafePerformEff (unsafeCoerceEff (modifyRef' ref \x -> { state: (f x), value: (f x) }))
307−
308− get :: Pure a
309− get = unsafeCoerceEff (readRef ref)
310−
311−foreign import drain :: forall e a. Stream a -> EffStream e Unit
312−foreign import subscribe :: forall e a. (a -> Eff e Unit) -> (Unit -> Eff e Unit) -> Stream a -> EffStream e Unit
313−foreign import fromArray :: forall a b. Array a -> Stream b -> Stream a
314−foreign import chain :: forall a b. Stream a -> (a -> Stream b) -> Stream b
315−foreign import mergeConcurrently :: forall a. Int -> Stream (Stream a) -> Stream a
316−foreign import join :: forall a. Stream (Stream a) -> Stream a
317−foreign import mergeMapConcurrently :: forall a b. (a -> Stream b) -> Int -> Stream a -> Stream b
318−foreign import switch :: forall a. Stream (Stream a) -> Stream a
319−foreign import continueWith :: forall a. (Unit -> Stream a) -> Stream a -> Stream a
320−foreign import combine2 :: forall a b c. (a -> b -> c) -> Stream a -> Stream b -> Stream c
321−foreign import combine3 :: forall a b c d. (a -> b -> c -> d) -> Stream a -> Stream b -> Stream c -> Stream d
322−foreign import combine4 :: forall a b c d e. (a -> b -> c -> d -> e) -> Stream a -> Stream b -> Stream c -> Stream d -> Stream e
323−foreign import combine5 :: forall a b c d e f. (a -> b -> c -> d -> e -> f) -> Stream a -> Stream b -> Stream c -> Stream d -> Stream e -> Stream f
324−foreign import combineArray :: forall a. Array (Stream a) -> Stream (Array a)
325−foreign import merge :: forall a. Array (Stream a) -> Stream a
326−foreign import until :: forall a b. Stream b -> Stream a -> Stream a
327−foreign import since :: forall a b. Stream b -> Stream a -> Stream a
328−foreign import debounce :: forall a. Number -> Stream a -> Stream a
329−foreign import throttle :: forall a. Number -> Stream a -> Stream a
330−foreign import delay :: forall a. Number -> Stream a -> Stream a
331−foreign import multicast :: forall a. Stream a -> Stream a
332−foreign import hold :: forall a. Stream a -> Stream a
333−foreign import proxy :: forall a. a -> { attach :: (Stream a -> Stream a), stream :: Stream a }
334−
335−-- Sad subject types :/
336−foreign import toSubject :: forall a. Stream a -> Subject a
337−foreign import toHoldSubject :: forall a. Int -> Stream a -> Subject a
338−foreign import fromSubject :: forall a. Subject a -> Stream a
339−foreign import subjectEvent :: forall a. a -> Subject a -> Subject a
340−foreign import subjectEnd :: forall a. a -> Subject a -> Subject a
src/Control/Time.pursdeleted−3
@@ -1,3 +0,0 @@
1−module Control.Stream.Time where
2−
3−newtype Time = Time Int
test/Main.pursdeleted−9
@@ -1,9 +0,0 @@
1−module Test.Main where
2−
3−import Control.Monad.Eff (Eff)
4−import Control.Monad.Eff.Console (CONSOLE, logShow)
5−import Data.Unit (Unit)
6−
7−main :: Eff (console :: CONSOLE) Unit
8−main = do
9− logShow "Write tests. You're a bad developer!"