mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
Refactor
This commit is contained in:
parent
2050c2585f
commit
cc10c80a90
10 changed files with 174 additions and 220 deletions
|
|
@ -43,7 +43,7 @@ function setup(instance: Instance, setter: (Instance) -> ())
|
|||
local trace = traceback()
|
||||
setter = function(instance)
|
||||
local ok, err: string? = pcall(fn, instance)
|
||||
if not ok then warn(`error occured updating state binding:\n{err}\nset from:{trace}`) end
|
||||
if not ok then warn(`error occured updating property:\n{err}\nset from:{trace}`) end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -68,8 +68,6 @@ function setup(instance: Instance, setter: (Instance) -> ())
|
|||
instance:GetPropertyChangedSignal("Parent"):Connect(ref)
|
||||
end
|
||||
|
||||
-- todo: move `fn` as arg?
|
||||
|
||||
local function bind_property(instance: Instance, property: string, fn: () -> unknown)
|
||||
setup(instance, function(instance_weak: any)
|
||||
instance_weak[property] = fn()
|
||||
|
|
@ -80,13 +78,13 @@ local function bind_parent(instance: Instance, fn: () -> Instance?)
|
|||
instance.Destroying:Connect(function()
|
||||
instance= nil :: any -- allow gc when destroyed
|
||||
end)
|
||||
|
||||
setup(instance, function(instance)
|
||||
local _ = instance -- state will strongly reference instance when parent is bound
|
||||
instance.Parent = fn()
|
||||
end)
|
||||
end
|
||||
|
||||
-- todo: could optimize, see: maps.luau values()
|
||||
local function bind_children(parent: Instance, fn: () -> { Instance })
|
||||
local current_child_set: { [Instance]: true } = {} -- cache of all children parented before update
|
||||
local new_child_set: { [Instance]: true } = {} -- cache of all children parented after update
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ local defaults = require(script.Parent.defaults)
|
|||
local apply = require(script.Parent.apply)
|
||||
local memoize = require(script.Parent.memoize)
|
||||
|
||||
local function createInstance(className: string)
|
||||
local function create_instance(className: string)
|
||||
local success, instance: Instance = pcall(Instance.new, className :: any)
|
||||
if success == false then throw(`invalid class name, could not create instance of class { className }`) end
|
||||
|
||||
|
|
@ -26,9 +26,9 @@ local function createInstance(className: string)
|
|||
return function(properties: { [any]: unknown }): Instance
|
||||
return apply(instance:Clone(), properties)
|
||||
end
|
||||
end; createInstance = memoize(createInstance)
|
||||
end; create_instance = memoize(create_instance)
|
||||
|
||||
local function cloneInstance(instance: Instance)
|
||||
local function clone_instance(instance: Instance)
|
||||
return function(properties: { [any]: unknown }): Instance
|
||||
local clone = instance:Clone()
|
||||
if not clone then error("Attempt to clone a non-archivable instance", 3) end
|
||||
|
|
@ -38,9 +38,9 @@ end
|
|||
|
||||
local function create(classNameOrInstance: string|Instance)
|
||||
if type(classNameOrInstance) == "string" then
|
||||
return createInstance(classNameOrInstance)
|
||||
return create_instance(classNameOrInstance)
|
||||
elseif typeof(classNameOrInstance) == "Instance" then
|
||||
return cloneInstance(classNameOrInstance)
|
||||
return clone_instance(classNameOrInstance)
|
||||
else
|
||||
error("Bad argument #1, expected string or instance, got "..typeof(classNameOrInstance), 2)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
if not game then script = require "test/wrap-require" end
|
||||
|
||||
local throw = require(script.Parent.throw)
|
||||
local flags = require(script.Parent.flags)
|
||||
|
||||
export type Node<T> = {
|
||||
|
|
@ -13,28 +14,30 @@ local reff = false
|
|||
local refs = {} :: { Node<unknown> }
|
||||
|
||||
local WEAK_VALUES_RESIZABLE = { __mode = "vs" }
|
||||
local EVALUATION_ERR = "error while evaluating node:\n\n"
|
||||
local EVALUATION_ERR = "error while evaluating source:\n\n"
|
||||
|
||||
setmetatable(refs :: any, WEAK_VALUES_RESIZABLE)
|
||||
|
||||
local check_for_yield do
|
||||
local check_for_yield: <T...>(fn: (T...) -> unknown, T...) -> () do
|
||||
local t = { __mode = "kv" }
|
||||
setmetatable(t, t)
|
||||
|
||||
check_for_yield = function<T..., U...>(fn: (T...) -> (), ...: any)
|
||||
check_for_yield = function(fn, ...: any)
|
||||
local args = { ... }
|
||||
t.__unm = function()
|
||||
|
||||
t.__unm = function(_)
|
||||
fn(unpack(args))
|
||||
end
|
||||
|
||||
local ok, err = pcall(function()
|
||||
return -t :: any
|
||||
local _ = -t
|
||||
end)
|
||||
|
||||
if not ok then
|
||||
if err == "attempt to yield across metamethod/C-call boundary" or err == "thread is not yieldable" then
|
||||
error(EVALUATION_ERR .. "cannot yield when deriving node in watcher", 3)
|
||||
throw(EVALUATION_ERR .. "cannot yield when deriving node in watcher")
|
||||
else
|
||||
error(EVALUATION_ERR..err, 3)
|
||||
throw(EVALUATION_ERR .. err)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -45,10 +48,16 @@ local function set_effect<T>(node: Node<unknown>, fn: (T) -> (), key: T)
|
|||
end
|
||||
|
||||
local function run_effects(node: Node<unknown>)
|
||||
for effect, key in next, node.effects do
|
||||
if flags.strict then effect(key) end
|
||||
effect(key)
|
||||
end
|
||||
if flags.strict then
|
||||
for effect, key in next, node.effects do
|
||||
effect(key)
|
||||
effect(key)
|
||||
end
|
||||
else
|
||||
for effect, key in next, node.effects do
|
||||
effect(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- retrieves a node's cached value
|
||||
|
|
@ -71,8 +80,10 @@ end
|
|||
local function update(node: Node<unknown>)
|
||||
run_effects(node)
|
||||
if node.children then
|
||||
local strict = flags.strict
|
||||
|
||||
for _, child in node.children do
|
||||
if flags.strict then check_for_yield(child.derive) end
|
||||
if strict then check_for_yield(child.derive) end
|
||||
child.cache = child.derive()
|
||||
update(child)
|
||||
end
|
||||
|
|
@ -108,7 +119,7 @@ local function capture<T, U>(fn: (U?) -> T, arg: U?): ({ Node<unknown> }, T)
|
|||
|
||||
reff = false
|
||||
|
||||
if not ok then error("error while detecting watcher: " .. result :: string, 0) end
|
||||
if not ok then throw(EVALUATION_ERR .. result :: string) end
|
||||
|
||||
return refs, result :: T
|
||||
end
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ local indexes, values = require(script.maps)()
|
|||
local spring, update_springs = require(script.spring)()
|
||||
local action = require(script.action)()
|
||||
|
||||
local throw = require(script.throw)
|
||||
local flags = require(script.flags)
|
||||
|
||||
local vide = {
|
||||
|
|
@ -49,15 +50,20 @@ local vide = {
|
|||
}
|
||||
|
||||
setmetatable(vide :: any, {
|
||||
__index = function(_, index: unknown)
|
||||
error(string.format("\"%s\" is not a valid member of vide", tostring(index)), 2)
|
||||
__index = function(_, index: unknown): ()
|
||||
if index == "strict" then
|
||||
return flags.strict
|
||||
else
|
||||
throw(`{tostring(index)} is not a valid member of vide`)
|
||||
end
|
||||
end,
|
||||
|
||||
__newindex = function(_, index: unknown, value: unknown)
|
||||
if index == "strict" then
|
||||
flags.strict = if type(value) == "boolean" then value else error("strict must be a boolean", 2)
|
||||
if value ~= true then throw "strict mode can only be set to true" end
|
||||
flags.strict = true
|
||||
else
|
||||
error(string.format("\"%s\" is not a valid member of vide", tostring(index)), 2)
|
||||
throw(`{tostring(index)} is not a valid member of vide`)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
if not game then script = require "test/wrap-require" end
|
||||
|
||||
local throw = require(script.Parent.throw)
|
||||
local flags = require(script.Parent.flags)
|
||||
local graph = require(script.Parent.graph)
|
||||
type Node<T> = graph.Node<T>
|
||||
local create = graph.create
|
||||
|
|
@ -9,6 +11,15 @@ local link = graph.link
|
|||
|
||||
type Map<K, V> = { [K]: V }
|
||||
|
||||
local function check_primitives(t: {})
|
||||
if not flags.strict then return end
|
||||
|
||||
for _, v in next, t do
|
||||
if type(v) == "table" or type(v) == "userdata" then continue end
|
||||
throw("table source map cannot return primitives")
|
||||
end
|
||||
end
|
||||
|
||||
-- todo: optimize output array
|
||||
local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI, K) -> VO): () -> { VO }
|
||||
local input_cache = {} :: Map<K, VI>
|
||||
|
|
@ -54,7 +65,8 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
|
|||
for _, v in next, output_cache do
|
||||
table.insert(output_array, v)
|
||||
end
|
||||
|
||||
check_primitives(output_array)
|
||||
|
||||
return output_array
|
||||
end
|
||||
|
||||
|
|
@ -86,6 +98,16 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
|
|||
|
||||
local function recompute(data: Map<K, VI>)
|
||||
local cur_input_cache, new_input_cache = cur_input_cache_up, new_input_cache_up
|
||||
|
||||
if flags.strict then
|
||||
local cache = {}
|
||||
for _, v in next, data do
|
||||
if cache[v] ~= nil then
|
||||
throw "duplicate table value detected"
|
||||
end
|
||||
cache[v] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- process data
|
||||
for i, v in next, data do
|
||||
|
|
@ -136,6 +158,7 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
|
|||
for _, node in next, nodes do
|
||||
link(node, output, derive)
|
||||
end
|
||||
check_primitives(output_array)
|
||||
|
||||
output.cache = recompute(value)
|
||||
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ local function update_springs(dt: number)
|
|||
typeof(initial_position),
|
||||
target_type
|
||||
))
|
||||
throw(`Cannot tween type { typeof(initial_position) } and { target_type }`)
|
||||
throw(`cannot tween type { typeof(initial_position) } and { target_type }`)
|
||||
continue
|
||||
end
|
||||
|
||||
|
|
@ -165,14 +165,13 @@ local function update_springs(dt: number)
|
|||
|
||||
if lerp == nil then
|
||||
springs[data] = nil
|
||||
throw(`Cannot animate type { target_type }`)
|
||||
throw(`cannot animate type { target_type }`)
|
||||
continue
|
||||
end
|
||||
|
||||
local new_time = data.duration + dt
|
||||
local new_alpha = solve(data.period, data.damping_ratio, data.initial_velocity, new_time)
|
||||
local new_velocity = -(new_alpha - data.alpha)/dt
|
||||
|
||||
local acceleration = (new_velocity - data.velocity)/dt
|
||||
|
||||
data.velocity = new_velocity
|
||||
|
|
@ -181,7 +180,8 @@ local function update_springs(dt: number)
|
|||
|
||||
local value = lerp(initial_position, target_position, new_alpha)
|
||||
|
||||
if math.abs(acceleration) < 0.01 then
|
||||
if math.abs(acceleration) < (0.01 / data.period) then
|
||||
-- close enough to target, remove and set value to target
|
||||
table.insert(remove_queue, data)
|
||||
set(output, target_position)
|
||||
else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue