mirror of
https://github.com/littensy/charm.git
synced 2026-10-22 12:41:37 +00:00
fix: always return pending value in signal setter
This commit is contained in:
parent
6499a0064f
commit
ccdd539b28
2 changed files with 62 additions and 45 deletions
|
|
@ -226,11 +226,9 @@ local function run(effect: EffectNode)
|
||||||
|
|
||||||
purgeDeps(effect)
|
purgeDeps(effect)
|
||||||
|
|
||||||
if success then
|
if success and result then
|
||||||
if type(result) == "function" then
|
table.insert(effect.cleanups, wrapUserSpace(result))
|
||||||
table.insert(effect.cleanups, wrapUserSpace(result))
|
elseif not success then
|
||||||
end
|
|
||||||
else
|
|
||||||
error(result, 0)
|
error(result, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -442,6 +440,32 @@ local function signal<T>(initialValue: T, equals: Equals<T>?): (Getter<T>, Sette
|
||||||
deepFreeze(initialValue)
|
deepFreeze(initialValue)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function signalGetter(): T
|
||||||
|
-- Check if the signal has a pending update that needs to be applied
|
||||||
|
if bit32.btest(node.flags, DIRTY) then
|
||||||
|
if updateSignal(node) then
|
||||||
|
local subs = node.subs
|
||||||
|
if subs then
|
||||||
|
shallowPropagate(subs)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Register this signal as a dependency of the first subscriber in the
|
||||||
|
-- chain that is a computed signal or an effect
|
||||||
|
local sub = activeSub
|
||||||
|
while sub do
|
||||||
|
if bit32.btest(sub.flags, bit32.bor(MUTABLE, WATCHING)) then
|
||||||
|
link(node, sub, cycle)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local subs = sub.subs
|
||||||
|
sub = if subs then subs.sub else nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return node.currentValue
|
||||||
|
end
|
||||||
|
|
||||||
local function signalSetter(update: Update<T>): T
|
local function signalSetter(update: Update<T>): T
|
||||||
local value: T
|
local value: T
|
||||||
|
|
||||||
|
|
@ -475,37 +499,9 @@ local function signal<T>(initialValue: T, equals: Equals<T>?): (Getter<T>, Sette
|
||||||
propagate(subs)
|
propagate(subs)
|
||||||
flush()
|
flush()
|
||||||
end
|
end
|
||||||
|
|
||||||
return value
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return node.currentValue
|
return node.pendingValue
|
||||||
end
|
|
||||||
|
|
||||||
local function signalGetter(): T
|
|
||||||
-- Check if the signal has a pending update that needs to be applied
|
|
||||||
if bit32.btest(node.flags, DIRTY) then
|
|
||||||
if updateSignal(node) then
|
|
||||||
local subs = node.subs
|
|
||||||
if subs then
|
|
||||||
shallowPropagate(subs)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Register this signal as a dependency of the first subscriber in the
|
|
||||||
-- chain that is a computed signal or an effect
|
|
||||||
local sub = activeSub
|
|
||||||
while sub do
|
|
||||||
if bit32.btest(sub.flags, bit32.bor(MUTABLE, WATCHING)) then
|
|
||||||
link(node, sub, cycle)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
local subs = sub.subs
|
|
||||||
sub = if subs then subs.sub else nil
|
|
||||||
end
|
|
||||||
|
|
||||||
return node.currentValue
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return signalGetter, signalSetter
|
return signalGetter, signalSetter
|
||||||
|
|
@ -522,9 +518,11 @@ end
|
||||||
]]
|
]]
|
||||||
local function atom<T>(initialValue: T, equals: Equals<T>?): Atom<T>
|
local function atom<T>(initialValue: T, equals: Equals<T>?): Atom<T>
|
||||||
local get, set = signal(initialValue, equals)
|
local get, set = signal(initialValue, equals)
|
||||||
|
|
||||||
local function atomOper(...)
|
local function atomOper(...)
|
||||||
return if select("#", ...) == 0 then get() else set((...))
|
return if select("#", ...) == 0 then get() else set((...))
|
||||||
end
|
end
|
||||||
|
|
||||||
return atomOper
|
return atomOper
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -628,16 +626,15 @@ local function effect(fn: () -> ...Cleanup?): Cleanup
|
||||||
local success, result = pcall(node.fn)
|
local success, result = pcall(node.fn)
|
||||||
activeSub = prevSub
|
activeSub = prevSub
|
||||||
|
|
||||||
if success then
|
if success and result then
|
||||||
if type(result) == "function" then
|
table.insert(node.cleanups, wrapUserSpace(result))
|
||||||
table.insert(node.cleanups, wrapUserSpace(result))
|
elseif not success then
|
||||||
end
|
|
||||||
endBatch()
|
|
||||||
else
|
|
||||||
endBatch()
|
endBatch()
|
||||||
error(result, 2)
|
error(result, 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
endBatch()
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
stopEffect(node)
|
stopEffect(node)
|
||||||
end
|
end
|
||||||
|
|
@ -667,11 +664,9 @@ local function effectScope(fn: () -> ...Cleanup?, detached: boolean?): Cleanup
|
||||||
local success, result = pcall(wrapUserSpace(fn))
|
local success, result = pcall(wrapUserSpace(fn))
|
||||||
activeSub = prevSub
|
activeSub = prevSub
|
||||||
|
|
||||||
if success then
|
if success and result then
|
||||||
if type(result) == "function" then
|
table.insert(node.cleanups, wrapUserSpace(result))
|
||||||
table.insert(node.cleanups, wrapUserSpace(result))
|
elseif not success then
|
||||||
end
|
|
||||||
else
|
|
||||||
error(result, 2)
|
error(result, 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -750,9 +745,11 @@ local function untracked<Args..., Results...>(fn: (Args...) -> Results..., ...:
|
||||||
local prevSub = setActiveSub(nil)
|
local prevSub = setActiveSub(nil)
|
||||||
local results: { any } = { pcall(wrapUserSpace(fn), ...) }
|
local results: { any } = { pcall(wrapUserSpace(fn), ...) }
|
||||||
activeSub = prevSub
|
activeSub = prevSub
|
||||||
|
|
||||||
if not results[1] then
|
if not results[1] then
|
||||||
error(results[2], 2)
|
error(results[2], 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
return unpack(results, 2)
|
return unpack(results, 2)
|
||||||
else
|
else
|
||||||
return fn(...)
|
return fn(...)
|
||||||
|
|
@ -772,9 +769,11 @@ local function batch<Args..., Results...>(fn: (Args...) -> Results..., ...: Args
|
||||||
startBatch()
|
startBatch()
|
||||||
local results: { any } = { pcall(wrapUserSpace(fn), ...) }
|
local results: { any } = { pcall(wrapUserSpace(fn), ...) }
|
||||||
endBatch()
|
endBatch()
|
||||||
|
|
||||||
if not results[1] then
|
if not results[1] then
|
||||||
error(results[2], 2)
|
error(results[2], 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
return unpack(results, 2)
|
return unpack(results, 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,4 +46,22 @@ test("should not freeze values with metatables", function()
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
test("should setter return same value as getter even if equal", function()
|
||||||
|
local src, setSrc = signal(0, function()
|
||||||
|
return true
|
||||||
|
end)
|
||||||
|
assert(setSrc(1) == src(), `setSrc(1) expected 0, got {setSrc(1)}`)
|
||||||
|
end)
|
||||||
|
|
||||||
|
test("should setter return latest value", function()
|
||||||
|
local src, setSrc = signal(0)
|
||||||
|
effect(function()
|
||||||
|
if src() == 1 then
|
||||||
|
setSrc(2)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
assert(setSrc(1) == 2, `setSrc(1) expected 2, got {setSrc(1)}`)
|
||||||
|
assert(src() == 2, `src() expected 2, got {src()}`)
|
||||||
|
end)
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue