first defer impl

This commit is contained in:
BlackMATov
2024-12-02 03:25:33 +07:00
parent 9e616d8c6a
commit ac8e197980
5 changed files with 398 additions and 1 deletions

View File

@@ -1,5 +1,32 @@
# evolved.lua
## Module `defers`
```
defers.defer -> (defer)
defers.set -> defer -> entity -> entity -> any -> (defer)
defers.apply -> defer -> entity -> {any -> any} -> entity -> (defer)
defers.assign -> defer -> entity -> entity -> any -> (defer)
defers.insert -> defer -> entity -> entity -> any -> (defer)
defers.remove -> defer -> entity -> entity... -> (defer)
defers.detach -> defer -> entity -> (defer)
defers.destroy -> defer -> entity -> (defer)
defers.playback -> defer -> (defer)
```
### Instance `defer`
```
defer:set -> entity -> entity -> any -> (defer)
defer:apply -> entity -> {any -> any} -> entity -> (defer)
defer:assign -> entity -> entity -> any -> (defer)
defer:insert -> entity -> entity -> any -> (defer)
defer:remove -> entity -> entity... -> (defer)
defer:detach -> entity -> (defer)
defer:destroy -> entity -> (defer)
defer:playback -> (defer)
```
## Module `idpools`
```
@@ -71,7 +98,7 @@ entity:apply -> {any -> any} -> entity -> (boolean)
entity:assign -> entity -> any -> (boolean)
entity:insert -> entity -> any -> (boolean)
entity:remove -> entity... -> (boolean)
entity:detach -> (entity)
entity:detach -> (boolean)
entity:destroy -> (boolean)
```

View File

@@ -1,3 +1,4 @@
require 'develop.untests.defer_untests'
require 'develop.untests.idpools_untests'
require 'develop.untests.registry_untests'
require 'develop.untests.singles_untests'

View File

@@ -0,0 +1,108 @@
---@diagnostic disable: invisible
local evo = require 'evolved.evolved'
do
local f = evo.registry.entity()
local e = evo.registry.entity()
local d = evo.defers.defer():set(e, f, 42)
assert(not e:has(f))
assert(d == d:playback())
assert(e:get(f) == 42)
evo.defers.defer():set(e, f, 84):playback()
assert(e:get(f) == 84)
end
do
local mul2 = function(v) return v * 2 end
local f1, f2 = evo.registry.entity(), evo.registry.entity()
local e = evo.registry.entity():set(f1, 21)
local d = evo.defers.defer():apply(e, mul2, f1)
assert(e:get(f1) == 21)
assert(d == d:playback())
assert(e:get(f1) == 42)
evo.defers.defer():apply(e, mul2, f2):playback()
assert(not e:has(f2) and e:get(f1) == 42)
end
do
local mul2 = function(v) return v * 2 end
local mul3 = function(v) return v * 3 end
local f1, f2 = evo.registry.entity(), evo.registry.entity()
local e = evo.registry.entity():set(f1, 21):set(f2, 42)
local d = evo.defers.defer():apply(e, mul2, f1):apply(e, mul3, f2)
assert(e:get(f1) == 21 and e:get(f2) == 42)
assert(d == d:playback())
assert(e:get(f1) == 42 and e:get(f2) == 126)
end
do
local f = evo.registry.entity()
local e = evo.registry.entity():set(f, 21)
local d = evo.defers.defer():assign(e, f, 42)
assert(e:get(f) == 21)
assert(d == d:playback())
assert(e:get(f) == 42)
evo.defers.defer():assign(e, f, 84):playback()
assert(e:get(f) == 84)
end
do
local f = evo.registry.entity()
local e = evo.registry.entity()
local d = evo.defers.defer():insert(e, f, 42)
assert(not e:has(f))
assert(d == d:playback())
assert(e:get(f) == 42)
evo.defers.defer():insert(e, f, 84):playback()
assert(e:get(f) == 42)
end
do
local f = evo.registry.entity()
local e = evo.registry.entity():set(f, 21)
local d = evo.defers.defer():remove(e)
assert(e:get(f) == 21)
assert(d == d:playback())
assert(e:get(f) == 21)
end
do
local f = evo.registry.entity()
local e = evo.registry.entity():set(f, 21)
local d = evo.defers.defer():remove(e, f)
assert(e:get(f) == 21)
assert(d == d:playback())
assert(not e:has(f))
end
do
local f1, f2 = evo.registry.entity(), evo.registry.entity()
local e = evo.registry.entity():set(f1, 21):set(f2, 42)
assert(e:get(f1) == 21 and e:get(f2) == 42)
evo.defers.defer():remove(e, f1, f2):playback()
assert(not e:has(f1) and not e:has(f2))
end
do
local f1, f2 = evo.registry.entity(), evo.registry.entity()
local e = evo.registry.entity():set(f1, 4):set(f2, 2)
local d = evo.defers.defer():detach(e)
assert(e:alive() and e:has_all(f1, f2))
assert(d == d:playback())
assert(e:alive() and not e:has_any(f1, f2))
end
do
local f1, f2 = evo.registry.entity(), evo.registry.entity()
local e = evo.registry.entity():set(f1, 4):set(f2, 2)
local d = evo.defers.defer():destroy(e)
assert(e:alive() and e:has_all(f1, f2))
assert(d == d:playback())
assert(not e:alive() and not e:has_any(f1, f2))
end

