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")
|
error("None of the derived atoms were collected")
|
||||||
end)
|
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
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,16 @@
|
||||||
local reference = require(script.Parent.Parent.utils.reference)
|
local reference = require(script.Parent.Parent.utils.reference)
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
|
local previous = _G.__DEV__
|
||||||
|
|
||||||
|
beforeAll(function()
|
||||||
|
_G.__DEV__ = true
|
||||||
|
end)
|
||||||
|
|
||||||
|
afterAll(function()
|
||||||
|
_G.__DEV__ = previous
|
||||||
|
end)
|
||||||
|
|
||||||
afterEach(function()
|
afterEach(function()
|
||||||
reference.clear()
|
reference.clear()
|
||||||
end)
|
end)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ return function()
|
||||||
local previous = _G.__DEV__
|
local previous = _G.__DEV__
|
||||||
|
|
||||||
beforeAll(function()
|
beforeAll(function()
|
||||||
_G.__DEV__ = true
|
_G.__DEV__ = false -- prevent React errors
|
||||||
end)
|
end)
|
||||||
|
|
||||||
afterAll(function()
|
afterAll(function()
|
||||||
|
|
@ -1,15 +1,10 @@
|
||||||
local reference = require(script.Parent.utils.reference)
|
local reference = require(script.Parent.utils.reference)
|
||||||
|
|
||||||
type AtomInternal<T> = {
|
type AtomInternal<T> = {
|
||||||
--- @deprecated
|
|
||||||
setForced: (self: AtomInternal<T>, state: T | ((T) -> T)) -> (),
|
setForced: (self: AtomInternal<T>, state: T | ((T) -> T)) -> (),
|
||||||
--- @deprecated
|
|
||||||
listeners: { [(T) -> ()]: true },
|
listeners: { [(T) -> ()]: true },
|
||||||
--- @deprecated
|
|
||||||
debugTraceback: string,
|
debugTraceback: string,
|
||||||
--- @deprecated
|
|
||||||
debugLabel: string,
|
debugLabel: string,
|
||||||
--- @deprecated
|
|
||||||
owners: { [any]: true },
|
owners: { [any]: true },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,10 +58,10 @@ local function atom<State>(state: State): Atom<State>
|
||||||
if setter then
|
if setter then
|
||||||
local result = setter(nextState, state)
|
local result = setter(nextState, state)
|
||||||
|
|
||||||
if result == nil then
|
if result ~= nil then
|
||||||
return
|
|
||||||
else
|
|
||||||
nextState = result
|
nextState = result
|
||||||
|
else
|
||||||
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -103,7 +98,9 @@ local function atom<State>(state: State): Atom<State>
|
||||||
|
|
||||||
function atom:readonly(): ReadonlyAtom<State>
|
function atom:readonly(): ReadonlyAtom<State>
|
||||||
function setter(_, _)
|
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
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -15,16 +15,29 @@ type Derive =
|
||||||
local function derive<Result>(...): ReadonlyAtom<Result>
|
local function derive<Result>(...): ReadonlyAtom<Result>
|
||||||
local atoms: { Atom<unknown> } = { ... }
|
local atoms: { Atom<unknown> } = { ... }
|
||||||
local combiner: (...unknown) -> Result = table.remove(atoms) :: any
|
local combiner: (...unknown) -> Result = table.remove(atoms) :: any
|
||||||
local size = #atoms
|
local size = 0
|
||||||
local dependencies: { unknown } = {}
|
local dependencies: { unknown } = {}
|
||||||
|
local listeners: { [() -> ()]: boolean } = {}
|
||||||
|
|
||||||
for index, atom in atoms do
|
for index, atom in atoms do
|
||||||
dependencies[index] = atom:get()
|
dependencies[index] = atom:get()
|
||||||
|
size += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local derivedAtom = atom(combiner(table.unpack(dependencies, 1, size))):readonly()
|
local derivedAtom = atom(combiner(table.unpack(dependencies, 1, size))):readonly()
|
||||||
|
local derivedAtomUnmount = derivedAtom.unmount
|
||||||
local getDerivedAtom = reference.weak(derivedAtom)
|
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
|
for index, atom in atoms do
|
||||||
local function listener(state: unknown)
|
local function listener(state: unknown)
|
||||||
-- Remove the listener if the derived atom has been garbage collected,
|
-- 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.
|
-- its derived atoms will be in use as well.
|
||||||
derivedAtom.owners[atom] = true
|
derivedAtom.owners[atom] = true
|
||||||
atom.listeners[listener] = true
|
atom.listeners[listener] = true
|
||||||
|
listeners[listener] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
return derivedAtom
|
return derivedAtom
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue