mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
This commit is contained in:
parent
bbe634f433
commit
31b1956b5a
6 changed files with 54 additions and 41 deletions
|
|
@ -9,7 +9,7 @@ Creates and runs a function in a new reactive scope.
|
||||||
- **Type**
|
- **Type**
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function root<T>(fn: () -> T): (T, () -> ())
|
function root<T...>(fn: (destroy: () -> ()) -> T...): T...
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Details**
|
- **Details**
|
||||||
|
|
@ -19,8 +19,8 @@ Creates and runs a function in a new reactive scope.
|
||||||
|
|
||||||
Returns the result of the given function.
|
Returns the result of the given function.
|
||||||
|
|
||||||
Also returns a function to destroy the root, which will run any cleanups
|
A function to destroy the root is passed into the callback, which will run
|
||||||
and allow derived sources created to garbage collect.
|
any cleanups and allow derived sources created to garbage collect.
|
||||||
|
|
||||||
::: warning
|
::: warning
|
||||||
`fn()` cannot yield.
|
`fn()` cannot yield.
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,8 @@ local function destroy<T>(node: Node<T>)
|
||||||
run_cleanups(node)
|
run_cleanups(node)
|
||||||
unparent(node)
|
unparent(node)
|
||||||
|
|
||||||
|
node.effect = false
|
||||||
|
|
||||||
if node.parents.owner then
|
if node.parents.owner then
|
||||||
remove_child(node.parents.owner, node)
|
remove_child(node.parents.owner, node)
|
||||||
node.parents.owner = nil
|
node.parents.owner = nil
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,12 @@ if not game then script = require "test/relative-string" end
|
||||||
local root = require(script.Parent.root)
|
local root = require(script.Parent.root)
|
||||||
local apply = require(script.Parent.apply)
|
local apply = require(script.Parent.apply)
|
||||||
|
|
||||||
local function mount<T>(app: () -> T, target: Instance?): () -> ()
|
local function mount<T>(component: () -> T, target: Instance?): () -> ()
|
||||||
local _, destroy = root(function()
|
return root(function(destroy)
|
||||||
local result = app()
|
local result = component()
|
||||||
if target then apply(target, { result }) end
|
if target then apply(target, { result }) end
|
||||||
return nil
|
|
||||||
end)
|
|
||||||
|
|
||||||
return destroy
|
return destroy
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
return mount
|
return mount :: (<T>(component: () -> T, target: Instance) -> () -> ()) & ((component: () -> ()) -> () -> ())
|
||||||
|
|
|
||||||
|
|
@ -10,25 +10,29 @@ local destroy = graph.destroy
|
||||||
|
|
||||||
local refs = {}
|
local refs = {}
|
||||||
|
|
||||||
local function root<T>(fn: () -> T): (T, () -> ())
|
local function root<T...>(fn: (destroy: () -> ()) -> T...): T...
|
||||||
local node = create_node(false, false)
|
local node = create_node(false, false)
|
||||||
|
|
||||||
open_scope(node)
|
|
||||||
|
|
||||||
local ok, result = pcall(fn)
|
|
||||||
|
|
||||||
close_scope()
|
|
||||||
|
|
||||||
if not ok then
|
|
||||||
throw(`mount error\n{result}`)
|
|
||||||
end
|
|
||||||
|
|
||||||
refs[node] = true -- prevent gc of root node
|
refs[node] = true -- prevent gc of root node
|
||||||
|
|
||||||
return result, function()
|
local destroy = function()
|
||||||
|
if not refs[node] then throw "root already destroyed" end
|
||||||
refs[node] = nil
|
refs[node] = nil
|
||||||
destroy(node)
|
destroy(node)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
open_scope(node)
|
||||||
|
|
||||||
|
local result = { pcall(fn, destroy) }
|
||||||
|
|
||||||
|
close_scope()
|
||||||
|
|
||||||
|
if not result[1] then
|
||||||
|
refs[node] = nil
|
||||||
|
throw(`mount error\n{result}`)
|
||||||
end
|
end
|
||||||
|
|
||||||
return root :: (<T>(fn: () -> T) -> (T, () -> ())) & ((fn: () -> ()) -> (nil, () -> ()))
|
return unpack(result :: any, 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
return root :: (<T...>(fn: (destroy: () -> ()) -> T...) -> T...) & ((fn: (destroy: () -> ()) -> ()) -> ())
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@ end
|
||||||
local N = 2^18 -- 262144
|
local N = 2^18 -- 262144
|
||||||
|
|
||||||
local function WRAP_BENCH(name: string, fn: () -> ())
|
local function WRAP_BENCH(name: string, fn: () -> ())
|
||||||
local _, destroy = vide.root(function()
|
vide.root(function(destroy)
|
||||||
BENCH(name, fn)
|
BENCH(name, fn)
|
||||||
end)
|
return destroy
|
||||||
destroy()
|
end)()
|
||||||
end
|
end
|
||||||
|
|
||||||
TITLE "sources"
|
TITLE "sources"
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ end
|
||||||
|
|
||||||
local function wrap_root(fn: () -> ())
|
local function wrap_root(fn: () -> ())
|
||||||
return function()
|
return function()
|
||||||
local _, destroy = vide.root(fn :: any)
|
local destroy = vide.mount(fn :: any)
|
||||||
destroy()
|
destroy()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -289,6 +289,20 @@ TEST("mount()", function()
|
||||||
CHECK(count == 1)
|
CHECK(count == 1)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
TEST("root()", function()
|
||||||
|
local root = vide.root
|
||||||
|
local cleanup = vide.cleanup
|
||||||
|
|
||||||
|
local count = 0
|
||||||
|
|
||||||
|
root(function(destroy)
|
||||||
|
cleanup(function() count += 1 end)
|
||||||
|
destroy()
|
||||||
|
end)
|
||||||
|
|
||||||
|
CHECK(count == 1)
|
||||||
|
end)
|
||||||
|
|
||||||
TEST("source()", wrap_root(function()
|
TEST("source()", wrap_root(function()
|
||||||
local source = vide.source
|
local source = vide.source
|
||||||
local effect = vide.effect
|
local effect = vide.effect
|
||||||
|
|
@ -357,7 +371,6 @@ TEST("source()", wrap_root(function()
|
||||||
end))
|
end))
|
||||||
|
|
||||||
TEST("derive()", wrap_root(function()
|
TEST("derive()", wrap_root(function()
|
||||||
local root = vide.root
|
|
||||||
local source = vide.source
|
local source = vide.source
|
||||||
local derive = vide.derive
|
local derive = vide.derive
|
||||||
local effect = vide.effect
|
local effect = vide.effect
|
||||||
|
|
@ -450,7 +463,7 @@ TEST("derive()", wrap_root(function()
|
||||||
local count = 0
|
local count = 0
|
||||||
local a = source(0)
|
local a = source(0)
|
||||||
|
|
||||||
local _, destroy = root(function()
|
local destroy = vide.mount(function()
|
||||||
|
|
||||||
local _b = derive(function()
|
local _b = derive(function()
|
||||||
cleanup(function()
|
cleanup(function()
|
||||||
|
|
@ -542,7 +555,6 @@ TEST("effect()", wrap_root(function()
|
||||||
end))
|
end))
|
||||||
|
|
||||||
TEST("cleanup()", wrap_root(function()
|
TEST("cleanup()", wrap_root(function()
|
||||||
local root = vide.root
|
|
||||||
local source = vide.source
|
local source = vide.source
|
||||||
local effect = vide.effect
|
local effect = vide.effect
|
||||||
local cleanup = vide.cleanup
|
local cleanup = vide.cleanup
|
||||||
|
|
@ -550,12 +562,10 @@ TEST("cleanup()", wrap_root(function()
|
||||||
do CASE "root cleanup"
|
do CASE "root cleanup"
|
||||||
local count = 0
|
local count = 0
|
||||||
|
|
||||||
local _, destroy = root(function()
|
local destroy = vide.mount(function()
|
||||||
cleanup(function()
|
cleanup(function()
|
||||||
count += 1
|
count += 1
|
||||||
end)
|
end)
|
||||||
|
|
||||||
return nil
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
CHECK(count == 0)
|
CHECK(count == 0)
|
||||||
|
|
@ -606,7 +616,6 @@ TEST("cleanup()", wrap_root(function()
|
||||||
end))
|
end))
|
||||||
|
|
||||||
TEST("create()", wrap_root(function()
|
TEST("create()", wrap_root(function()
|
||||||
local root = vide.root
|
|
||||||
local create = vide.create
|
local create = vide.create
|
||||||
local source = vide.source
|
local source = vide.source
|
||||||
local cleanup = vide.cleanup
|
local cleanup = vide.cleanup
|
||||||
|
|
@ -716,7 +725,7 @@ TEST("create()", wrap_root(function()
|
||||||
do CASE "binding destroy"
|
do CASE "binding destroy"
|
||||||
local count = 0
|
local count = 0
|
||||||
|
|
||||||
local _, destroy = root(function()
|
local destroy = vide.mount(function()
|
||||||
local src = source(0)
|
local src = source(0)
|
||||||
|
|
||||||
return create "TextLabel" {
|
return create "TextLabel" {
|
||||||
|
|
@ -782,7 +791,7 @@ TEST("create()", wrap_root(function()
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE "parent bound to source"
|
do CASE "parent bound to source"
|
||||||
local wref, destroy = root(function()
|
local wref, destroy = vide.root(function(destroy)
|
||||||
local frame = create "Frame" { Name = "Parent" }
|
local frame = create "Frame" { Name = "Parent" }
|
||||||
local parent = source(frame :: Frame?)
|
local parent = source(frame :: Frame?)
|
||||||
|
|
||||||
|
|
@ -795,7 +804,7 @@ TEST("create()", wrap_root(function()
|
||||||
|
|
||||||
parent(nil)
|
parent(nil)
|
||||||
|
|
||||||
return wref
|
return wref, destroy
|
||||||
end)
|
end)
|
||||||
|
|
||||||
gc()
|
gc()
|
||||||
|
|
@ -1373,7 +1382,7 @@ TEST("untrack()", wrap_root(function()
|
||||||
|
|
||||||
local input = source(0)
|
local input = source(0)
|
||||||
|
|
||||||
local output, destroy = root(function()
|
local output, destroy = root(function(destroy)
|
||||||
local output = derive(function()
|
local output = derive(function()
|
||||||
outer_count += 1
|
outer_count += 1
|
||||||
|
|
||||||
|
|
@ -1390,7 +1399,7 @@ TEST("untrack()", wrap_root(function()
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
return output
|
return output, destroy
|
||||||
end)
|
end)
|
||||||
|
|
||||||
CHECK(outer_count == 1)
|
CHECK(outer_count == 1)
|
||||||
|
|
@ -1503,13 +1512,13 @@ TEST("changed()", wrap_root(function()
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE "connection disconnected"
|
do CASE "connection disconnected"
|
||||||
local text, destroy = root(function()
|
local text, destroy = root(function(destroy)
|
||||||
local output = source(nil)
|
local output = source(nil)
|
||||||
|
|
||||||
return create "TextLabel" {
|
return create "TextLabel" {
|
||||||
Text = "a",
|
Text = "a",
|
||||||
changed("Text", output)
|
changed("Text", output)
|
||||||
}
|
}, destroy
|
||||||
end)
|
end)
|
||||||
|
|
||||||
destroy() -- changed() should of disconnect connection
|
destroy() -- changed() should of disconnect connection
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue