git.iko.soy/purescript-stream
on 820bb35 help sign in
39 files changed+1533−2166
since splitsnapshots
unifiedsplit
.eslintignore+1 .gitignore−2 CHANGELOG.md−28 README.md−28 bower.json+2−3 ffi/Control/Stream/LinkedList.js+47 ffi/Control/Stream/Stream.js+5 ffi/Control/Stream/combinators/drain.js+4 ffi/Control/Stream/combinators/index.js+2 ffi/Control/Stream/combinators/mergeConcurrently.js+123 ffi/Control/Stream/combinators/tap.js+50 ffi/Control/Stream/disposables/Disposable.js+15 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+4 ffi/Control/Stream/runEffects.js+28 ffi/Control/Stream/scheduler/ClockTimer.js+48 ffi/Control/Stream/scheduler/PropagateTask.js+30 ffi/Control/Stream/scheduler/ScheduledTask.js+14 ffi/Control/Stream/scheduler/Scheduler.js+99 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−4 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+688 src/Control/Stream.purs+123−52 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−2
@@ -5,5 +5,3 @@
55/generated-docs/
66/.psc*
77/.psa*
8−src/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+2−3
@@ -9,9 +9,8 @@
99 "dependencies": {
1010 "purescript-eff": "^2.0.0",
1111 "purescript-prelude": "^2.5.0",
12− "purescript-refs": "^2.0.0",
13− "purescript-maybe": "^2.1.1",
14− "purescript-partial": "^1.2.0"
12+ "purescript-aff-promise": "^0.4.0",
13+ "purescript-aff": "^2.0.3"
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/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+2
@@ -0,0 +1,2 @@
1+export * from './tap'
2+export * from './drain'
ffi/Control/Stream/combinators/mergeConcurrently.jsnew file+123
@@ -0,0 +1,123 @@
1+/** @license MIT License (c) copyright 2010-2016 original author or authors */
2+/** @author Brian Cavalier */
3+/** @author John Hann */
4+
5+import { LinkedList } from '../LinkedList'
6+import { MemoizedDisosable } from '../disposables/MemoizedDisposable'
7+import { id as identity } from '@most/prelude'
8+
9+export const mergeConcurrently = (concurrency, stream) =>
10+ mergeMapConcurrently(identity, concurrency, stream)
11+
12+export const mergeMapConcurrently = (f, concurrency, stream) =>
13+ new MergeConcurrently(f, concurrency, stream)
14+
15+class MergeConcurrently {
16+ constructor (f, concurrency, source) {
17+ this.f = f
18+ this.concurrency = concurrency
19+ this.source = source
20+ }
21+
22+ run (sink, scheduler) {
23+ return new Outer(this.f, this.concurrency, this.source, sink, scheduler)
24+ }
25+}
26+
27+class Outer {
28+ constructor (f, concurrency, source, sink, scheduler) {
29+ this.f = f
30+ this.concurrency = concurrency
31+ this.sink = sink
32+ this.scheduler = scheduler
33+ this.pending = []
34+ this.current = new LinkedList()
35+ this.disposable = new MemoizedDisosable(source.run(this, scheduler))
36+ this.active = true
37+ }
38+
39+ event (t, x) {
40+ this._addInner(t, x)
41+ }
42+
43+ _addInner (t, x) {
44+ if (this.current.length < this.concurrency) {
45+ this._startInner(t, x)
46+ } else {
47+ this.pending.push(x)
48+ }
49+ }
50+
51+ _startInner (t, x) {
52+ try {
53+ this._initInner(t, x)
54+ } catch (e) {
55+ this.error(t, e)
56+ }
57+ }
58+
59+ _initInner (t, x) {
60+ const innerSink = new Inner(t, this, this.sink)
61+ innerSink.disposable = mapAndRun(this.f, x, innerSink, this.scheduler)
62+ this.current.add(innerSink)
63+ }
64+
65+ end (t, x) {
66+ this.active = false
67+ this.disposable.dispose()
68+ this._checkEnd(t, x)
69+ }
70+
71+ dispose () {
72+ this.active = false
73+ this.pending.length = 0
74+ this.disposable.dispose()
75+ this.current.dispose()
76+ }
77+
78+ _endInner (t, x, inner) {
79+ this.current.remove(inner)
80+ inner.dispose()
81+
82+ if (this.pending.length === 0) {
83+ this._checkEnd(t, x)
84+ } else {
85+ this._startInner(t, this.pending.shift())
86+ }
87+ }
88+
89+ _checkEnd (t, x) {
90+ if (!this.active && this.current.isEmpty()) {
91+ this.sink.end(t, x)
92+ }
93+ }
94+}
95+
96+const mapAndRun = (f, x, sink, scheduler) =>
97+ f(x).run(sink, scheduler)
98+
99+class Inner {
100+ constructor (time, outer, sink) {
101+ this.prev = this.next = null
102+ this.time = time
103+ this.outer = outer
104+ this.sink = sink
105+ this.disposable = void 0
106+ }
107+
108+ event (t, x) {
109+ this.sink.event(Math.max(t, this.time), x)
110+ }
111+
112+ end (t, x) {
113+ this.outer._endInner(Math.max(t, this.time), x, this)
114+ }
115+
116+ error (t, e) {
117+ this.outer.error(Math.max(t, this.time), e)
118+ }
119+
120+ dispose () {
121+ return this.disposable.dispose()
122+ }
123+}
ffi/Control/Stream/combinators/tap.jsnew file+50
@@ -0,0 +1,50 @@
1+import { Stream } from '../Stream'
2+import { curry2 } from '@most/prelude'
3+
4+export const tapEnd = curry2((f, stream) => new Stream(new TapEnd(f, stream.source)))
5+
6+export const tapEvent = curry2((f, stream) => new Stream(new TapEvent(f, stream.source)))
7+
8+class TapEvent {
9+ constructor (f, source) {
10+ this.source = source
11+ this.f = f
12+
13+ this.run = sink => scheduler =>
14+ source.run(new TapSink(f, sink))(scheduler)
15+ }
16+}
17+
18+class TapSink {
19+ constructor (f, sink) {
20+ this.event = t => x => {
21+ f(x)()
22+ sink.event(t)(x)
23+ }
24+
25+ this.end = t => {
26+ sink.end(t)
27+ }
28+ }
29+}
30+
31+class TapEnd {
32+ constructor (f, source) {
33+ this.source = source
34+ this.f = f
35+
36+ this.run = sink => scheduler =>
37+ source.run(new TapEndSink(f, sink))(scheduler)
38+ }
39+}
40+
41+class TapEndSink {
42+ constructor (f, sink) {
43+ this.event = t => x => sink.event(t)(x)
44+
45+ this.end = t => {
46+ f()
47+ sink.end(t)
48+ }
49+ }
50+}
ffi/Control/Stream/disposables/Disposable.jsnew file+15
@@ -0,0 +1,15 @@
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+
12+ dispose () {
13+ return this._dispose(this._data)
14+ }
15+}
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 = disposeSafely(this.disposable)
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(map(disposeSafely, disposables), disposables)
ffi/Control/Stream/index.jsnew file+4
@@ -0,0 +1,4 @@
1+/* @flow */
2+export * from './disposables'
3+export * from './scheduler'
4+export * from './combinators'
ffi/Control/Stream/runEffects.jsnew file+28
@@ -0,0 +1,28 @@
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+
16+var RunEffectsSink = function RunEffectsSink (disposable) {
17+ this._disposable = disposable
18+ this.active = true
19+}
20+
21+RunEffectsSink.prototype.event = function event (t) {
22+ return function (x) {}
23+}
24+
25+RunEffectsSink.prototype.end = function end (t) {
26+ this.active = false
27+ Promise.resolve(this._disposable).then(d => d.dispose())
28+}
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+30
@@ -0,0 +1,30 @@
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+
15+ this.dispose = () => { active = false }
16+ this.run = t => {
17+ if (!active) return
18+
19+ run(t, value, sink)
20+ }
21+ }
22+}
23+
24+function runEvent (time, value, sink) {
25+ sink.event(time)(value)
26+}
27+
28+function runEnd (time, value, sink) {
29+ sink.end(time, value)
30+}
ffi/Control/Stream/scheduler/ScheduledTask.jsnew file+14
@@ -0,0 +1,14 @@
1+/* @flow */
2+export function ScheduledTask (delay, period, task, scheduler) {
3+ this.time = delay
4+ this.period = period
5+ this.task = task
6+ this.scheduler = scheduler
7+ this.active = true
8+
9+ this.run = () => task.run(this.time)
10+ this.dispose = () => {
11+ scheduler.cancel(this)
12+ task.dispose()
13+ }
14+}
ffi/Control/Stream/scheduler/Scheduler.jsnew file+99
@@ -0,0 +1,99 @@
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, task) {
32+ return this.schedule(delay, -1, task)
33+ }
34+
35+ periodic (period, task) {
36+ return this.schedule(0, period, task)
37+ }
38+
39+ schedule (delay, period, task) {
40+ const now = this.now()
41+ const st = new ScheduledTask(now + Math.max(0, delay), period, task, this)
42+
43+ this.timeline.add(st)
44+ this._scheduleNextRun(now)
45+ return st
46+ }
47+
48+ cancel (task) {
49+ task.active = false
50+ if (this.timeline.remove(task)) {
51+ this._reschedule()
52+ }
53+ }
54+
55+ cancelAll (f) {
56+ this.timeline.removeAll(f)
57+ this._reschedule()
58+ }
59+
60+ _reschedule () {
61+ if (this.timeline.isEmpty()) {
62+ this._unschedule()
63+ } else {
64+ this._scheduleNextRun(this.now())
65+ }
66+ }
67+
68+ _unschedule () {
69+ this.timer.clearTimer(this._timer)
70+ this._timer = null
71+ }
72+
73+ _scheduleNextRun (now) { // eslint-disable-line complexity
74+ if (this.timeline.isEmpty()) {
75+ return
76+ }
77+
78+ const nextArrival = this.timeline.nextArrival()
79+
80+ if (this._timer === null) {
81+ this._scheduleNextArrival(nextArrival, now)
82+ } else if (nextArrival < this._nextArrival) {
83+ this._unschedule()
84+ this._scheduleNextArrival(nextArrival, now)
85+ }
86+ }
87+
88+ _scheduleNextArrival (nextArrival, now) {
89+ this._nextArrival = nextArrival
90+ const delay = Math.max(0, nextArrival - now)
91+ this._timer = this.timer.setTimer(this._runReadyTasksBound, delay)
92+ }
93+
94+ _runReadyTasks (now) {
95+ this._timer = null
96+ this.timeline.runTasks(now, runTask)
97+ this._scheduleNextRun(this.now())
98+ }
99+}
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, x) {
19+ if (!this.active) return
20+
21+ this.active = false
22+ this.sink.end(t, { index: this.index, value: x })
23+ }
24+}
ffi/Control/Stream/sink/index.jsnew file+1
@@ -0,0 +1 @@
1+export * from './IndexSink'
package.json+10−4
@@ -1,11 +1,10 @@
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": {
7− "start": "yarn build && pulp run",
8− "build": "pulp build",
7+ "build": "rollup -c && pulp build",
98 "changelog": "conventional-changelog -i CHANGELOG.md -s -r 0 -p angular",
109 "clean": "rimraf lib lib.es2015",
1110 "commit": "git-cz",
@@ -32,7 +31,14 @@
3231 "husky": "^0.13.2",
3332 "pulp": "^10.0.4",
3433 "purescript": "^0.10.7",
34+ "rollup": "^0.41.4",
35+ "rollup-plugin-buble": "^0.15.0",
36+ "rollup-plugin-flow": "^1.1.1",
37+ "rollup-plugin-node-resolve": "^2.0.0",
3538 "uglify-js": "^2.8.11",
3639 "validate-commit-msg": "^2.11.2"
40+ },
41+ "dependencies": {
42+ "@most/prelude": "^1.5.0"
3743 }
3844}
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+688
@@ -0,0 +1,688 @@
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+
16+
17+// drop :: Int -> [a] -> [a]
18+// drop first n elements
19+
20+
21+// tail :: [a] -> [a]
22+// drop head element
23+
24+
25+// copy :: [a] -> [a]
26+// duplicate a (shallow duplication)
27+
28+
29+// map :: (a -> b) -> [a] -> [b]
30+// transform each element with f
31+function map (f, a) {
32+ var l = a.length;
33+ var b = new Array(l);
34+ for (var i = 0; i < l; ++i) {
35+ b[i] = f(a[i]);
36+ }
37+ return b
38+}
39+
40+// reduce :: (a -> b -> a) -> a -> [b] -> a
41+// accumulate via left-fold
42+
43+
44+// replace :: a -> Int -> [a]
45+// replace element at index
46+
47+
48+// remove :: Int -> [a] -> [a]
49+// remove element at index
50+
51+
52+// removeAll :: (a -> boolean) -> [a] -> [a]
53+// remove all elements matching a predicate
54+function removeAll (f, a) {
55+ var l = a.length;
56+ var b = new Array(l);
57+ var j = 0;
58+ for (var x = (void 0), i = 0; i < l; ++i) {
59+ x = a[i];
60+ if (!f(x)) {
61+ b[j] = x;
62+ ++j;
63+ }
64+ }
65+
66+ b.length = j;
67+ return b
68+}
69+
70+// findIndex :: a -> [a] -> Int
71+// find index of x in a, from the left
72+function findIndex (x, a) {
73+ for (var i = 0, l = a.length; i < l; ++i) {
74+ if (x === a[i]) {
75+ return i
76+ }
77+ }
78+ return -1
79+}
80+
81+// isArrayLike :: * -> boolean
82+// Return true iff x is array-like
83+
84+/** @license MIT License (c) copyright 2010-2016 original author or authors */
85+
86+// id :: a -> a
87+var id = function (x) { return x; };
88+
89+// compose :: (b -> c) -> (a -> b) -> (a -> c)
90+
91+
92+// apply :: (a -> b) -> a -> b
93+
94+
95+// curry2 :: ((a, b) -> c) -> (a -> b -> c)
96+function curry2 (f) {
97+ function curried (a, b) {
98+ switch (arguments.length) {
99+ case 0: return curried
100+ case 1: return function (b) { return f(a, b); }
101+ default: return f(a, b)
102+ }
103+ }
104+ return curried
105+}
106+
107+// curry3 :: ((a, b, c) -> d) -> (a -> b -> c -> d)
108+function curry3 (f) {
109+ function curried (a, b, c) { // eslint-disable-line complexity
110+ switch (arguments.length) {
111+ case 0: return curried
112+ case 1: return curry2(function (b, c) { return f(a, b, c); })
113+ case 2: return function (c) { return f(a, b, c); }
114+ default:return f(a, b, c)
115+ }
116+ }
117+ return curried
118+}
119+
120+// curry4 :: ((a, b, c, d) -> e) -> (a -> b -> c -> d -> e)
121+
122+/** @license MIT License (c) copyright 2016 original author or authors */
123+
124+var Disposable = function Disposable (dispose, data) {
125+ this._dispose = dispose;
126+ this._data = data;
127+};
128+
129+Disposable.prototype.dispose = function dispose () {
130+ return this._dispose(this._data)
131+};
132+
133+var MemoizedDisposable = function MemoizedDisposable (disposable) {
134+ this.disposed = false;
135+ this.value = undefined;
136+ this.disposable = disposable;
137+};
138+
139+MemoizedDisposable.prototype.dispose = function dispose () {
140+ if (!this.disposed) {
141+ this.disposed = true;
142+ this.value = disposeSafely(this.disposable);
143+ this.disposable = undefined;
144+ }
145+
146+ return this.value
147+};
148+
149+function disposeSafely$1 (disposable) {
150+ disposable.dispose();
151+}
152+
153+var createDisposable = curry2(function (dispose, data) { return new MemoizedDisposable(new Disposable(dispose, data)); });
154+
155+var emptyDisposable = new Disposable(id, undefined);
156+
157+var disposeAll = function (disposables) { return createDisposable(map(disposeSafely$1, disposables), disposables); };
158+
159+/** @license MIT License (c) copyright 2010-2016 original author or authors */
160+/** @author Brian Cavalier */
161+/** @author John Hann */
162+
163+/*global setTimeout, clearTimeout*/
164+
165+function defer (task) {
166+ return Promise.resolve(task).then(runTask)
167+}
168+
169+function runTask (task) {
170+ return task.run()
171+}
172+
173+var ClockTimer = function ClockTimer () {
174+ this.now = Date.now;
175+};
176+
177+ClockTimer.prototype.setTimer = function setTimer (f, dt) {
178+ return dt <= 0 ? runAsap(f) : setTimeout(f, dt)
179+};
180+
181+ClockTimer.prototype.clearTimer = function clearTimer (t) {
182+ return t instanceof Asap ? t.cancel() : clearTimeout(t)
183+};
184+
185+var Asap = function Asap (f) {
186+ this.f = f;
187+ this.active = true;
188+};
189+
190+Asap.prototype.run = function run () {
191+ return this.active && this.f()
192+};
193+
194+Asap.prototype.cancel = function cancel () {
195+ this.active = false;
196+};
197+
198+function runAsap (f) {
199+ var task = new Asap(f);
200+ defer(task);
201+ return task
202+}
203+
204+/* */
205+function ScheduledTask (delay, period, task, scheduler) {
206+ var this$1 = this;
207+
208+ this.time = delay;
209+ this.period = period;
210+ this.task = task;
211+ this.scheduler = scheduler;
212+ this.active = true;
213+
214+ this.run = function () { return task.run(this$1.time); };
215+ this.dispose = function () {
216+ scheduler.cancel(this$1);
217+ task.dispose();
218+ };
219+}
220+
221+/* */
222+function runTask$1 (task) {
223+ try {
224+ return task.run()
225+ } catch (e) {
226+ console.error(e);
227+ }
228+}
229+
230+var Scheduler = function Scheduler (timer, timeline) {
231+ var this$1 = this;
232+
233+ this.timer = timer;
234+ this.timeline = timeline;
235+
236+ this._timer = null;
237+ this._nextArrival = Infinity;
238+
239+ this._runReadyTasksBound = function () { return this$1._runReadyTasks(this$1.now()); };
240+};
241+
242+Scheduler.prototype.now = function now () {
243+ return this.timer.now()
244+};
245+
246+Scheduler.prototype.asap = function asap (task) {
247+ return this.schedule(0, -1, task)
248+};
249+
250+Scheduler.prototype.delay = function delay (delay$1, task) {
251+ return this.schedule(delay$1, -1, task)
252+};
253+
254+Scheduler.prototype.periodic = function periodic (period, task) {
255+ return this.schedule(0, period, task)
256+};
257+
258+Scheduler.prototype.schedule = function schedule (delay, period, task) {
259+ var now = this.now();
260+ var st = new ScheduledTask(now + Math.max(0, delay), period, task, this);
261+
262+ this.timeline.add(st);
263+ this._scheduleNextRun(now);
264+ return st
265+};
266+
267+Scheduler.prototype.cancel = function cancel (task) {
268+ task.active = false;
269+ if (this.timeline.remove(task)) {
270+ this._reschedule();
271+ }
272+};
273+
274+Scheduler.prototype.cancelAll = function cancelAll (f) {
275+ this.timeline.removeAll(f);
276+ this._reschedule();
277+};
278+
279+Scheduler.prototype._reschedule = function _reschedule () {
280+ if (this.timeline.isEmpty()) {
281+ this._unschedule();
282+ } else {
283+ this._scheduleNextRun(this.now());
284+ }
285+};
286+
287+Scheduler.prototype._unschedule = function _unschedule () {
288+ this.timer.clearTimer(this._timer);
289+ this._timer = null;
290+};
291+
292+Scheduler.prototype._scheduleNextRun = function _scheduleNextRun (now) { // eslint-disable-line complexity
293+ if (this.timeline.isEmpty()) {
294+ return
295+ }
296+
297+ var nextArrival = this.timeline.nextArrival();
298+
299+ if (this._timer === null) {
300+ this._scheduleNextArrival(nextArrival, now);
301+ } else if (nextArrival < this._nextArrival) {
302+ this._unschedule();
303+ this._scheduleNextArrival(nextArrival, now);
304+ }
305+};
306+
307+Scheduler.prototype._scheduleNextArrival = function _scheduleNextArrival (nextArrival, now) {
308+ this._nextArrival = nextArrival;
309+ var delay = Math.max(0, nextArrival - now);
310+ this._timer = this.timer.setTimer(this._runReadyTasksBound, delay);
311+};
312+
313+Scheduler.prototype._runReadyTasks = function _runReadyTasks (now) {
314+ this._timer = null;
315+ this.timeline.runTasks(now, runTask$1);
316+ this._scheduleNextRun(this.now());
317+};
318+
319+/** @license MIT License (c) copyright 2010-2016 original author or authors */
320+/** @author Brian Cavalier */
321+/** @author John Hann */
322+
323+var Timeline = function Timeline () {
324+ this.tasks = [];
325+};
326+
327+Timeline.prototype.nextArrival = function nextArrival () {
328+ return this.isEmpty() ? Infinity : this.tasks[0].time
329+};
330+
331+Timeline.prototype.isEmpty = function isEmpty () {
332+ return this.tasks.length === 0
333+};
334+
335+Timeline.prototype.add = function add (st) {
336+ insertByTime(st, this.tasks);
337+};
338+
339+Timeline.prototype.remove = function remove$$1 (st) {
340+ var i = binarySearch(st.time, this.tasks);
341+
342+ if (i >= 0 && i < this.tasks.length) {
343+ var at = findIndex(st, this.tasks[i].events);
344+ if (at >= 0) {
345+ this.tasks[i].events.splice(at, 1);
346+ return true
347+ }
348+ }
349+
350+ return false
351+};
352+
353+Timeline.prototype.removeAll = function removeAll$$1 (f) {
354+ var this$1 = this;
355+
356+ for (var i = 0; i < this.tasks.length; ++i) {
357+ removeAllFrom(f, this$1.tasks[i]);
358+ }
359+};
360+
361+Timeline.prototype.runTasks = function runTasks (t, runTask) {
362+ var this$1 = this;
363+
364+ var tasks = this.tasks;
365+ var l = tasks.length;
366+ var i = 0;
367+
368+ while (i < l && tasks[i].time <= t) {
369+ ++i;
370+ }
371+
372+ this.tasks = tasks.slice(i);
373+
374+ // Run all ready tasks
375+ for (var j = 0; j < i; ++j) {
376+ this$1.tasks = runReadyTasks(runTask, tasks[j].events, this$1.tasks);
377+ }
378+};
379+
380+function runReadyTasks (runTask, events, tasks) { // eslint-disable-line complexity
381+ for (var i = 0; i < events.length; ++i) {
382+ var task = events[i];
383+
384+ if (task.active) {
385+ runTask(task);
386+
387+ // Reschedule periodic repeating tasks
388+ // Check active again, since a task may have canceled itself
389+ if (task.period >= 0 && task.active) {
390+ task.time = task.time + task.period;
391+ insertByTime(task, tasks);
392+ }
393+ }
394+ }
395+
396+ return tasks
397+}
398+
399+function insertByTime (task, timeslots) { // eslint-disable-line complexity
400+ var l = timeslots.length;
401+
402+ if (l === 0) {
403+ timeslots.push(newTimeslot(task.time, [task]));
404+ return
405+ }
406+
407+ var i = binarySearch(task.time, timeslots);
408+
409+ if (i >= l) {
410+ timeslots.push(newTimeslot(task.time, [task]));
411+ } else if (task.time === timeslots[i].time) {
412+ timeslots[i].events.push(task);
413+ } else {
414+ timeslots.splice(i, 0, newTimeslot(task.time, [task]));
415+ }
416+}
417+
418+function removeAllFrom (f, timeslot) {
419+ timeslot.events = removeAll(f, timeslot.events);
420+}
421+
422+function binarySearch (t, sortedArray) { // eslint-disable-line complexity
423+ var lo = 0;
424+ var hi = sortedArray.length;
425+ var mid, y;
426+
427+ while (lo < hi) {
428+ mid = Math.floor((lo + hi) / 2);
429+ y = sortedArray[mid];
430+
431+ if (t === y.time) {
432+ return mid
433+ } else if (t < y.time) {
434+ hi = mid;
435+ } else {
436+ lo = mid + 1;
437+ }
438+ }
439+ return hi
440+}
441+
442+var newTimeslot = function (t, events) { return ({ time: t, events: events }); };
443+
444+var propagateTask =
445+ curry3(function (run, value, sink) { return new PropagateTask(run, value, sink); });
446+
447+var eventTask =
448+ curry2(function (value, sink) { return propagateTask(runEvent, value, sink); });
449+
450+var endTask = function (sink) { return propagateTask(runEnd, void 0, sink); };
451+
452+var PropagateTask = function PropagateTask (run, value, sink) {
453+ var active = true;
454+
455+ this.dispose = function () { active = false; };
456+ this.run = function (t) {
457+ if (!active) { return }
458+
459+ run(t, value, sink);
460+ };
461+};
462+
463+function runEvent (time, value, sink) {
464+ sink.event(time)(value);
465+}
466+
467+function runEnd (time, value, sink) {
468+ sink.end(time, value);
469+}
470+
471+var defaultScheduler = new Scheduler(new ClockTimer(), new Timeline());
472+
473+var scheduleTasks = curry2(function (tasks, scheduler) {
474+ var scheduledTasks = tasks.map(function (task) { return scheduler.asap(task); });
475+
476+ return {
477+ dispose: function () { return scheduledTasks.forEach(function (task) { return task.dispose(); }); }
478+ }
479+});
480+
481+var Stream = function Stream (source) {
482+ this.source = source;
483+};
484+
485+var tapEnd = curry2(function (f, stream) { return new Stream(new TapEnd(f, stream.source)); });
486+
487+var tapEvent = curry2(function (f, stream) { return new Stream(new TapEvent(f, stream.source)); });
488+
489+var TapEvent = function TapEvent (f, source) {
490+ this.source = source;
491+ this.f = f;
492+
493+ this.run = function (sink) { return function (scheduler) { return source.run(new TapSink(f, sink))(scheduler); }; };
494+};
495+
496+var TapSink = function TapSink (f, sink) {
497+ this.event = function (t) { return function (x) {
498+ f(x)();
499+ sink.event(t)(x);
500+ }; };
501+
502+ this.end = function (t) {
503+ sink.end(t);
504+ };
505+};
506+
507+var TapEnd = function TapEnd (f, source) {
508+ this.source = source;
509+ this.f = f;
510+
511+ this.run = function (sink) { return function (scheduler) { return source.run(new TapEndSink(f, sink))(scheduler); }; };
512+};
513+
514+var TapEndSink = function TapEndSink (f, sink) {
515+ this.event = function (t) { return function (x) { return sink.event(t)(x); }; };
516+
517+ this.end = function (t) {
518+ f();
519+ sink.end(t);
520+ };
521+};
522+
523+var SettableDisposable = function SettableDisposable () {
524+ this.disposable = void 0;
525+ this.disposed = false;
526+ this.result = void 0;
527+};
528+
529+SettableDisposable.prototype.setDisposable = function setDisposable (disposable) {
530+ this.disposable = disposable;
531+
532+ if (this.disposed) {
533+ this.result = disposable.dispose();
534+ }
535+};
536+
537+SettableDisposable.prototype.dispose = function dispose () {
538+ if (this.disposed) {
539+ return this.result
540+ }
541+
542+ this.disposed = true;
543+
544+ if (this.disposable !== void 0) {
545+ this.result = this.disposable.dispose();
546+ }
547+
548+ return this.result
549+};
550+
551+function runEffects (stream, scheduler) {
552+ return runSourceEffects(stream.source, scheduler)
553+}
554+
555+var runSourceEffects = function (source, scheduler) { return runSource(source, scheduler); };
556+
557+function runSource (source, scheduler) {
558+ var disposable = new SettableDisposable();
559+ var observer = new RunEffectsSink(disposable);
560+
561+ disposable.setDisposable(source.run(observer)(scheduler));
562+}
563+
564+var RunEffectsSink = function RunEffectsSink (disposable) {
565+ this._disposable = disposable;
566+ this.active = true;
567+};
568+
569+RunEffectsSink.prototype.event = function event (t) {
570+ return function (x) {}
571+};
572+
573+RunEffectsSink.prototype.end = function end (t) {
574+ this.active = false;
575+ Promise.resolve(this._disposable).then(function (d) { return d.dispose(); });
576+};
577+
578+var drain = function (stream) { return function () { return runEffects(stream, defaultScheduler); }; };
579+
580+var combine =
581+ curry3(function (f, stream1, stream2) { return new Stream(new Combine(f, stream1.source, stream2.source)); });
582+
583+var Combine = function Combine (f, source1, source2) {
584+ this.f = f;
585+ this.source1 = source1;
586+ this.source2 = source2;
587+};
588+
589+Combine.prototype.run = function run (sink) {
590+ var this$1 = this;
591+
592+ return function (scheduler) {
593+ var disposables = Array(2);
594+ var sinks = Array(2);
595+
596+ var mergeSink = new CombineSink(disposables, sinks, sink, this$1.f);
597+
598+ sinks[0] = new IndexSink(0, mergeSink);
599+ sinks[1] = new IndexSink(1, mergeSink);
600+ disposables[0] = this$1.source1.run(sinks[0])(scheduler);
601+ disposables[1] = this$1.source2.run(sinks[1])(scheduler);
602+
603+ return disposeAll(disposables)
604+ }
605+};
606+
607+var IndexSink = function IndexSink () {};
608+
609+IndexSink.prototype.cosntructor = function cosntructor (i, sink) {
610+ this.i = i;
611+ this.sink = sink;
612+};
613+
614+IndexSink.prototype.event = function event (t) {
615+ var this$1 = this;
616+
617+ return function (x) {
618+ this$1.sink.event(t)({ index: this$1.i, value: x });
619+ }
620+};
621+
622+IndexSink.prototype.end = function end (t) {
623+ this.sink.end(t, this.i);
624+};
625+
626+var CombineSink = function CombineSink (disposables, sinks, sink, f) {
627+ this.disposables = disposables;
628+ this.sinks = sinks;
629+ this.sink = sink;
630+ this.f = f;
631+
632+ this.awaiting = 2;
633+ this.values = Array(2);
634+ this.hasValue = [false, false];
635+ this.activeCount = 2;
636+};
637+
638+CombineSink.prototype.event = function event (t) {
639+ var this$1 = this;
640+
641+ return function (ref) {
642+ var index = ref.index;
643+ var value = ref.value;
644+
645+ var f = this$1.f;
646+ var awaiting = this$1._updateReady(index);
647+ this$1.values[index] = value;
648+
649+ if (awaiting === 0) {
650+ var result = f(this$1.values[0])(this$1.values[1]);
651+ this$1.sink.event(t)(result);
652+ }
653+ }
654+};
655+
656+CombineSink.prototype._updateReady = function _updateReady (index) {
657+ if (this.awaiting > 0) {
658+ if (!this.hasValue[index]) {
659+ this.hasValue[index] = true;
660+ this.awaiting -= 1;
661+ }
662+ }
663+
664+ return this.awaiting
665+};
666+
667+CombineSink.prototype.end = function end (t, ref) {
668+ var index = ref.index;
669+ var value = ref.value;
670+
671+ this.disposables[index].dispose();
672+
673+ if (--this.activeCount === 0) { this.sink.end(t); }
674+};
675+
676+/* */
677+
678+exports.createDisposable = createDisposable;
679+exports.emptyDisposable = emptyDisposable;
680+exports.disposeAll = disposeAll;
681+exports.defaultScheduler = defaultScheduler;
682+exports.scheduleTasks = scheduleTasks;
683+exports.endTask = endTask;
684+exports.eventTask = eventTask;
685+exports.tapEnd = tapEnd;
686+exports.tapEvent = tapEvent;
687+exports.drain = drain;
688+exports.combine = combine;
src/Control/Stream.purs+123−52
@@ -1,59 +1,130 @@
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
17− , createCombinator
18− , createEventCombinator
19− , createEndCombinator
4+ , PureStream
5+ , Stream
6+ , Source
7+ , Sink
8+ , Scheduler
9+ , Task
10+ , ScheduledTask
11+ , Disposable
12+ , Time
13+ , createStream
14+ , getSource
15+ , runSource
16+ , defaultScheduler
17+ , eventTask
18+ , endTask
19+ , createDisposable
20+ , emptyDisposable
21+ , disposeAll
22+ , scheduleTasks
2023 , drain
2124 , tapEvent
2225 , tapEnd
26+ , just
2327 , fromArray
24− , filter
25− , take
26− , skip
27− , constant
28− , continueWith
29− , concat
30− , startWith
31− , scan
32− , loop
33− , chain
34− , mergeConcurrently
35− , join
36− , mergeMapConcurrently
37− , concatMap
38− , switch
39− , combine2
40− , combine3
41− , combine4
42− , combine5
43− , combineArray
44− , merge
45− , skipRepeatsWith
46− , skipRepeats
47− , until
48− , since
49− , during
50− , sample
51− , debounce
52− , throttle
53− , delay
54− , multicast
5528 )
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)
29+ where
30+
31+import Control.Monad.Eff (Eff, Pure)
32+import Data.Array (snoc)
33+import Data.Functor (class Functor, map)
34+import Data.Unit (Unit)
35+import Prelude (flip)
36+
37+newtype Time = Time Int
38+
39+foreign import data STREAM :: !
40+
41+type EffStream e a = Eff (stream :: STREAM | e) a
42+type PureStream a = EffStream () a
43+
44+newtype Stream a = Stream { source :: Source a }
45+
46+type Source a = { run :: Sink a -> Scheduler -> Disposable }
47+
48+type Sink a =
49+ { event :: Time -> a -> Unit
50+ , end :: Time -> Unit
51+ }
52+
53+type Scheduler =
54+ { now :: Pure Time
55+ , asap :: Task -> ScheduledTask
56+ , delay :: Number -> Task -> ScheduledTask
57+ , period :: Number -> Task -> ScheduledTask
58+ , schedule :: Number -> Number -> Task -> ScheduledTask
59+ , cancel :: ScheduledTask -> Unit
60+ , cancelAll :: (ScheduledTask -> Boolean) -> Unit
61+ }
62+
63+type Task =
64+ { run :: Time -> Unit
65+ , dispose :: Pure Unit
66+ }
67+
68+type ScheduledTask =
69+ { run :: Pure Unit
70+ , dispose :: Pure Unit
71+ }
72+
73+type Disposable = { dispose :: Pure Unit }
74+
75+instance functorStream :: Functor Stream where
76+ map = _map
77+
78+createStream :: forall a. (Sink a -> Scheduler -> Disposable) -> Stream a
79+createStream run = Stream { source: { run } }
80+
81+getSource :: forall a. Stream a -> Source a
82+getSource stream = case stream of Stream a -> a.source
83+
84+runSource :: forall a. Stream a -> Sink a -> Scheduler -> Disposable
85+runSource stream sink scheduler = (getSource stream).run sink scheduler
86+
87+just :: forall a. a -> Stream a
88+just a = createStream (runJust a)
89+
90+runJust :: forall a. a -> Sink a -> Scheduler -> Disposable
91+runJust a sink scheduler =
92+ scheduleTasks [ eventTask a sink, endTask sink ] scheduler
93+
94+-- TODO: remove fromArray because it's not a real event stream
95+-- replace with a fromArray combinator
96+fromArray :: forall a. Array a -> Stream a
97+fromArray arr = createStream (runFromArray arr)
98+
99+runFromArray :: forall a. Array a -> Sink a -> Scheduler -> Disposable
100+runFromArray arr sink scheduler = scheduleTasks tasks scheduler
101+ where
102+ tasks :: Array Task
103+ tasks = snoc eventTasks (endTask sink)
104+
105+ eventTasks :: Array Task
106+ eventTasks = map (flip eventTask sink) arr
107+
108+_map :: forall a b. (a -> b) -> Stream a -> Stream b
109+_map f stream = createStream runMap
110+ where
111+ runMap :: Sink b -> Scheduler -> Disposable
112+ runMap sink scheduler =
113+ runSource stream (mapSink f sink) scheduler
114+
115+mapSink :: forall a b. (a -> b) -> Sink b -> Sink a
116+mapSink f sink = { event: mapEvent, end: sink.end }
117+ where
118+ mapEvent :: Time -> a -> Unit
119+ mapEvent time value = sink.event time (f value)
120+
121+foreign import defaultScheduler :: Scheduler
122+foreign import eventTask :: forall a. a -> Sink a -> Task
123+foreign import endTask :: forall a. Sink a -> Task
124+foreign import createDisposable :: forall a. (a -> Unit) -> a -> Disposable
125+foreign import emptyDisposable :: Disposable
126+foreign import disposeAll :: Array Disposable -> Disposable
127+foreign import scheduleTasks :: Array Task -> Scheduler -> Disposable
128+foreign import drain :: forall e a. Stream a -> EffStream e Unit
129+foreign import tapEvent :: forall e a. (a -> EffStream e Unit) -> Stream a -> Stream a
130+foreign import tapEnd :: forall e a. EffStream e Unit -> 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!"