-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjoin.go
More file actions
64 lines (52 loc) · 1.95 KB
/
Copy pathjoin.go
File metadata and controls
64 lines (52 loc) · 1.95 KB
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
package incremental
import "github.com/PrositAS/go-incremental/internal/core"
// Join creates a node whose value tracks input's current value, unwrapping one level of
// dynamism - the Go counterpart of Incremental's join. Where Bind rebuilds its right-hand
// side by running a function whenever the left-hand side changes, Join's right-hand side
// is simply whatever node input currently points to: input.Value() is itself a node, and
// Join's result mirrors that node's value, updating whenever input points somewhere new.
func Join[T any](input core.ValueNode[core.ValueNode[T]]) core.ValueNode[T] {
j := &joinState[T]{lhs: input}
main := &joinMain[T]{Node: core.New[T](nil, nil), j: j}
main.SetKind(int(KindJoinMain))
lhsChange := &joinLHSChange[T]{Node: core.New[struct{}](nil, nil), j: j}
lhsChange.SetKind(int(KindJoinLHSChange))
core.AddEdge(lhsChange, input)
j.lhsChange = lhsChange
j.main = main
core.AddEdge(main, lhsChange)
return main
}
// joinState holds the state shared by a join's two nodes: the lhs-change watcher, which
// re-reads input, and the main result node, which copies the pointed-to node's value.
type joinState[T any] struct {
lhs core.ValueNode[core.ValueNode[T]]
lhsChange *joinLHSChange[T]
main *joinMain[T]
// rhs is written only by lhsChange.Recompute and read only by main.Recompute; see
// bindState.rhs for why that's race-free without its own lock.
rhs core.ValueNode[T]
}
type joinLHSChange[T any] struct {
*core.Node[struct{}]
j *joinState[T]
}
func (n *joinLHSChange[T]) Recompute(now core.StabilizationNum, round core.RoundCtx) {
rhs, _ := n.j.lhs.Value()
oldRHS := n.j.rhs
n.j.rhs = rhs
changeChild(round, n.j.main, oldRHS, rhs)
n.SetValue(struct{}{}, now)
}
type joinMain[T any] struct {
*core.Node[T]
j *joinState[T]
}
func (n *joinMain[T]) Recompute(now core.StabilizationNum, _ core.RoundCtx) {
if !n.j.rhs.IsValid() {
n.Invalidate()
return
}
v, _ := n.j.rhs.Value()
n.SetValue(v, now)
}