From 31b1956b5a024807e51c01f77596e5aabbc1ac15 Mon Sep 17 00:00:00 2001 From: aaron <83140718+centau@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:51:39 +0100 Subject: [PATCH] --- docs/api/reactivity-core.md | 6 +++--- src/graph.luau | 2 ++ src/mount.luau | 12 +++++------- src/root.luau | 30 +++++++++++++++------------- test/benchmark.luau | 6 +++--- test/tests.luau | 39 +++++++++++++++++++++++-------------- 6 files changed, 54 insertions(+), 41 deletions(-) diff --git a/docs/api/reactivity-core.md b/docs/api/reactivity-core.md index 0e056f9..0e4a5d0 100644 --- a/docs/api/reactivity-core.md +++ b/docs/api/reactivity-core.md @@ -9,7 +9,7 @@ Creates and runs a function in a new reactive scope. - **Type** ```lua - function root(fn: () -> T): (T, () -> ()) + function root(fn: (destroy: () -> ()) -> T...): T... ``` - **Details** @@ -19,8 +19,8 @@ Creates and runs a function in a new reactive scope. Returns the result of the given function. - Also returns a function to destroy the root, which will run any cleanups - and allow derived sources created to garbage collect. + A function to destroy the root is passed into the callback, which will run + any cleanups and allow derived sources created to garbage collect. ::: warning `fn()` cannot yield. diff --git a/src/graph.luau b/src/graph.luau index 33ed011..20140bd 100644 --- a/src/graph.luau +++ b/src/graph.luau @@ -106,6 +106,8 @@ local function destroy(node: Node) run_cleanups(node) unparent(node) + node.effect = false + if node.parents.owner then remove_child(node.parents.owner, node) node.parents.owner = nil diff --git a/src/mount.luau b/src/mount.luau index 4de1985..315925e 100644 --- a/src/mount.luau +++ b/src/mount.luau @@ -3,14 +3,12 @@ if not game then script = require "test/relative-string" end local root = require(script.Parent.root) local apply = require(script.Parent.apply) -local function mount(app: () -> T, target: Instance?): () -> () - local _, destroy = root(function() - local result = app() +local function mount(component: () -> T, target: Instance?): () -> () + return root(function(destroy) + local result = component() if target then apply(target, { result }) end - return nil + return destroy end) - - return destroy end -return mount +return mount :: ((component: () -> T, target: Instance) -> () -> ()) & ((component: () -> ()) -> () -> ()) diff --git a/src/root.luau b/src/root.luau index 766f1fb..a2900cd 100644 --- a/src/root.luau +++ b/src/root.luau @@ -10,25 +10,29 @@ local destroy = graph.destroy local refs = {} -local function root(fn: () -> T): (T, () -> ()) +local function root(fn: (destroy: () -> ()) -> T...): T... 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 - return result, function() + local destroy = function() + if not refs[node] then throw "root already destroyed" end refs[node] = nil destroy(node) 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 + + return unpack(result :: any, 2) end -return root :: ((fn: () -> T) -> (T, () -> ())) & ((fn: () -> ()) -> (nil, () -> ())) +return root :: ((fn: (destroy: () -> ()) -> T...) -> T...) & ((fn: (destroy: () -> ()) -> ()) -> ()) diff --git a/test/benchmark.luau b/test/benchmark.luau index f858f5f..6702235 100644 --- a/test/benchmark.luau +++ b/test/benchmark.luau @@ -17,10 +17,10 @@ end local N = 2^18 -- 262144 local function WRAP_BENCH(name: string, fn: () -> ()) - local _, destroy = vide.root(function() + vide.root(function(destroy) BENCH(name, fn) - end) - destroy() + return destroy + end)() end TITLE "sources" diff --git a/test/tests.luau b/test/tests.luau index 030f846..4d8a52c 100644 --- a/test/tests.luau +++ b/test/tests.luau @@ -24,7 +24,7 @@ end local function wrap_root(fn: () -> ()) return function() - local _, destroy = vide.root(fn :: any) + local destroy = vide.mount(fn :: any) destroy() end end @@ -289,6 +289,20 @@ TEST("mount()", function() CHECK(count == 1) 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() local source = vide.source local effect = vide.effect @@ -357,7 +371,6 @@ TEST("source()", wrap_root(function() end)) TEST("derive()", wrap_root(function() - local root = vide.root local source = vide.source local derive = vide.derive local effect = vide.effect @@ -450,7 +463,7 @@ TEST("derive()", wrap_root(function() local count = 0 local a = source(0) - local _, destroy = root(function() + local destroy = vide.mount(function() local _b = derive(function() cleanup(function() @@ -542,7 +555,6 @@ TEST("effect()", wrap_root(function() end)) TEST("cleanup()", wrap_root(function() - local root = vide.root local source = vide.source local effect = vide.effect local cleanup = vide.cleanup @@ -550,12 +562,10 @@ TEST("cleanup()", wrap_root(function() do CASE "root cleanup" local count = 0 - local _, destroy = root(function() + local destroy = vide.mount(function() cleanup(function() count += 1 end) - - return nil end) CHECK(count == 0) @@ -606,7 +616,6 @@ TEST("cleanup()", wrap_root(function() end)) TEST("create()", wrap_root(function() - local root = vide.root local create = vide.create local source = vide.source local cleanup = vide.cleanup @@ -716,7 +725,7 @@ TEST("create()", wrap_root(function() do CASE "binding destroy" local count = 0 - local _, destroy = root(function() + local destroy = vide.mount(function() local src = source(0) return create "TextLabel" { @@ -782,7 +791,7 @@ TEST("create()", wrap_root(function() end 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 parent = source(frame :: Frame?) @@ -795,7 +804,7 @@ TEST("create()", wrap_root(function() parent(nil) - return wref + return wref, destroy end) gc() @@ -1373,7 +1382,7 @@ TEST("untrack()", wrap_root(function() local input = source(0) - local output, destroy = root(function() + local output, destroy = root(function(destroy) local output = derive(function() outer_count += 1 @@ -1390,7 +1399,7 @@ TEST("untrack()", wrap_root(function() end) end) - return output + return output, destroy end) CHECK(outer_count == 1) @@ -1503,13 +1512,13 @@ TEST("changed()", wrap_root(function() end do CASE "connection disconnected" - local text, destroy = root(function() + local text, destroy = root(function(destroy) local output = source(nil) return create "TextLabel" { Text = "a", changed("Text", output) - } + }, destroy end) destroy() -- changed() should of disconnect connection