exercism/go/react/react.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))
}