starlit  registry.lua at [cade6683f7]

File mods/vtlib/registry.lua artifact 0cb9a501da part of check-in cade6683f7


local register = {}
local registry = {
	defercheck = function() return true end
	-- used to warn about deferments that have not been discharged by a certain threshold
}
registry.mk = function(name,db)
	local reg = {}
	if not db then -- auxiliary db, stored in registry itself
		reg.db = {}
		db = reg.db
	end
	local dat = {
		iters = {};
		state = {};
		defer = {};
	}
	reg.invoke = function(fnid,tgtid)
		local fno = dat.iters[fnid]
		if not fno then return false end

		local runid = fnid .. '@' ..tgtid
		if dat.state[runid] then return true end

		if fno.deps then for k,f in pairs(fno.deps) do
			if reg.invoke(f,tgtid) == false then return false end
		end end
		
		fno.fn(tgtid, db[tgtid])

		dat.state[runid] = true
		return true
	end
	reg.foreach = function(ident,deps,fn)
		dat.iters[ident] = {deps = deps, fn = fn}
		for k in pairs(db) do
			if reg.invoke(ident,k) == false then
				-- not all dependencies are available
				-- to run yet; must defer until then
				dat.defer[#dat.defer+1] = ident
				return false
			end
		end
		for i,dfn in pairs(dat.defer) do
			local deferred = dat.iters[dfn]
			for _,d in pairs(deferred.deps) do
				if not dat.iters[d] then goto skipdfmt end
			end
			-- a deferred function can now be run, do so
			table.remove(dat.defer,i)
			reg.foreach(dfn,deferred.deps,deferred.fn)
		::skipdfmt::end

		return true
	end
	reg.link = function(key,value)
		-- support simple arrays as well as kv stores
		if value == nil then
			value = key
			key = #db+1
		end
		db[key] = value
		for id in pairs(dat.iters) do 
			reg.invoke(id,key)
		end
		return value
	end
	reg.meld = function(tbl)
		for k,v in pairs(tbl) do reg.link(k,v) end
	end
	register[name] = reg

	local nextfn = registry.defercheck
	registry.defercheck = function()
		if #dat.defer ~= 0 then
			print('WARNING: ' .. tostring(#dat.defer) .. ' deferred iterator(s) have not yet been discharged for registry “' .. name .. '”')
			local log = print
			for i,v in pairs(dat.defer) do
				log('\t' .. tostring(i) .. ') ' .. v)
			end
			log('there is likely a missing dependency or dependency ordering problem. also make sure you have spelled the names of the iterator dependencies correctly')
			return false
		end
		nextfn()
	end
	return reg
end

return registry

--[[
if sorcery.DEBUG then
	local function dump(tbl,indent)
		indent = indent or 0
		local space = string.rep(' ',indent*4)
		for k,v in pairs(tbl) do
			if type(v) == 'table' then
				print(string.format('%s%s = {',space,k))
				dump(v,indent + 1)
				print(string.format('%s}', space))
			else
				print(string.format('%s%s = %q',space,k,tostring(v)))
			end
		end
	end 

	local metals = {
		oregonium = {desc = 'Oregonium'};
		nevadite = {desc = 'Nevadite'};
	}
	local myreg = sorcery.registry.mk('metals',metals)

	sorcery.register.metals.link('californium', {
		desc = "Californium";
	})

	sorcery.register.metals.foreach('sorcery:mkingot',{'sorcery:mkfrag'}, function(k,v)
		local ingot = 'sorcery:' .. k .. '_ingot'
		print('registered',ingot)
		v.parts = v.parts or {}
		v.parts.ingot = ingot;
	end)

	sorcery.registry.defercheck()

	sorcery.register.metals.link('washingtonium', {
		desc = "Washingtonium";
	})

	sorcery.register.metals.foreach('sorcery:mkfrag',{}, function(k,v)
		local fragment = 'sorcery:' .. k .. '_fragment'
		print('registered',fragment)
		v.parts = v.parts or {}
		v.parts.fragment = fragment;
	end)

	sorcery.register.metals.link('biloxite', {
		desc = "Biloxite";
	})
	
	dump(metals)
	if sorcery.registry.defercheck() then
		print('lingering deferments!')
	else
		print('all good!')
	end
end
]]