mirror of
https://github.com/littensy/charm.git
synced 2026-10-20 17:51:37 +00:00
test: add benchmarks, dev mode
This commit is contained in:
parent
3548ca5c58
commit
4586882d3c
6 changed files with 95 additions and 11 deletions
53
src/__tests__/benchmarks/atom.bench.luau
Normal file
53
src/__tests__/benchmarks/atom.bench.luau
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
-- This file is for use by Benchmarker
|
||||
-- https://boatbomber.itch.io/benchmarker
|
||||
|
||||
local Package = game:GetService("ReplicatedStorage").Packages.charm
|
||||
|
||||
local atom = require(Package.atom)
|
||||
local derive = require(Package.derive)
|
||||
|
||||
return {
|
||||
ParameterGenerator = function()
|
||||
return atom({ count = 0 })
|
||||
end,
|
||||
|
||||
Functions = {
|
||||
atom = function(_, source: any)
|
||||
for _ = 1, 500 do
|
||||
source({ count = math.random(1, 2) })
|
||||
end
|
||||
end,
|
||||
|
||||
derived = function(_, source: any)
|
||||
derive(source, function(state)
|
||||
return { count = 2 * state.count }
|
||||
end)
|
||||
for _ = 1, 500 do
|
||||
source({ count = math.random(1, 2) })
|
||||
end
|
||||
end,
|
||||
|
||||
derived_memo = function(_, source: any)
|
||||
source:memo(function(previous, current)
|
||||
return previous.count == current.count
|
||||
end)
|
||||
derive(source, function(state)
|
||||
return { count = 2 * state.count }
|
||||
end)
|
||||
for _ = 1, 500 do
|
||||
source({ count = math.random(1, 2) })
|
||||
end
|
||||
end,
|
||||
|
||||
derived_writable = function(_, source: any)
|
||||
local derived = derive(source, function(state)
|
||||
return { count = 2 * state.count }
|
||||
end):writable(function(update)
|
||||
source({ count = 0.5 * update.count })
|
||||
end)
|
||||
for _ = 1, 500 do
|
||||
derived({ count = 2 * math.random(1, 2) })
|
||||
end
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
|
@ -89,4 +89,14 @@ return function()
|
|||
|
||||
error("None of the derived atoms were collected")
|
||||
end)
|
||||
|
||||
it("unmounts from parent atom", function()
|
||||
local source = atom(1)
|
||||
local derived = derive(source, function(value)
|
||||
return value
|
||||
end)
|
||||
expect((next(source.listeners))).to.be.ok()
|
||||
derived:unmount()
|
||||
expect((next(source.listeners))).to.never.be.ok()
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,16 @@
|
|||
local reference = require(script.Parent.Parent.utils.reference)
|
||||
|
||||
return function()
|
||||
local previous = _G.__DEV__
|
||||
|
||||
beforeAll(function()
|
||||
_G.__DEV__ = true
|
||||
end)
|
||||
|
||||
afterAll(function()
|
||||
_G.__DEV__ = previous
|
||||
end)
|
||||
|
||||
afterEach(function()
|
||||
reference.clear()
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ return function()
|
|||
local previous = _G.__DEV__
|
||||
|
||||
beforeAll(function()
|
||||
_G.__DEV__ = true
|
||||
_G.__DEV__ = false -- prevent React errors
|
||||
end)
|
||||
|
||||
afterAll(function()
|
||||
|
|
@ -1,15 +1,10 @@
|
|||
local reference = require(script.Parent.utils.reference)
|
||||
|
||||
type AtomInternal<T> = {
|
||||
--- @deprecated
|
||||
setForced: (self: AtomInternal<T>, state: T | ((T) -> T)) -> (),
|
||||
--- @deprecated
|
||||
listeners: { [(T) -> ()]: true },
|
||||
--- @deprecated
|
||||
debugTraceback: string,
|
||||
--- @deprecated
|
||||
debugLabel: string,
|
||||
--- @deprecated
|
||||
owners: { [any]: true },
|
||||
}
|
||||
|
||||
|
|
@ -63,10 +58,10 @@ local function atom<State>(state: State): Atom<State>
|
|||
if setter then
|
||||
local result = setter(nextState, state)
|
||||
|
||||
if result == nil then
|
||||
return
|
||||
else
|
||||
if result ~= nil then
|
||||
nextState = result
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -103,7 +98,9 @@ local function atom<State>(state: State): Atom<State>
|
|||
|
||||
function atom:readonly(): ReadonlyAtom<State>
|
||||
function setter(_, _)
|
||||
error(`Attempt to set read-only atom '{label}' created at: {traceback}`, 3)
|
||||
if _G.__DEV__ then
|
||||
error(`Attempt to set read-only atom '{label}' created at: {traceback}`, 3)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,16 +15,29 @@ type Derive =
|
|||
local function derive<Result>(...): ReadonlyAtom<Result>
|
||||
local atoms: { Atom<unknown> } = { ... }
|
||||
local combiner: (...unknown) -> Result = table.remove(atoms) :: any
|
||||
local size = #atoms
|
||||
local size = 0
|
||||
local dependencies: { unknown } = {}
|
||||
local listeners: { [() -> ()]: boolean } = {}
|
||||
|
||||
for index, atom in atoms do
|
||||
dependencies[index] = atom:get()
|
||||
size += 1
|
||||
end
|
||||
|
||||
local derivedAtom = atom(combiner(table.unpack(dependencies, 1, size))):readonly()
|
||||
local derivedAtomUnmount = derivedAtom.unmount
|
||||
local getDerivedAtom = reference.weak(derivedAtom)
|
||||
|
||||
function derivedAtom:unmount()
|
||||
derivedAtomUnmount(self)
|
||||
|
||||
for listener in listeners do
|
||||
for _, atom in atoms do
|
||||
atom.listeners[listener] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for index, atom in atoms do
|
||||
local function listener(state: unknown)
|
||||
-- Remove the listener if the derived atom has been garbage collected,
|
||||
|
|
@ -44,6 +57,7 @@ local function derive<Result>(...): ReadonlyAtom<Result>
|
|||
-- its derived atoms will be in use as well.
|
||||
derivedAtom.owners[atom] = true
|
||||
atom.listeners[listener] = true
|
||||
listeners[listener] = true
|
||||
end
|
||||
|
||||
return derivedAtom
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue