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> = {
|
export type StartNode<T> = {
|
||||||
cache: T,
|
cache: T,
|
||||||
children: { [Node<T>]: true } | false
|
children: { Node<T> } | false
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Node<T> = {
|
export type Node<T> = {
|
||||||
cache: T,
|
cache: T,
|
||||||
children: { [Node<T>]: true } | false,
|
parents: { StartNode<T> },
|
||||||
|
children: { Node<T> } | false,
|
||||||
effect: (T) -> () | false,
|
effect: (T) -> () | false,
|
||||||
cleanups: { () -> () } | false,
|
cleanups: { () -> () } | false,
|
||||||
}
|
}
|
||||||
|
|
||||||
local active = {} :: { [Node<any>]: true }
|
|
||||||
|
|
||||||
local scopes = { n = 0 } :: { [number]: Node<any>, n: number }
|
local scopes = { n = 0 } :: { [number]: Node<any>, n: number }
|
||||||
|
|
||||||
local WEAK_VALUES = { __mode = "v" }
|
local WEAK_VALUES = { __mode = "v" }
|
||||||
|
|
@ -59,11 +58,12 @@ end
|
||||||
|
|
||||||
local function add_child<T>(parent: StartNode<any>, child: Node<any>)
|
local function add_child<T>(parent: StartNode<any>, child: Node<any>)
|
||||||
if parent.children then
|
if parent.children then
|
||||||
parent.children[child] = true
|
table.insert(parent.children :: { Node<T> }, child)
|
||||||
else
|
else
|
||||||
parent.children = { [child] = true :: true }
|
parent.children = { child }
|
||||||
setmetatable(parent.children :: any, WEAK_KEYS) -- todo:
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
table.insert(child.parents, parent)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function open_scope<T>(node: Node<T>)
|
local function open_scope<T>(node: Node<T>)
|
||||||
|
|
@ -101,13 +101,25 @@ local function run_effect<T>(node: Node<T>)
|
||||||
end
|
end
|
||||||
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>)
|
local function destroy<T>(node: Node<T>)
|
||||||
run_cleanups(node)
|
run_cleanups(node)
|
||||||
active[node] = nil
|
unparent(node)
|
||||||
if node.children then
|
local children = node.children :: {}
|
||||||
for child in node.children do
|
if children then
|
||||||
destroy(child)
|
while children[1] do destroy(children[1]) end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -117,12 +129,15 @@ local update_queue = {} :: { Node<any> }
|
||||||
local function rec<T>(node: StartNode<T>)
|
local function rec<T>(node: StartNode<T>)
|
||||||
if not node.children then return end
|
if not node.children then return end
|
||||||
|
|
||||||
for child in next, node.children do
|
local children = node.children :: {}
|
||||||
table.insert(update_queue, child)
|
|
||||||
rec(child)
|
while children[1] do
|
||||||
|
table.insert(update_queue, children[1])
|
||||||
|
rec(children[1])
|
||||||
|
unparent(children[1])
|
||||||
end
|
end
|
||||||
|
|
||||||
table.clear(node.children)
|
table.clear(children)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function update<T>(node: StartNode<T>)
|
local function update<T>(node: StartNode<T>)
|
||||||
|
|
@ -156,11 +171,10 @@ local function create_node<T>(value: T): Node<T>
|
||||||
cache = value,
|
cache = value,
|
||||||
effect = false,
|
effect = false,
|
||||||
cleanups = false :: false,
|
cleanups = false :: false,
|
||||||
|
parents = {},
|
||||||
children = false :: false
|
children = false :: false
|
||||||
}
|
}
|
||||||
|
|
||||||
active[node] = true
|
|
||||||
|
|
||||||
return node
|
return node
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -169,7 +183,7 @@ local function get_children<T>(node: Node<T>): { Node<unknown> }
|
||||||
|
|
||||||
local children = {}
|
local children = {}
|
||||||
|
|
||||||
for child in node.children do
|
for _, child in node.children do
|
||||||
table.insert(children, child)
|
table.insert(children, child)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ TEST("graph", function()
|
||||||
CHECK(count == 3)
|
CHECK(count == 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE "diamond problem"
|
do CASE "diamond graph"
|
||||||
local a, b, c, d = node(), node(), node(), node()
|
local a, b, c, d = node(), node(), node(), node()
|
||||||
|
|
||||||
local b_cnt, c_cnt, d_cnt = 0, 0, 0
|
local b_cnt, c_cnt, d_cnt = 0, 0, 0
|
||||||
|
|
@ -119,7 +119,7 @@ TEST("graph", function()
|
||||||
|
|
||||||
CHECK(b_cnt == 1)
|
CHECK(b_cnt == 1)
|
||||||
CHECK(c_cnt == 1)
|
CHECK(c_cnt == 1)
|
||||||
CHECK(d_cnt == 2) -- confirm current behavior
|
CHECK(d_cnt == 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE "duplicate child on rerun"
|
do CASE "duplicate child on rerun"
|
||||||
|
|
@ -387,6 +387,36 @@ TEST("derive()", wrap_root(function()
|
||||||
CHECK(count == 4)
|
CHECK(count == 4)
|
||||||
end
|
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"
|
do CASE "garbage collection"
|
||||||
-- check that `b` does not allow gc of `a`
|
-- check that `b` does not allow gc of `a`
|
||||||
local a = source(1)
|
local a = source(1)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue