-- ROBLOX deviation: our implementation of any has significant deviations, check README for more info
-- > any("number"):asymmetricMatch(1) -- true
-- > any("number"):toAsymmetricMatcher() -- "Any<number>"
-- > any(ClassA):asymmetricMatch(ClassA.new()) -- true
-- > any(ClassA):asymmetricMatch(ClassB.new()) -- false
-- > any(ClassA):asymmetricMatch(DerivedClassA.new()) -- true

local Any = {}
Any.__index = Any
setmetatable(Any, AsymmetricMatcher)
function Any.new(sample: any)
	if typeof(sample) ~= "table" and typeof(sample) ~= "string" then
		error(
			"any() expects to be passed a typename string or a prototype class. "
				.. "Please pass one or use anything() to match any object."
		)
	end
	local self = AsymmetricMatcher.new(sample)
	setmetatable(self, Any)
	return self
end

function Any:asymmetricMatch(other: any): boolean
	-- ROBLOX deviation: simplified since this covers all the cases in Lua
	local selfType = getType(self.sample)
	local otherType = getType(other)
	-- compare metatable to check instance of Lua prototypical class
	if (selfType == "table" and otherType == "table") or (selfType == "error" and otherType == "error") then
		return instanceof(other, self.sample)
		-- check type matches type provided by string
	elseif selfType == "string" and self.sample == otherType then
		return true
	end
	return false
end

function Any:toString(): string
	return "Any"
end

function Any:getExpectedType(): string
	-- ROBLOX deviation: simplified since this already covers all the cases in Lua
	return tostring(self.sample)
end

function Any:toAsymmetricMatcher(): string
	return "Any<" .. tostring(self.sample) .. ">"
end

local Anything = {}
Anything.__index = Anything
setmetatable(Anything, AsymmetricMatcher)
function Anything.new(sample: any)
	local self = AsymmetricMatcher.new(sample)
	setmetatable(self, Anything)
	return self
end

function Anything:asymmetricMatch(other: any): boolean
	-- ROBLOX deviation: other !== null is redundant since Lua doesn't distinguish undefined/nil
	return not isUndefined(other)
end

function Anything:toString(): string
	return "Anything"
end