260
evolved/defers.lua Normal file
View File

@@ -0,0 +1,260 @@
local compat = require 'evolved.compat'
local registry = require 'evolved.registry'
---@class evolved.defers
local defers = {}
---
---
---
---
---
---@enum evolved.defer_op
local evolved_defer_op = {
set = 1,
apply = 2,
assign = 3,
insert = 4,
remove = 5,
detach = 6,
destroy = 7,
}
---@class evolved.defer
---@field operations any[]
---@field operation_count integer
local evolved_defer_mt = {}
evolved_defer_mt.__index = evolved_defer_mt
---
---
---
---
---
---@type table<evolved.defer_op, fun(ops: any[], idx: integer): integer>
local __operation_processors = {
[evolved_defer_op.set] = function(ops, idx)
local entity = ops[idx + 1]
local fragment = ops[idx + 2]
local component = ops[idx + 3]
registry.set(entity, fragment, component)
return 4
end,
[evolved_defer_op.apply] = function(ops, idx)
local entity = ops[idx + 1]
local apply = ops[idx + 2]
local fragment = ops[idx + 3]
registry.apply(entity, apply, fragment)
return 4
end,
[evolved_defer_op.assign] = function(ops, idx)
local entity = ops[idx + 1]
local fragment = ops[idx + 2]
local component = ops[idx + 3]
registry.assign(entity, fragment, component)
return 4
end,
[evolved_defer_op.insert] = function(ops, ids)
local entity = ops[ids + 1]
local fragment = ops[ids + 2]
local component = ops[ids + 3]
registry.insert(entity, fragment, component)
return 4
end,
[evolved_defer_op.remove] = function(ops, idx)
local entity = ops[idx + 1]
local fragment_count = ops[idx + 2]
registry.remove(entity, compat.unpack(ops, idx + 3, idx + 3 + fragment_count))
return 3 + fragment_count
end,
[evolved_defer_op.detach] = function(ops, idx)
local entity = ops[idx + 1]
registry.detach(entity)
return 2
end,
[evolved_defer_op.destroy] = function(ops, idx)
local entity = ops[idx + 1]
registry.destroy(entity)
return 2
end,
}
---
---
---
---
---
---@return evolved.defer
---@nodiscard
function defers.defer()
---@type evolved.defer
local defer = {
operations = {},
operation_count = 0,
}
return setmetatable(defer, evolved_defer_mt)
end
---@param defer evolved.defer
---@param entity evolved.entity
---@param fragment evolved.entity
---@param component any
---@return evolved.defer
function defers.set(defer, entity, fragment, component)
local operations = defer.operations
local operation_count = defer.operation_count
operations[operation_count + 1] = evolved_defer_op.set
operations[operation_count + 2] = entity
operations[operation_count + 3] = fragment
operations[operation_count + 4] = component
defer.operation_count = operation_count + 4
return defer
end
---@param defer evolved.defer
---@param entity evolved.entity
---@param apply fun(any): any
---@param fragment evolved.entity
---@return evolved.defer
function defers.apply(defer, entity, apply, fragment)
local operations = defer.operations
local operation_count = defer.operation_count
operations[operation_count + 1] = evolved_defer_op.apply
operations[operation_count + 2] = entity
operations[operation_count + 3] = apply
operations[operation_count + 4] = fragment
defer.operation_count = operation_count + 4
return defer
end
---@param defer evolved.defer
---@param entity evolved.entity
---@param fragment evolved.entity
---@param component any
---@return evolved.defer
function defers.assign(defer, entity, fragment, component)
local operations = defer.operations
local operation_count = defer.operation_count
operations[operation_count + 1] = evolved_defer_op.assign
operations[operation_count + 2] = entity
operations[operation_count + 3] = fragment
operations[operation_count + 4] = component
defer.operation_count = operation_count + 4
return defer
end
---@param defer evolved.defer
---@param entity evolved.entity
---@param fragment evolved.entity
---@param component any
---@return evolved.defer
function defers.insert(defer, entity, fragment, component)
local operations = defer.operations
local operation_count = defer.operation_count
operations[operation_count + 1] = evolved_defer_op.insert
operations[operation_count + 2] = entity
operations[operation_count + 3] = fragment
operations[operation_count + 4] = component
defer.operation_count = operation_count + 4
return defer
end
---@param defer evolved.defer
---@param entity evolved.entity
---@param ... evolved.entity fragments
---@return evolved.defer
function defers.remove(defer, entity, ...)
local fragment_count = select('#', ...)
if fragment_count == 0 then return defer end
local operations = defer.operations
local operation_count = defer.operation_count
operations[operation_count + 1] = evolved_defer_op.remove
operations[operation_count + 2] = entity
operations[operation_count + 3] = fragment_count
for i = 1, fragment_count do
operations[operation_count + 3 + i] = select(i, ...)
end
defer.operation_count = operation_count + 3 + fragment_count
return defer
end
---@param defer evolved.defer
---@param entity evolved.entity
---@return evolved.defer
function defers.detach(defer, entity)
local operations = defer.operations
local operation_count = defer.operation_count
operations[operation_count + 1] = evolved_defer_op.detach
operations[operation_count + 2] = entity
defer.operation_count = operation_count + 2
return defer
end
---@param defer evolved.defer
---@param entity evolved.entity
---@return evolved.defer
function defers.destroy(defer, entity)
local operations = defer.operations
local operation_count = defer.operation_count
operations[operation_count + 1] = evolved_defer_op.destroy
operations[operation_count + 2] = entity
defer.operation_count = operation_count + 2
return defer
end
---@param defer evolved.defer
---@return evolved.defer
function defers.playback(defer)
local operations = defer.operations
local operation_count = defer.operation_count
local operation_index = 1; while operation_index <= operation_count do
local operation = operations[operation_index]
local processor = __operation_processors[operation]
operation_index = operation_index + processor(operations, operation_index)
end
return defer
end
---
---
---
---
---
evolved_defer_mt.set = defers.set
evolved_defer_mt.apply = defers.apply
evolved_defer_mt.assign = defers.assign
evolved_defer_mt.insert = defers.insert
evolved_defer_mt.remove = defers.remove
evolved_defer_mt.detach = defers.detach
evolved_defer_mt.destroy = defers.destroy
evolved_defer_mt.playback = defers.playback
---
---
---
---
---
return defers

View File

@@ -1,5 +1,6 @@
return {
compat = require 'evolved.compat',
defers = require 'evolved.defers',
idpools = require 'evolved.idpools',
registry = require 'evolved.registry',
singles = require 'evolved.singles',