use the generated getters to make the reactive extensions more robust
This commit is contained in:
parent
e70924c88e
commit
539f6d7244
1 changed files with 58 additions and 43 deletions
101
src/reactive.nim
101
src/reactive.nim
|
|
@ -20,7 +20,7 @@ type
|
||||||
ReactiveBase* = ref object of RootObj ## everything that is a "reactive"
|
ReactiveBase* = ref object of RootObj ## everything that is a "reactive"
|
||||||
## value derives from that
|
## value derives from that
|
||||||
sinks*: SinkSeq
|
sinks*: SinkSeq
|
||||||
dups: JDict[cstring, bool]
|
dups: JDict[cstring, int]
|
||||||
id: int
|
id: int
|
||||||
Reactive*[T] = ref object of ReactiveBase
|
Reactive*[T] = ref object of ReactiveBase
|
||||||
value*: T
|
value*: T
|
||||||
|
|
@ -38,13 +38,16 @@ type
|
||||||
var rid: int
|
var rid: int
|
||||||
|
|
||||||
proc addSink(x: ReactiveBase; key: cstring; sink: proc(msg: Message; pos: int)) =
|
proc addSink(x: ReactiveBase; key: cstring; sink: proc(msg: Message; pos: int)) =
|
||||||
if x.dups == nil: x.dups = newJDict[cstring, bool]()
|
if x.dups == nil: x.dups = newJDict[cstring, int]()
|
||||||
if not x.dups.contains(key):
|
if not x.dups.contains(key):
|
||||||
x.dups[key] = true
|
x.dups[key] = x.sinks.len
|
||||||
x.sinks.add sink
|
x.sinks.add sink
|
||||||
if x.id == 0:
|
if x.id == 0:
|
||||||
inc rid
|
inc rid
|
||||||
x.id = rid
|
x.id = rid
|
||||||
|
else:
|
||||||
|
# update existing entry:
|
||||||
|
x.sinks[x.dups[key]] = sink
|
||||||
|
|
||||||
proc addSink(x: ReactiveBase; sink: proc(msg: Message; pos: int)) =
|
proc addSink(x: ReactiveBase; sink: proc(msg: Message; pos: int)) =
|
||||||
x.sinks.add sink
|
x.sinks.add sink
|
||||||
|
|
@ -58,12 +61,16 @@ proc broadcast(x: ReactiveBase, msg: Message; pos = 0) =
|
||||||
if inhibited == 0:
|
if inhibited == 0:
|
||||||
for s in x.sinks: s(msg, pos)
|
for s in x.sinks: s(msg, pos)
|
||||||
|
|
||||||
var toTrack: proc (msg: Message; pos: int) = nil
|
var toTrack: seq[(cstring, proc (msg: Message; pos: int))] = @[]
|
||||||
|
|
||||||
proc now*[T](x: Reactive[T]): T =
|
template withTrack(key, t, body) =
|
||||||
if toTrack != nil:
|
toTrack.add((key, t))
|
||||||
x.addSink toTrack
|
body
|
||||||
result = x.value
|
discard toTrack.pop()
|
||||||
|
|
||||||
|
proc trackDependency*(r: ReactiveBase) =
|
||||||
|
for t in toTrack:
|
||||||
|
r.addSink t[0], t[1]
|
||||||
|
|
||||||
template wrapObserver(f: untyped) =
|
template wrapObserver(f: untyped) =
|
||||||
var state: State
|
var state: State
|
||||||
|
|
@ -114,11 +121,6 @@ template glitchFree(f: untyped) =
|
||||||
x.broadcast(msg, pos)
|
x.broadcast(msg, pos)
|
||||||
helper
|
helper
|
||||||
|
|
||||||
proc `:=`[T](x: Reactive[T], f: proc(): T) =
|
|
||||||
toTrack = wrapObserver(f())
|
|
||||||
x.value = f()
|
|
||||||
toTrack = nil
|
|
||||||
|
|
||||||
proc `<-`*[T](x: Reactive[T], val: T) =
|
proc `<-`*[T](x: Reactive[T], val: T) =
|
||||||
#if x.value != val:
|
#if x.value != val:
|
||||||
x.value = val
|
x.value = val
|
||||||
|
|
@ -204,25 +206,31 @@ proc deleteElem*[T](x: RSeq[T]; y: T) =
|
||||||
x.broadcast(Mark)
|
x.broadcast(Mark)
|
||||||
x.broadcast(Deleted, position)
|
x.broadcast(Deleted, position)
|
||||||
|
|
||||||
proc map*[T, U](x: RSeq[T], f: proc(x: T): U): RSeq[U] =
|
when false:
|
||||||
let xl = x.L.value
|
proc `:=`[T](x: Reactive[T], f: proc(): T) =
|
||||||
let res = newRSeq[U](xl)
|
toTrack = wrapObserver(f())
|
||||||
for i in 0..<xl:
|
x.value = f()
|
||||||
res.s[i] := proc(): U = f(x[i].now)
|
toTrack = nil
|
||||||
|
|
||||||
let reactor = proc (msg: Message, pos: int) =
|
proc map*[T, U](x: RSeq[T], f: proc(x: T): U): RSeq[U] =
|
||||||
case msg:
|
let xl = x.L.value
|
||||||
of Mark, Changed, Unchanged: discard "nothing to do"
|
let res = newRSeq[U](xl)
|
||||||
of Inserted:
|
for i in 0..<xl:
|
||||||
res.insert(f(x[pos]), pos)
|
res.s[i] := proc(): U = f(x[i].now)
|
||||||
of Deleted:
|
|
||||||
res.delete(pos)
|
let reactor = proc (msg: Message, pos: int) =
|
||||||
x.addSink reactor
|
case msg:
|
||||||
result = res
|
of Mark, Changed, Unchanged: discard "nothing to do"
|
||||||
|
of Inserted:
|
||||||
|
res.insert(f(x[pos]), pos)
|
||||||
|
of Deleted:
|
||||||
|
res.delete(pos)
|
||||||
|
x.addSink reactor
|
||||||
|
result = res
|
||||||
|
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
template protect(r: ReactiveBase; body: untyped) =
|
template protect(body: untyped) =
|
||||||
#var tmp: seq[proc(msg: Message, pos: int)]
|
#var tmp: seq[proc(msg: Message, pos: int)]
|
||||||
#swap(r.sinks, tmp)
|
#swap(r.sinks, tmp)
|
||||||
inc inhibited
|
inc inhibited
|
||||||
|
|
@ -230,14 +238,17 @@ template protect(r: ReactiveBase; body: untyped) =
|
||||||
dec inhibited
|
dec inhibited
|
||||||
#swap(r.sinks, tmp)
|
#swap(r.sinks, tmp)
|
||||||
|
|
||||||
template trackImpl(r: ReactiveBase; key: cstring; a, b: untyped) =
|
template trackStart(key: cstring; a, b: untyped) =
|
||||||
when r is ReactiveBase:
|
proc differ(m: Message; pos: int) =
|
||||||
addSink r, key, proc(m: Message; pos: int) =
|
if m == Changed:
|
||||||
if m == Changed:
|
protect:
|
||||||
protect r:
|
karax.runDiff(kxi, a, b)
|
||||||
karax.runDiff(kxi, a, b)
|
toTrack.add((key, differ))
|
||||||
|
|
||||||
template doTrack*(r: ReactiveBase; a, b: untyped) {.dirty.} =
|
template trackEnd() =
|
||||||
|
discard toTrack.pop()
|
||||||
|
|
||||||
|
template doTrack(r: ReactiveBase; a, b: untyped) {.dirty.} =
|
||||||
bind addSink, Message, RSeq, Changed, Deleted, Inserted
|
bind addSink, Message, RSeq, Changed, Deleted, Inserted
|
||||||
addSink r, proc(m: Message; pos: int) =
|
addSink r, proc(m: Message; pos: int) =
|
||||||
#when r is RSeq:
|
#when r is RSeq:
|
||||||
|
|
@ -246,7 +257,7 @@ template doTrack*(r: ReactiveBase; a, b: untyped) {.dirty.} =
|
||||||
protect r:
|
protect r:
|
||||||
karax.runDiff(kxi, a, b)
|
karax.runDiff(kxi, a, b)
|
||||||
|
|
||||||
template doTrackResize*(r: ReactiveBase; a, b: untyped) {.dirty.} =
|
template doTrackResize(r: ReactiveBase; a, b: untyped) {.dirty.} =
|
||||||
bind addSink, Message, RSeq, Changed, Deleted, Inserted
|
bind addSink, Message, RSeq, Changed, Deleted, Inserted
|
||||||
addSink r, proc(m: Message; pos: int) =
|
addSink r, proc(m: Message; pos: int) =
|
||||||
#when r is RSeq:
|
#when r is RSeq:
|
||||||
|
|
@ -264,8 +275,6 @@ macro track*(procDef: untyped): untyped =
|
||||||
var inner = copyNimTree(procDef)
|
var inner = copyNimTree(procDef)
|
||||||
inner[0] = ident($procDef.name & "Inner")
|
inner[0] = ident($procDef.name & "Inner")
|
||||||
var call = newCall(inner[0])
|
var call = newCall(inner[0])
|
||||||
trackings.add inner
|
|
||||||
trackings.add newAssignment(ident"result", call)
|
|
||||||
|
|
||||||
for j in 1..<params.len:
|
for j in 1..<params.len:
|
||||||
let x = params[j]
|
let x = params[j]
|
||||||
|
|
@ -274,9 +283,11 @@ macro track*(procDef: untyped): untyped =
|
||||||
let param = x[i]
|
let param = x[i]
|
||||||
call.add(param)
|
call.add(param)
|
||||||
|
|
||||||
let key = lineInfo(procDef)
|
trackings.add inner
|
||||||
for j in 1..<call.len:
|
let key = newCall("cstring", newLit lineInfo(procDef))
|
||||||
trackings.add getAst(trackImpl(call[j], key, ident"result", call))
|
trackings.add getAst(trackStart(key, ident"result", call))
|
||||||
|
trackings.add newAssignment(ident"result", call)
|
||||||
|
trackings.add getAst(trackEnd())
|
||||||
|
|
||||||
result = copyNimTree(procDef)
|
result = copyNimTree(procDef)
|
||||||
result.body = trackings
|
result.body = trackings
|
||||||
|
|
@ -285,7 +296,9 @@ macro track*(procDef: untyped): untyped =
|
||||||
|
|
||||||
proc generatePrivateAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
proc generatePrivateAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
||||||
template helper(name, hidden, typ, fieldTyp) {.dirty.} =
|
template helper(name, hidden, typ, fieldTyp) {.dirty.} =
|
||||||
proc name(self: typ): fieldTyp = self.hidden
|
proc name(self: typ): fieldTyp =
|
||||||
|
trackDependency(self)
|
||||||
|
result = self.hidden
|
||||||
proc `name=`(self: typ; val: fieldTyp) =
|
proc `name=`(self: typ; val: fieldTyp) =
|
||||||
self.hidden = val
|
self.hidden = val
|
||||||
notifyObservers(self)
|
notifyObservers(self)
|
||||||
|
|
@ -293,7 +306,9 @@ proc generatePrivateAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
||||||
|
|
||||||
proc generatePublicAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
proc generatePublicAccessors(name, hidden, typ, fieldTyp: NimNode): NimNode =
|
||||||
template helper(name, hidden, typ, fieldTyp) {.dirty.} =
|
template helper(name, hidden, typ, fieldTyp) {.dirty.} =
|
||||||
proc name*(self: typ): fieldTyp = self.hidden
|
proc name*(self: typ): fieldTyp =
|
||||||
|
trackDependency(self)
|
||||||
|
result = self.hidden
|
||||||
proc `name=`*(self: typ; val: fieldTyp) =
|
proc `name=`*(self: typ; val: fieldTyp) =
|
||||||
self.hidden = val
|
self.hidden = val
|
||||||
notifyObservers(self)
|
notifyObservers(self)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue