This repository has been archived by the owner on Jun 6, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
events.janet
152 lines (140 loc) · 3.91 KB
/
events.janet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# a push-pull system
# events are pushed to queues
# then things can pull from the queues
(import ./state)
# functions to not block the fiber when interacting with channels
(defn pop
``
Like `ev/take` but non-blocking, instead returns `nil` if the
channel is empty.
``
[chan]
(when (pos? (ev/count chan))
(ev/take chan)))
(defn push!
``
Like `ev/give`, but if the channel is full, throw away the
oldest value.
``
[chan v]
(when (ev/full chan)
(ev/take chan)) ## throw away old values
(ev/give chan v))
(defn vs
``
Returns the values in a channel.
``
[chan]
(def vs @[])
# empty the queue
(loop [v :iterate (pop chan)]
(array/push vs v))
# then put them back again
(loop [v :in vs]
(push! chan v))
#
vs)
# we want to be able to pull
# multiple things should be able to pull from it
# essentially splitting the value
(defn pull
[pullable pullers]
(when-let [v (case (type pullable)
:core/channel
(pop pullable)
#
:table
(when (pullable :event/changed)
(put pullable :event/changed false))
#
(errorf "%s is not a pullable." (type pullable)))]
(loop [puller :in pullers]
(try
(case (type puller)
:function
(puller v)
#
:core/channel
(push! puller v)
#
:table
(:on-event puller v)
#
(errorf "Pulling not implemented for %s" (type puller)))
([err fib]
(push! state/eval-results
(if (and (dictionary? err) (err :error))
err
(let [event
(if (dictionary? v)
(string/format "dictionary with keys: %p"
(keys v))
v)
subscriber
(if (dictionary? puller)
(string/format "dictionary with keys: %p"
(keys puller))
puller)]
{:error err
:fiber fib
:msg (string/format
``
%s
event:
%p
subscriber:
%p
``
err event subscriber)
:cause [v puller]}))))))
# if there was a value, we return it
v))
(defn pull-all
[pullable pullers]
(while
(pull pullable pullers)
nil))
(defn put!
[state k v]
(-> state
(put k v)
(put :event/changed true)))
(defn update!
[state k f & args]
(-> state
(update k f ;args)
(put :event/changed true)))
(defn record-all
[pullables]
(loop [[pullable pullers] :pairs pullables]
(case (type pullable)
:core/channel
(array/push pullers
@{:history (ev/chan 10000)
:on-event (fn [self ev]
(update self :history push! ev))})
#
:table
(array/push pullers
@{:history (freeze pullable)
:on-event (fn [self ev] nil)})))
pullables)
(defn fresh?
[pullable]
(case (type pullable)
:core/channel
(pos? (ev/count pullable))
#
:table
(pullable :event/changed)))
(varfn pull-deps
[deps &opt finally]
# as long as dependencies have changed (are `fresh?`)
# keep looping through them and tell dependees
# that changes have happened (`pull-all`)
(while (some fresh? (keys deps))
(loop [[pullable pullers] :pairs deps]
(pull-all pullable pullers)))
# then when all is done, run the things in `finally`
(loop [[pullable pullers] :pairs (or finally {})]
(pull-all pullable pullers)))