mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
This commit is contained in:
parent
4f9db6ff41
commit
3ecec1f787
2 changed files with 65 additions and 21 deletions
|
|
@ -5,18 +5,17 @@ local flags = require(script.Parent.flags)
|
|||
|
||||
export type StartNode<T> = {
|
||||
cache: T,
|
||||
children: { [Node<T>]: true } | false
|
||||
children: { Node<T> } | false
|
||||
}
|
||||
|
||||
export type Node<T> = {
|
||||
cache: T,
|
||||
children: { [Node<T>]: true } | false,
|
||||
parents: { StartNode<T> },
|
||||
children: { Node<T> } | false,
|
||||
effect: (T) -> () | false,
|
||||
cleanups: { () -> () } | false,
|
||||
}
|
||||
|
||||
local active = {} :: { [Node<any>]: true }
|
||||
|
||||
local scopes = { n = 0 } :: { [number]: Node<any>, n: number }
|
||||
|
||||
local WEAK_VALUES = { __mode = "v" }
|
||||
|
|
@ -59,11 +58,12 @@ end
|
|||
|
||||
local function add_child<T>(parent: StartNode<any>, child: Node<any>)
|
||||
if parent.children then
|
||||
parent.children[child] = true
|
||||
table.insert(parent.children :: { Node<T> }, child)
|
||||
else
|
||||
parent.children = { [child] = true :: true }
|
||||
setmetatable(parent.children :: any, WEAK_KEYS) -- todo:
|
||||
parent.children = { child }
|
||||
end
|
||||
|
||||
table.insert(child.parents, parent)
|
||||
end
|
||||
|
||||
local function open_scope<T>(node: Node<T>)
|
||||
|
|
@ -101,13 +101,25 @@ local function run_effect<T>(node: Node<T>)
|
|||
end
|
||||
end
|
||||
|
||||
local function unparent<T>(node: Node<T>)
|
||||
for _, parent in node.parents do
|
||||
local children = parent.children :: {}
|
||||
local idx = table.find(children :: {}, node)
|
||||
|
||||
local n = #children
|
||||
children[idx] = children[n]
|
||||
children[n] = nil
|
||||
end
|
||||
|
||||
table.clear(node.parents)
|
||||
end
|
||||
|
||||
local function destroy<T>(node: Node<T>)
|
||||
run_cleanups(node)
|
||||
active[node] = nil
|
||||
if node.children then
|
||||
for child in node.children do
|
||||
destroy(child)
|
||||
end
|
||||
unparent(node)
|
||||
local children = node.children :: {}
|
||||
if children then
|
||||
while children[1] do destroy(children[1]) end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -117,12 +129,15 @@ local update_queue = {} :: { Node<any> }
|
|||
local function rec<T>(node: StartNode<T>)
|
||||
if not node.children then return end
|
||||
|
||||
for child in next, node.children do
|
||||
table.insert(update_queue, child)
|
||||
rec(child)
|
||||
local children = node.children :: {}
|
||||
|
||||
while children[1] do
|
||||
table.insert(update_queue, children[1])
|
||||
rec(children[1])
|
||||
unparent(children[1])
|
||||
end
|
||||
|
||||
table.clear(node.children)
|
||||
table.clear(children)
|
||||
end
|
||||
|
||||
local function update<T>(node: StartNode<T>)
|
||||
|
|
@ -156,11 +171,10 @@ local function create_node<T>(value: T): Node<T>
|
|||
cache = value,
|
||||
effect = false,
|
||||
cleanups = false :: false,
|
||||
parents = {},
|
||||
children = false :: false
|
||||
}
|
||||
|
||||
active[node] = true
|
||||
|
||||
return node
|
||||
end
|
||||
|
||||
|
|
@ -169,7 +183,7 @@ local function get_children<T>(node: Node<T>): { Node<unknown> }
|
|||
|
||||
local children = {}
|
||||
|
||||
for child in node.children do
|
||||
for _, child in node.children do
|
||||
table.insert(children, child)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ TEST("graph", function()
|
|||
CHECK(count == 3)
|
||||
end
|
||||
|
||||
do CASE "diamond problem"
|
||||
do CASE "diamond graph"
|
||||
local a, b, c, d = node(), node(), node(), node()
|
||||
|
||||
local b_cnt, c_cnt, d_cnt = 0, 0, 0
|
||||
|
|
@ -119,7 +119,7 @@ TEST("graph", function()
|
|||
|
||||
CHECK(b_cnt == 1)
|
||||
CHECK(c_cnt == 1)
|
||||
CHECK(d_cnt == 2) -- confirm current behavior
|
||||
CHECK(d_cnt == 1)
|
||||
end
|
||||
|
||||
do CASE "duplicate child on rerun"
|
||||
|
|
@ -387,6 +387,36 @@ TEST("derive()", wrap_root(function()
|
|||
CHECK(count == 4)
|
||||
end
|
||||
|
||||
do CASE "conditional derive"
|
||||
local a = source(false)
|
||||
local b = source(false)
|
||||
|
||||
local c = derive(function()
|
||||
return
|
||||
if a() then "a"
|
||||
elseif b() then "b"
|
||||
else "never"
|
||||
end)
|
||||
|
||||
local count = 0
|
||||
|
||||
watch(function() count += 1 end)
|
||||
|
||||
b(true)
|
||||
CHECK(c() == "b")
|
||||
CHECK(count == 2)
|
||||
a(true)
|
||||
CHECK(c() == "a")
|
||||
CHECK(count == 3)
|
||||
b(false)
|
||||
CHECK(count == 3)
|
||||
b(true)
|
||||
CHECK(count == 3)
|
||||
a(false)
|
||||
CHECK(c() == "b")
|
||||
CHECK(count == 4)
|
||||
end
|
||||
|
||||
do CASE "garbage collection"
|
||||
-- check that `b` does not allow gc of `a`
|
||||
local a = source(1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue