local jecs = require("@jecs")

local function create_cache(hook)
	local columns = setmetatable({}, {
		__index = function(self, component)
			local column = {}
			self[component] = column
			return column
		end,
	})

	return function(world, component, fn)
		local column = columns[component]
		table.insert(column, fn)
		world:set(component, hook, function(entity, value)
			for _, callback in column do
				callback(entity, value)
			end
		end)
	end
end

local hooks = {
	OnSet = create_cache(jecs.OnSet),
	OnAdd = create_cache(jecs.OnAdd),
	OnRemove = create_cache(jecs.OnRemove),
}

local world = jecs.World.new()
local Position = world:component()
local order = ""
hooks.OnSet(world, Position, function(entity, value)
	print("$1", entity, `({value.x}, {value.y}, {value.z})`)
	order ..= "$1"
end)
hooks.OnSet(world, Position, function(entity, value)
	print("$2", entity, `\{{value.x}, {value.y}, {value.z}}`)
	order ..= "-$2"
end)

world:set(world:entity(), Position, { x = 1, y = 0, z = 1 })

-- Output:
--  $1      270     (1, 0, 1)
--  $2      270     {1, 0, 1}

assert(order == "$1" .. "-" .. "$2")
