mirror of
https://github.com/centau/vide.git
synced 2026-08-20 23:01:37 +00:00
This commit is contained in:
parent
f7ce5f024d
commit
7cdcebf03c
11 changed files with 367 additions and 233 deletions
|
|
@ -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
46
src/cleanup.lua
Normal 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
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue