This commit is contained in:
Aaron Smith 2023-08-02 16:12:05 +01:00
parent f7ce5f024d
commit 7cdcebf03c
11 changed files with 367 additions and 233 deletions

View file

@ -2,7 +2,10 @@
-- vide/apply.lua
------------------------------------------------------------------------------------------
if not game then script = (require :: any) "test/wrap-require" end
if not game then
script = (require :: any) "test/wrap-require"
typeof = require "test/mock".typeof
end
local graph = require(script.Parent.graph)
type Node<T> = graph.Node<T>

46
src/cleanup.lua Normal file
View file

@ -0,0 +1,46 @@
------------------------------------------------------------------------------------------
-- vide/cleanup.lua
------------------------------------------------------------------------------------------
if not game then script = require "test/wrap-require" end
-- todo: verify correct behavior in non-standard usage
local cleanup_callbacks = {} :: { [string]: () -> () }
local cleanup_callers = {} :: { [string]: () -> () }
setmetatable(cleanup_callers :: any, { __mode = "vs" })
-- todo: rare case where mem address is reused by another function on same line
local function cleanup(callback: () -> ())
local caller = debug.info(2, "f") :: () -> ()
local line = debug.info(2, "l") :: number
local ref = tostring(caller) .. "\0" .. line
local fn = cleanup_callbacks[ref]
if fn then
fn()
else
cleanup_callers[ref] = caller
end
cleanup_callbacks[ref] = callback
end
local buffer = {}
local function clean_garbage()
for ref, callback in next, cleanup_callbacks do
if cleanup_callers[ref] == nil then -- caller was garbage collected
callback()
table.insert(buffer, ref)
end
end
for _, ref in next, buffer do
cleanup_callbacks[ref] = nil
end
table.clear(buffer)
end
return function() return cleanup, clean_garbage end

View file

@ -9,18 +9,8 @@ local create = graph.create
local get = graph.get
local capture_and_link = graph.capture_and_link
local function derive<T>(fn: () -> T, cleanup: (T) -> ()?): () -> T
local function derive<T>(fn: () -> T): () -> T
local node = create((nil :: any) :: T)
if cleanup then
local f = fn
local last: T? = nil
fn = function()
if last ~= nil then cleanup(last) end
last = f()
return last :: T
end
end
node.cache = capture_and_link(node, fn)

View file

@ -8,6 +8,7 @@ if not game then script = (require :: any) "test/wrap-require" end
local create = require(script.create)
local source = require(script.source)
local watch = require(script.watch)
local cleanup, clean_garbage = require(script.cleanup)()
local derive = require(script.derive)
local map = require(script.map)
@ -25,9 +26,10 @@ local vide = {
-- core
create = create,
source = source,
watch = watch,
cleanup = cleanup,
derive = derive,
map = map,
watch = watch,
-- animations
spring = spring,
@ -45,6 +47,7 @@ local vide = {
-- test
step = function(dt: number)
update_springs(dt)
clean_garbage()
end
}

View file

@ -93,14 +93,14 @@ local lerpable: { [string]: Lerp<any> } = {
local springs: { [SpringData<any>]: Node<any> } = {}
setmetatable(springs, { __mode = "vs" })
local function spring<T>(target: () -> T, period: number, damping_ratio: number?): () -> T
local function spring<T>(target: () -> T, period: number?, damping_ratio: number?): () -> T
local initial_position = target()
local node = create(initial_position)
local data: SpringData<T> = {
alpha = 0,
duration = 0,
period = period,
period = period or 1,
damping_ratio = damping_ratio or 1,
velocity = 0,
initial_velocity = 0,

View file

@ -9,25 +9,18 @@ local set_effect = graph.set_effect
local capture = graph.capture
local function watch(effect: () -> ()): () -> ()
-- todo: call cleanup on initial debug call when strict
local nodes, cleanup = capture(effect :: () -> (() -> ()?), nil)
local nodes = capture(effect :: () -> nil)
nodes = table.clone(nodes)
local function fn()
if cleanup then cleanup(); cleanup = nil end
cleanup = effect()
end
for _, node in next, nodes do
set_effect(node, fn, true)
set_effect(node, effect, true)
end
local function unwatch()
for _, node in next, nodes do
set_effect(node, fn, nil)
set_effect(node, effect, nil)
end
if cleanup then cleanup(); cleanup = nil end
end
return unwatch