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
153
154
155
156
157
158
|
----
-- Update scheduling policy for `Op` arguments.
--
-- @classmod Input
import Constant, SigStream, EvtStream from require 'alv.result'
import RTNode from require 'alv.rtnode'
inherits = (klass, frm) ->
assert klass, "cant find the ancestor of nil"
return true if klass == frm
while klass.__parent
return true if klass.__parent == frm
klass = klass.__parent
false
match_parent = (inst, map) ->
klass = assert inst and inst.__class, "not an instance"
if key = map[klass]
return key
while klass.__parent
if key = map[klass.__parent]
return key
klass = klass.__parent
local ColdInput, ValueInput, IOInput, mapping
class Input
--- Input interface.
--
-- Methods that have to be implemented by `Input` implementations.
-- @section interface
--- create a new Input.
--
-- @classmethod
-- @tparam Result result
new: (@result) =>
assert @result, "nil passed to Input: #{value}"
--- copy state from old instance (optional).
--
-- called by `Op:setup` with another `Input` instance or `nil` once this instance is
-- registered. Must prepare this instance for `dirty`.
--
-- May enter a 'setup state' that is exited using `finish_setup`.
--
-- @tparam ?Input prev previous `Input` intance or nil
setup: (prev) =>
--- whether this input requires processing (optional).
--
-- must return a boolean indicating whether `Op`s that refer to this instance
-- should be notified (via `Op:tick`). If not overwritten, delegates to
-- `result`:@{SigStream:dirty|dirty}.
--
-- @treturn bool whether processing is necessary
dirty: => @result\dirty!
--- leave setup state (optional).
--
-- called after the `Op` has completed (or skipped) its first `Op:tick` after
-- `Op:setup`. Must prepare this instance for dataflow operation.
finish_setup: =>
--- unwrap to Lua value (optional).
--
-- @treturn any the raw Lua value
unwrap: => @result\unwrap!
--- return the type name of this `Input` (optional).
type: => @result.type
--- return the metatype name of this `Input` (optional).
metatype: => @result.metatype
--- the current value
-- @tfield Result result
--- the Input mode
-- @tfield string mode `'hot'`, `'cold'` or `'io'`.
mode: 'hot'
--- members
-- @section members
--- alias for `unwrap`.
__call: => @result\unwrap!
__tostring: => "#{@@__name}:#{@result}"
__inherited: (cls) =>
cls.__base.__call = @__call
cls.__base.__tostring = @__tostring
--- static functions
-- @section static
--- Create a `cold` `Input`.
--
-- Never marked dirty. Use this for input results that are only read when
-- another `Input` is dirty.
--
-- @tparam Result|RTNode value
@cold: (value) ->
if value.__class == RTNode
value = assert value.result, "Input from node without result!"
ColdInput value
--- Create a `hot` `Input`.
--
-- Behaviour depends on what kind of `Result` `value` is:
--
-- - `Constant`: treated like `cold`.
-- - `SigStream`: Marked dirty only if old and new `result` differ.
-- - `EvtStream`: Marked dirty only if the current `result` is dirty.
--
-- This is the most common `Input` strategy.
--
-- @tparam Result|RTNode value
@hot: (value) ->
if value.__class == RTNode
value = assert value.result, "Input from node without result!"
InputType = match_parent value, mapping
assert InputType, "Input from unknown value: #{value}"
InputType value
class ColdInput extends Input
mode: 'cold'
dirty: => false
class ValueInput extends Input
new: (result) =>
super result
@mode = if @result.metatype == '=' then 'cold' else 'hot'
setup: (old) =>
@dirty_setup = not old or @result != old.result
finish_setup: => @dirty_setup = nil
dirty: =>
return @dirty_setup if @dirty_setup != nil
@result\dirty!
class IOInput extends Input
mode: 'io'
mapping = {
[Constant]: ValueInput
[SigStream]: ValueInput
[EvtStream]: Input
}
{
:Input
}
|