aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-05-12 14:20:52 +0000
committers-ol <s+removethis@s-ol.nu>2025-03-02 14:23:21 +0000
commitb41a406ab7f56cc33aca594fb38b60c67d4130ce (patch)
treefaf683fef2ee2b700b3f0d688e0f4727fc64ab0e
parentmake EvtStreams carry a single value (diff)
downloadalive-b41a406ab7f56cc33aca594fb38b60c67d4130ce.tar.gz
alive-b41a406ab7f56cc33aca594fb38b60c67d4130ce.zip
RTNode constifies constant SigStreams
-rw-r--r--alv/base/input.moon19
-rw-r--r--alv/rtnode.moon18
-rw-r--r--spec/input_spec.moon15
-rw-r--r--spec/match_spec.moon13
-rw-r--r--spec/rtnode_spec.moon49
5 files changed, 80 insertions, 34 deletions
diff --git a/alv/base/input.moon b/alv/base/input.moon
index b73a476..f29bd10 100644
--- a/alv/base/input.moon
+++ b/alv/base/input.moon
@@ -76,8 +76,11 @@ class Input
metatype: => @result.metatype
--- the current value
- --
- -- @tfield SigStream result
+ -- @tfield Result result
+
+ --- the Input mode
+ -- @tfield string mode `'hot'`, `'cold'` or `'io'`.
+ mode: 'hot'
--- members
-- @section members
@@ -125,17 +128,25 @@ class Input
InputType value
class ColdInput extends Input
+ mode: 'cold'
dirty: => false
class ValueInput extends Input
- setup: (old) => @dirty_setup = not old or @result != old.result
+ 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
- io: true
+ mode: 'io'
mapping = {
[Constant]: ValueInput
diff --git a/alv/rtnode.moon b/alv/rtnode.moon
index b10f9a1..23cffa5 100644
--- a/alv/rtnode.moon
+++ b/alv/rtnode.moon
@@ -45,7 +45,7 @@ class RTNode
-- should be called once per frame on the root, right before tick.
poll_io: =>
for result, input in pairs @side_inputs
- result\poll! if input.io
+ result\poll! if input.mode == 'io'
--- in depth-first order, tick all Ops which have dirty Inputs.
--
@@ -120,13 +120,15 @@ class RTNode
is_child[child.result] = true
if @op
- for input in @op\all_inputs!
- continue if input.result.metatype == '='
- if input.io or not is_child[input.result]
- @side_inputs[input.result] = input
-
- if @result and @result.metatype == '='
- assert not (next @side_inputs), "Const result has side_inputs"
+ for i in @op\all_inputs!
+ if i.mode == 'io' or (i.mode == 'hot' and not is_child[i.result])
+ @side_inputs[i.result] = i
+
+ if @result
+ if next @side_inputs
+ assert @result.metatype != '=', "Const result has side_inputs"
+ elseif @result.metatype == '~'
+ @result = @result.type\mk_const @result\unwrap!
{
:RTNode
diff --git a/spec/input_spec.moon b/spec/input_spec.moon
index 3a8eff9..9237fd8 100644
--- a/spec/input_spec.moon
+++ b/spec/input_spec.moon
@@ -28,6 +28,9 @@ describe 'Input.cold', ->
basic_tests result, input
+ it 'is marked cold', ->
+ assert.is.equal 'cold', input.mode
+
it 'is never dirty', ->
assert.is.false input\dirty!
result\set 2
@@ -51,6 +54,9 @@ describe 'Input.hot', ->
basic_tests result, input
+ it 'is marked cold', ->
+ assert.is.equal 'cold', input.mode
+
describe 'at evaltime', ->
it 'is dirty when new', ->
assert.is.false result\dirty!
@@ -84,8 +90,8 @@ describe 'Input.hot', ->
basic_tests result, input
- it 'is marked for lifting', ->
- assert.is.nil input.io
+ it 'is marked hot', ->
+ assert.is.equal 'hot', input.mode
it 'is dirty when the EvtStream is dirty', ->
assert.is.false input\dirty!
@@ -115,7 +121,7 @@ describe 'Input.hot', ->
basic_tests result, input
it 'is marked for lifting', ->
- assert.is.true input.io
+ assert.is.equal 'io', input.mode
it 'is dirty when the IOStream is dirty', ->
result.is_dirty = false
@@ -172,6 +178,9 @@ describe 'Input.hot', ->
assert.is.false newinput\dirty!
newinput\finish_setup!
+ it 'is marked hot', ->
+ assert.is.equal 'hot', input.mode
+
describe 'at runtime', ->
it 'is dirty when the result is dirty', ->
result\set 3
diff --git a/spec/match_spec.moon b/spec/match_spec.moon
index afaef56..8be64de 100644
--- a/spec/match_spec.moon
+++ b/spec/match_spec.moon
@@ -1,15 +1,18 @@
import val, evt from require 'alv.base.match'
+import Op, Input from require 'alv.base'
import RTNode, T, Error from require 'alv'
+op_with_inputs = (inputs) ->
+ with Op!
+ \setup inputs if inputs
+
mk_val = (type, const) ->
- result = T[type]\mk_sig!
- with RTNode :result
- .side_inputs = { 'fake' } unless const
+ result = T[type]\mk_sig true
+ RTNode :result, op: op_with_inputs { Input.hot result }
mk_evt = (type, const) ->
result = T[type]\mk_evt!
- with RTNode :result
- .side_inputs = { 'fake' } unless const
+ RTNode :result, op: op_with_inputs { Input.hot result }
describe 'val and evt', ->
describe 'type-less shorthand', ->
diff --git a/spec/rtnode_spec.moon b/spec/rtnode_spec.moon
index 9c62350..1719620 100644
--- a/spec/rtnode_spec.moon
+++ b/spec/rtnode_spec.moon
@@ -4,18 +4,23 @@ import T, Input, Op, Constant, IOStream from require 'alv.base'
setup do_setup
+class DirtyIO extends IOStream
+ new: => super T.dirty_io
+ dirty: => true
+
op_with_inputs = (inputs) ->
with Op!
\setup inputs if inputs
+dirty_op = ->
+ result = DirtyIO!
+ input = Input.hot result
+ result, input, op_with_inputs { input }
+
node_with_sideinput = (result, input) ->
with RTNode :result
.side_inputs = { [result]: input }
-class DirtyIO extends IOStream
- new: => super T.dirty_io
- dirty: => true
-
describe 'RTNode', ->
it 'wraps result, children', ->
result = Constant.num 3
@@ -69,23 +74,41 @@ describe 'RTNode', ->
value_input = Input.hot value
op = op_with_inputs { event_input, value_input }
- node = RTNode op: op, result: value
+ node = RTNode :op, result: value
assert.is.equal op, node.op
assert.is.same { [event]: event_input, [value]: value_input },
node.side_inputs
- it 'does not lift up op inputs that are also child values', ->
+ it 'does not lift up op inputs that are also children', ->
+ child_result, child_input, child_op = dirty_op!
+ result = T.num\mk_sig 4
+ child = RTNode op: child_op, :result
+
event = T.bang\mk_evt!
event_input = Input.hot event
+ input = Input.hot child
- result = T.num\mk_sig 4
- value_input = Input.hot result
+ op = op_with_inputs { event_input, input }
+ node = RTNode :op, children: { child }
- op = op_with_inputs { event_input, value_input }
- node = RTNode op: op, :result, children: { RTNode :result }
+ assert.is.same { [event]: event_input, [child_result]: child_input },
+ node.side_inputs
+
+ it 'does not lift up op inputs that are cold', ->
+ bang = T.bang\mk_const true
+ bang_input = Input.hot bang
+
+ num = T.num\mk_const 2
+ num_input = Input.cold num
+
+ sym = T.sym\mk_sig 'hello'
+ sym_input = Input.hot sym
+
+ op = op_with_inputs { bang_input, num_input, sym_input }
+ node = RTNode :op
- assert.is.same { [event]: event_input }, node.side_inputs
+ assert.is.same { [sym]: sym_input }, node.side_inputs
it 'lifts up side_inputs from children', ->
event_value = T.bang\mk_evt!
@@ -169,9 +192,7 @@ describe 'RTNode', ->
describe ':poll_io', ->
it 'polls IOs referenced in side_inputs', ->
- io = DirtyIO!
- input = Input.hot io
- op = op_with_inputs { input }
+ io, input, op = dirty_op!
node = RTNode :op
s = spy.on io, 'poll'