K wobsahej skočić

Modul:table/indexIpairs

z Wikisłownika

local table_get_unprotected_metatable = "Module:table/getUnprotectedMetatable"

local error = error
local ipairs = ipairs
local ipairs_iter = ipairs{}
local pcall = pcall
local rawget = rawget
local type = type

local function get_unprotected_metatable(...)
	get_unprotected_metatable = require(table_get_unprotected_metatable)
	return get_unprotected_metatable(...)
end

local current = {}

-- Iterator used when there is no __ipairs metamethod to deal with.
local function default_iter(t, i)
	i = i + 1
	local v = t[i]
	if v ~= nil then
		return i, v
	end
end

local function index_ipairs(t)
	if current[t] then
		return ipairs_iter, t, 0
	end

	local mt = get_unprotected_metatable(t)
	if mt == nil then
		return ipairs_iter, t, 0
	elseif not mt then
		current[t] = true
		-- Use pcall(), so that `t` can always be unset from `current`.
		local success, iter, state, init = pcall(ipairs, t)
		current[t] = nil
		-- If there was an error, raise it.
		if not success then
			error(iter)
		end
		return iter, state, init
	end

	-- Iterate up through __index metamethods.
	local parent
	repeat
		-- If an __ipairs metamethod is found, use the custom iterator.
		local ipairs_mm = rawget(mt, "__ipairs")
		if not (ipairs_mm == nil or ipairs_mm == index_ipairs) then
			break
		end
		-- If __index isn't a table, use default_iter().
		parent = rawget(mt, "__index")
		if not (parent and type(parent) == "table") then
			return default_iter, t, 0
		end
		-- If there's no metatable, use default_iter().
		mt = get_unprotected_metatable(parent)
		if mt == nil then
			return default_iter, t, 0
		end
	-- get_unprotected_metatable() will return false if the metatable is
	-- protected, which means there could be an __ipairs metamethod, so use the
	-- custom iterator.
	until not mt

	local iter, state

	return function(t, i)
		local new_i = i + 1
		local v = t[new_i]
		if v ~= nil then
			return new_i, v
		-- Use iter() as a fallback.
		elseif iter == nil then
			iter, state = ipairs(parent)
		end
		return iter(state, i)
	end, t, 0
end

return index_ipairs