This commit is contained in:
Aaron Smith 2023-09-07 18:11:25 +01:00
parent 470d2b5407
commit 574eb8e4c5
4 changed files with 29 additions and 21 deletions

View file

@ -9,17 +9,20 @@ export type Scope = {
[number]: Scope -- children
}
export type Node<T> = {
scope: Scope,
export type StartNode<T> = {
cache: T,
[number]: Node<T>
}
export type Node<T> = StartNode<T> & {
scope: Scope,
effect: (T) -> (),
[number]: Node<T> -- children
}
-- flag used to detect when node reference capturing is active
local reff = false
-- array of all nodes referenced since above flag was set
local refs = {} :: { Node<unknown> }
local refs = {} :: { StartNode<unknown> }
local scopes = { n = 0 } :: { [number]: Scope, n: number }
@ -102,7 +105,7 @@ local function run_effect<T>(node: Node<T>)
node.effect(node.cache)
end
local function add_child(parent: Node<any>, child: Node<any>)
local function add_child(parent: StartNode<any>, child: Node<any>)
table.insert(parent, child)
end
@ -120,7 +123,7 @@ local function destroy(scope: Scope)
end
-- runs node effects, recalculates descendants and runs descendant effects
local function update<T>(node: Node<T>)
local function update<T>(node: StartNode<T>)
for _, child in ipairs(node) do
local scope = child.scope
assert(scope)
@ -133,7 +136,7 @@ local function update<T>(node: Node<T>)
end
-- detect what nodes were referenced in the given callback and returns them in an array
local function capture<T, U>(fn: (U?) -> T, arg: U?): ({ Node<unknown> }, T)
local function capture<T, U>(fn: (U?) -> T, arg: U?): ({ StartNode<unknown> }, T)
if reff then throw("recursive capture detected") end
table.clear(refs)
@ -164,7 +167,7 @@ local function capture_parents<T, U>(child: Node<T>, fn: (U?) -> T, arg: U?): T
return result
end
local function track<T>(node: Node<T>)
local function track<T>(node: StartNode<T>)
if reff then table.insert(refs, node :: Node<any>) end
end
@ -176,13 +179,15 @@ local function create_scope(): Scope
end
local function create_node<T>(value: T): Node<T>
local node = {
return {
scope = create_scope(),
cache = value,
effect = function() end,
}
end
return node
local function create_start_node<T>(value: T): StartNode<T>
return { cache = value }
end
return table.freeze {
@ -199,6 +204,7 @@ return table.freeze {
capture = capture,
capture_parents = capture_parents,
create_node = create_node,
create_start_node = create_start_node,
create_scope = create_scope,
refs = refs
}

View file

@ -6,8 +6,9 @@ local throw = require(script.Parent.throw)
local flags = require(script.Parent.flags)
local graph = require(script.Parent.graph)
type Scope = graph.Scope
type Node<T> = graph.Node<T>
type StartNode<T> = graph.StartNode<T>
local create_node = graph.create_node
local create_start_node = graph.create_start_node
local create_scope = graph.create_scope
local track = graph.track
local update = graph.update
@ -38,7 +39,7 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
local input_cache = {} :: Map<K, VI>
local output_cache = {} :: Map<K, VO>
local input_nodes = {} :: Map<K, Node<VI>>
local input_nodes = {} :: Map<K, StartNode<VI>>
local remove_queue = {} :: { K }
local output_array = {} :: { VO }
@ -77,7 +78,7 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
open_scope(scope)
local node = create_node(v)
local node = create_start_node(v)
input_nodes[i] = node
input_cache[i] = v
output_cache[i] = transform(function()
@ -131,7 +132,7 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
local new_input_cache_up = {} :: Map<VI, K>
local output_cache = {} :: Map<VI, VO>
local input_nodes = {} :: Map<VI, Node<K>>
local input_nodes = {} :: Map<VI, StartNode<K>>
local output_array = {} :: { VO }
local scopes = {} :: Map<VI, Scope>
@ -163,7 +164,7 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
open_scope(scope)
local node = create_node(i)
local node = create_start_node(i)
input_nodes[v] = node
output_cache[v] = transform(v, function()
track(node)

View file

@ -2,7 +2,7 @@ if not game then script = require "test/relative-string" end
local graph = require(script.Parent.graph)
type Node<T> = graph.Node<T>
local create_node = graph.create_node
local create_start_node = graph.create_start_node
local get_scope = graph.get_scope
local track = graph.track
local update = graph.update
@ -10,9 +10,9 @@ local update = graph.update
export type Source<T> = (() -> T) & ((T) -> T)
local function source<T>(initial_value: T): Source<T>
assert(get_scope())
--assert(get_scope())
local node = create_node(initial_value)
local node = create_start_node(initial_value)
return function(...): T
if select("#", ...) == 0 then -- no args were given

View file

@ -24,7 +24,9 @@ Unsupported datatypes:
local throw = require(script.Parent.throw)
local graph = require(script.Parent.graph)
type Node<T> = graph.Node<T>
type StartNode<T> = graph.StartNode<T>
local create_node = graph.create_node
local create_start_node = graph.create_start_node
local update = graph.update
local capture = graph.capture
local add_child = graph.add_child
@ -142,7 +144,7 @@ setmetatable(vec6_to_type, invalid_type)
-- maps spring data to its corresponding output node
-- lifetime of spring data is tied to output node
local springs: { [SpringData<any>]: Node<any> } = {}
local springs: { [SpringData<any>]: StartNode<any> } = {}
setmetatable(springs, { __mode = "v" })
local function spring<T>(source: () -> T, period: number?, damping_ratio: number?): () -> T
@ -177,8 +179,7 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
source_value = initial_value,
}
local output = create_node(initial_value)
local output = create_start_node(initial_value)
local updater = create_node(false)
updater.effect = function()