117 lines
2.6 KiB
Go
117 lines
2.6 KiB
Go
package react
|
|
|
|
import "strconv"
|
|
|
|
const testVersion = 4
|
|
|
|
// MyReactor implements Reactor
|
|
type MyReactor struct {
|
|
lastId int
|
|
cells []Cell
|
|
}
|
|
|
|
// New creates a new Reactor
|
|
func New() *MyReactor {
|
|
r := &MyReactor{}
|
|
return r
|
|
}
|
|
|
|
// CreateInput builds an input cell and adds it to the reactor
|
|
func (r *MyReactor) CreateInput(i int) InputCell {
|
|
r.lastId++
|
|
ic := MyCell{val: i, id: r.lastId}
|
|
ic.previousVal = ic.Value()
|
|
return &ic
|
|
}
|
|
|
|
// CreateCompute1 Takes a cell and a function and returns a compute cell
|
|
// which has a value based on running the function on the cells value.
|
|
func (r *MyReactor) CreateCompute1(c Cell, f func(int) int) ComputeCell {
|
|
r.lastId++
|
|
cc := &MyCell{id: r.lastId, isComputed: true}
|
|
cc.compVal = func() int { return f(c.Value()) }
|
|
cc.previousVal = cc.Value()
|
|
c.(*MyCell).addDependent(cc)
|
|
return cc
|
|
}
|
|
|
|
// CreateCompute2 Takes two cells and a function and returns a compute cell
|
|
// which has a value based on running the function on the cells values.
|
|
func (r *MyReactor) CreateCompute2(c1, c2 Cell, f func(int, int) int) ComputeCell {
|
|
r.lastId++
|
|
cc := &MyCell{id: r.lastId, isComputed: true}
|
|
cc.compVal = func() int { return f(c1.Value(), c2.Value()) }
|
|
cc.previousVal = cc.Value()
|
|
c1.(*MyCell).addDependent(cc)
|
|
c2.(*MyCell).addDependent(cc)
|
|
return cc
|
|
}
|
|
|
|
// MyCell implements the all Cell interfaces
|
|
type MyCell struct {
|
|
id int
|
|
isComputed bool
|
|
val int
|
|
compVal func() int
|
|
lastCallbackId int
|
|
callbacks map[int]func(int)
|
|
dependents []Cell
|
|
previousVal int
|
|
}
|
|
|
|
// Value returns the value of the cell
|
|
func (c MyCell) Value() int {
|
|
if c.isComputed {
|
|
return c.compVal()
|
|
}
|
|
return c.val
|
|
}
|
|
|
|
// SetValue sets the value on the cell
|
|
func (c *MyCell) SetValue(i int) {
|
|
if i == c.val || c.isComputed {
|
|
// No change or this is a computed cell, just return
|
|
return
|
|
}
|
|
c.previousVal = c.val
|
|
c.val = i
|
|
c.updated()
|
|
}
|
|
|
|
func i(v int) string {
|
|
return strconv.Itoa(v)
|
|
}
|
|
|
|
func (c *MyCell) updated() {
|
|
if c.Value() == c.previousVal {
|
|
// Value didn't change, done.
|
|
return
|
|
}
|
|
c.previousVal = c.Value()
|
|
// Triggers callbacks
|
|
for _, v := range c.callbacks {
|
|
v(c.Value())
|
|
}
|
|
// Hit 'updated' on all dependents
|
|
for _, v := range c.dependents {
|
|
v.(*MyCell).updated()
|
|
}
|
|
}
|
|
|
|
func (c *MyCell) addDependent(nc Cell) {
|
|
c.dependents = append(c.dependents, nc)
|
|
}
|
|
|
|
func (c *MyCell) AddCallback(cb func(int)) CallbackHandle {
|
|
if c.lastCallbackId == 0 {
|
|
c.callbacks = make(map[int]func(int))
|
|
}
|
|
c.lastCallbackId++
|
|
c.callbacks[c.lastCallbackId] = cb
|
|
return c.lastCallbackId
|
|
}
|
|
|
|
func (c *MyCell) RemoveCallback(cbh CallbackHandle) {
|
|
delete(c.callbacks, cbh.(int))
|
|
}
|