mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
Disallow creation of nested tracking scopes
This commit is contained in:
parent
c0c2166edf
commit
38342b3805
6 changed files with 256 additions and 109 deletions
|
|
@ -10,7 +10,7 @@ export type StartNode<T> = {
|
|||
|
||||
export type Node<T> = {
|
||||
cache: T,
|
||||
effect: ((T) -> T) | false,
|
||||
effect: ((T) -> T) | "owner" | "untracked",
|
||||
cleanups: { () -> () } | false,
|
||||
parents: { owner: StartNode<T>?, [number]: StartNode<T> },
|
||||
[number]: Node<T>
|
||||
|
|
@ -50,8 +50,8 @@ local function get_owning_scope(): Node<unknown>
|
|||
if not scope then
|
||||
local caller_name = debug.info(2, "n")
|
||||
return throw(`cannot use {caller_name}() in non-reactive scope, must be used within a root() or mount() callback`)
|
||||
elseif scope.effect then
|
||||
throw("owning scope is not stable; are you trying to derive a new source from within a side-effect?")
|
||||
elseif scope.effect ~= "owner" then
|
||||
throw("reactive scope is not an owning scope; new effects cannot be created in side-effects")
|
||||
end
|
||||
return scope
|
||||
end
|
||||
|
|
@ -117,8 +117,6 @@ local function destroy<T>(node: Node<T>)
|
|||
run_cleanups(node)
|
||||
unparent(node)
|
||||
|
||||
node.effect = false
|
||||
|
||||
if node.parents.owner then
|
||||
remove_child(node.parents.owner, node)
|
||||
node.parents.owner = nil
|
||||
|
|
@ -168,24 +166,13 @@ local function update_from<T>(node: StartNode<T>, n0: number)
|
|||
|
||||
-- unparent all children and queue for eval
|
||||
do
|
||||
local i = 1
|
||||
local child = node[i]
|
||||
local child = node[1]
|
||||
while child do
|
||||
--assert(child.parents.owner)
|
||||
unparent(child)
|
||||
|
||||
n += 1
|
||||
update_queue[n] = child
|
||||
|
||||
local next_child = node[i]
|
||||
|
||||
-- children who have this parent as an owner will not be unparented
|
||||
-- if such a child is encountered then skip it
|
||||
if next_child == child then
|
||||
i += 1
|
||||
next_child = node[i]
|
||||
end
|
||||
|
||||
child = next_child
|
||||
child = node[1]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -194,7 +181,7 @@ local function update_from<T>(node: StartNode<T>, n0: number)
|
|||
-- evaluate all queued children
|
||||
for i = n0 + 1, n do
|
||||
local child = update_queue[i]
|
||||
if not child.effect then continue end
|
||||
assert(type(child.effect) == "function")
|
||||
|
||||
if evaluate_node(child) then
|
||||
update_from(child, n)
|
||||
|
|
@ -212,12 +199,12 @@ end
|
|||
|
||||
local function track<T>(node: StartNode<T>)
|
||||
local scope = get_scope()
|
||||
if scope and scope.effect then -- do not track nodes with no effect
|
||||
if scope and type(scope.effect) == "function" then -- do not track nodes with no effect
|
||||
add_child(node, scope)
|
||||
end
|
||||
end
|
||||
|
||||
local function create_node<T>(value: T, effect: false | (T) -> T): Node<T>
|
||||
local function create_node<T>(value: T, effect: "owner" | (T) -> T): Node<T>
|
||||
return {
|
||||
cache = value,
|
||||
effect = effect,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ end
|
|||
local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI, K) -> VO): () -> { VO }
|
||||
local owner = get_owning_scope()
|
||||
|
||||
local subowner = create_node(false, false)
|
||||
local subowner = create_node(false, "owner")
|
||||
set_owner(subowner, owner)
|
||||
|
||||
local input_cache = {} :: Map<K, VI>
|
||||
|
|
@ -67,7 +67,7 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
|
|||
|
||||
if cv ~= v then
|
||||
if cv == nil then -- create new scope and run transform
|
||||
local scope = create_node(false, false)
|
||||
local scope = create_node(false, "owner")
|
||||
scopes[i] = scope :: Node<any>
|
||||
|
||||
local node = create_start_node(v)
|
||||
|
|
@ -112,6 +112,7 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
|
|||
local node = create_node(false :: any, function()
|
||||
return update_children(input())
|
||||
end)
|
||||
set_owner(node, owner)
|
||||
|
||||
evaluate_node(node)
|
||||
|
||||
|
|
@ -124,7 +125,7 @@ end
|
|||
local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () -> K) -> VO): () -> { VO }
|
||||
local owner = get_owning_scope()
|
||||
|
||||
local subowner = create_node(false, false)
|
||||
local subowner = create_node(false, "owner")
|
||||
set_owner(subowner, owner)
|
||||
|
||||
local cur_input_cache_up = {} :: Map<VI, K>
|
||||
|
|
@ -155,7 +156,7 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
|
|||
local cv = cur_input_cache[v]
|
||||
|
||||
if cv == nil then -- create new scope and run transform
|
||||
local scope = create_node(false, false)
|
||||
local scope = create_node(false, "owner")
|
||||
scopes[v] = scope :: Node<any>
|
||||
|
||||
local node = create_start_node(i)
|
||||
|
|
@ -214,6 +215,7 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
|
|||
local node = create_node(false :: any, function()
|
||||
return update_children(input())
|
||||
end)
|
||||
set_owner(node, owner)
|
||||
|
||||
evaluate_node(node)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ local destroy = graph.destroy
|
|||
local refs = {}
|
||||
|
||||
local function root<T...>(fn: (destroy: () -> ()) -> T...): T...
|
||||
local node = create_node(false, false)
|
||||
local node = create_node(false, "owner")
|
||||
|
||||
refs[node] = true -- prevent gc of root node
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ local function switch<T, U>(source: () -> T): (map: Map<T, ((() -> U)?)>) -> ()
|
|||
throw("map must map a value to a function")
|
||||
end
|
||||
|
||||
local new_scope = create_node(false, false)
|
||||
local new_scope = create_node(false, "owner")
|
||||
last_scope = new_scope :: Node<any>
|
||||
|
||||
set_owner(new_scope, owner)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ local function untrack<T>(source: () -> T): T
|
|||
|
||||
-- sources are only tracked if the node in scope has an effect
|
||||
local effect = scope.effect
|
||||
scope.effect = false
|
||||
scope.effect = "untracked"
|
||||
|
||||
local ok, result = pcall(source)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue