t.Axes=primitive("\065\120\101\115")t.BrickColor=primitive("\066\114\105\099\107\067\111\108\111\114")t.CFrame=primitive("\067\070\114\097\109\101")t.Color3=primitive("\067\111\108\111\114\051")t.ColorSequence=primitive("\067\111\108\111\114\083\101\113\117\101\110\099\101")t.ColorSequenceKeypoint=primitive("\067\111\108\111\114\083\101\113\117\101\110\099\101\075\101\121\112\111\105\110\116")t.DockWidgetPluginGuiInfo=primitive("\068\111\099\107\087\105\100\103\101\116\080\108\117\103\105\110\071\117\105\073\110\102\111")t.Faces=primitive("\070\097\099\101\115")t.Instance=primitive("\073\110\115\116\097\110\099\101")t.NumberRange=primitive("\078\117\109\098\101\114\082\097\110\103\101")t.NumberSequence=primitive("\078\117\109\098\101\114\083\101\113\117\101\110\099\101")t.NumberSequenceKeypoint=primitive("\078\117\109\098\101\114\083\101\113\117\101\110\099\101\075\101\121\112\111\105\110\116")t.PathWaypoint=primitive("\080\097\116\104\087\097\121\112\111\105\110\116")t.PhysicalProperties=primitive("\080\104\121\115\105\099\097\108\080\114\111\112\101\114\116\105\101\115")t.Random=primitive("\082\097\110\100\111\109")t.Ray=primitive("\082\097\121")t.Rect=primitive("\082\101\099\116")t.Region3=primitive("\082\101\103\105\111\110\051")t.Region3int16=primitive("\082\101\103\105\111\110\051\105\110\116\049\054")t.TweenInfo=primitive("\084\119\101\101\110\073\110\102\111")t.UDim=primitive("\085\068\105\109")t.UDim2=primitive("\085\068\105\109\050")t.Vector2=primitive("\086\101\099\116\111\114\050")t.Vector3=primitive("\086\101\099\116\111\114\051")t.Vector3int16=primitive("\086\101\099\116\111\114\051\105\110\116\049\054")t.Enum=primitive("\069\110\117\109")t.EnumItem=primitive("\069\110\117\109\073\116\101\109")function t.literal(Y)return function(E)if E~=Y then return false end return true end end t.exactly=t.literal function t.integer(Y)local E=t.number(Y)if not E then return false end if Y%1==0 then return true else return false end end function t.numberMin(Y)return function(E)local k=t.number(E)if not k then return false end if E>=Y then return true else return false end end end function t.numberMax(Y)return function(E)local k=t.number(E)if not k then return false end if E<=Y then return true else return false end end end function t.numberMinExclusive(Y)return function(E)local k=t.number(E)if not k then return false end if Y<E then return true else return false end end end function t.numberMaxExclusive(Y)return function(E)local k=t.number(E)if not k then return false end if E<Y then return true else return false end end end t.numberPositive=t.numberMinExclusive(0)t.numberNegative=t.numberMaxExclusive(0)function t.numberConstrained(Y,E)assert(t.number(Y)and t.number(E))local k=t.numberMin(Y)local L=t.numberMax(E)return function(Y)local E=k(Y)if not E then return false end local n=L(Y)if not n then return false end return true end end function t.numberConstrainedExclusive(Y,E)assert(t.number(Y)and t.number(E))local k=t.numberMinExclusive(Y)local L=t.numberMaxExclusive(E)return function(Y)local E=k(Y)if not E then return false end local n=L(Y)if not n then return false end return true end end function t.optional(Y)assert(t.callback(Y))return function(E)if E==nil then return true end local k=Y(E)if k then return true else return false end end end function t.tuple(...)local Y={...}return function(...)local E={...}for k=1,#Y,1 do local L=Y[k](E[k])if L==false then return false end end return true end end function t.keys(Y)assert(t.callback(Y))return function(E)local k=t.table(E)if k==false then return false end for E in pairs(E)do local k=Y(E)if k==false then return false end end return true end end function t.values(Y)assert(t.callback(Y))return function(E)local k=t.table(E)if k==false then return false end for E,k in pairs(E)do local L=Y(k)if L==false then return false end end return true end end function t.map(Y,E)assert(t.callback(Y),t.callback(E))local k=t.keys(Y)local L=t.values(E)return function(Y)local E=k(Y)if not E then return false end local n=L(Y)if not n then return false end return true end end do local Y=t.keys(t.integer)function t.array(E)assert(t.callback(E))local k=t.values(E)return function(E)local L=Y(E)if L==false then return false end local n=0 for Y,E in ipairs(E)do n=n+1 end for Y in pairs(E)do if Y<1 or Y>n then return false end end local s=k(E)if not s then return false end return true end end end do local Y=t.array(t.callback)function t.union(...)local E={...}assert(Y(E))return function(Y)for E,k in pairs(E)do if k(Y)then return true end end return false end end function t.intersection(...)local E={...}assert(Y(E))return function(Y)for E,k in pairs(E)do local L=k(Y)if not L then return false end end return true end end end do local Y=t.map(t.any,t.callback)function t.interface(E)assert(Y(E))return function(Y)local k=t.table(Y)if k==false then return false end for E,k in pairs(E)do local L=k(Y[E])if L==false then return false end end return true end end function t.strictInterface(E)assert(Y(E))return function(Y)local k=t.table(Y)if k==false then return false end for E,k in pairs(E)do local L=k(Y[E])if L==false then return false end end for Y in pairs(Y)do if not E[Y]then return false end end return true end end end function t.instance(Y)assert(t.string(Y))return function(E)local k=t.Instance(E)if not k then return false end if E.ClassName~=Y then return false end return true end end function t.instanceIsA(Y)assert(t.string(Y))return function(E)local k=t.Instance(E)if not k then return false end if not E:IsA(Y)then return false end return true end end function t.enum(Y)assert(t.Enum(Y))return function(E)local k=t.EnumItem(E)if not k then return false end if E.EnumType==Y then return true else return false end end end do local Y=t.tuple(t.callback,t.callback)function t.wrap(E,k)assert(Y(E,k))return function(...)assert(k(...))return E(...)end end end function t.strict(Y)return function(...)assert(Y(...))end end return t


t.Axes = primitive("Axes")
t.BrickColor = primitive("BrickColor")
t.CFrame = primitive("CFrame")
t.Color3 = primitive("Color3")
t.ColorSequence = primitive("ColorSequence")
t.ColorSequenceKeypoint = primitive("ColorSequenceKeypoint")
t.DockWidgetPluginGuiInfo = primitive("DockWidgetPluginGuiInfo")
t.Faces = primitive("Faces")
t.Instance = primitive("Instance")
t.NumberRange = primitive("NumberRange")
t.NumberSequence = primitive("NumberSequence")
t.NumberSequenceKeypoint = primitive("NumberSequenceKeypoint")
t.PathWaypoint = primitive("PathWaypoint")
t.PhysicalProperties = primitive("PhysicalProperties")
t.Random = primitive("Random")
t.Ray = primitive("Ray")
t.Rect = primitive("Rect")
t.Region3 = primitive("Region3")
t.Region3int16 = primitive("Region3int16")
t.TweenInfo = primitive("TweenInfo")
t.UDim = primitive("UDim")
t.UDim2 = primitive("UDim2")
t.Vector2 = primitive("Vector2")
t.Vector3 = primitive("Vector3")
t.Vector3int16 = primitive("Vector3int16")
t.Enum = primitive("Enum")
t.EnumItem = primitive("EnumItem")

function t.literal(literal)
	return function(value)
		if value ~= literal then
			return false
		end
		return true
	end
end

t.exactly = t.literal

function t.integer(value)
	local success = t.number(value)
	if not success then
		return false
	end
	if value%1 == 0 then
		return true
	else
		return false
	end
end

function t.numberMin(min)
	return function(value)
		local success = t.number(value)
		if not success then
			return false
		end
		if value >= min then
			return true
		else
			return false
		end
	end
end

function t.numberMax(max)
	return function(value)
		local success = t.number(value)
		if not success then
			return false
		end
		if value <= max then
			return true
		else
			return false
		end
	end
end

function t.numberMinExclusive(min)
	return function(value)
		local success = t.number(value)
		if not success then
			return false
		end
		if min < value then
			return true
		else
			return false
		end
	end
end

function t.numberMaxExclusive(max)
	return function(value)
		local success = t.number(value)
		if not success then
			return false
		end
		if value < max then
			return true
		else
			return false
		end
	end
end

t.numberPositive = t.numberMinExclusive(0)
t.numberNegative = t.numberMaxExclusive(0)

function t.numberConstrained(min, max)
	assert(t.number(min) and t.number(max))
	local minCheck = t.numberMin(min)
	local maxCheck = t.numberMax(max)
	return function(value)
		local minSuccess = minCheck(value)
		if not minSuccess then
			return false
		end

		local maxSuccess = maxCheck(value)
		if not maxSuccess then
			return false
		end

		return true
	end
end

function t.numberConstrainedExclusive(min, max)
	assert(t.number(min) and t.number(max))
	local minCheck = t.numberMinExclusive(min)
	local maxCheck = t.numberMaxExclusive(max)
	return function(value)
		local minSuccess = minCheck(value)
		if not minSuccess then
			return false
		end

		local maxSuccess = maxCheck(value)
		if not maxSuccess then
			return false
		end

		return true
	end
end

function t.optional(check)
	assert(t.callback(check))
	return function(value)
		if value == nil then
			return true
		end
		local success = check(value)
		if success then
			return true
		else
			return false
		end
	end
end

function t.tuple(...)
	local checks = {...}
	return function(...)
		local args = {...}
		for i = 1, #checks do
			local success = checks[i](args[i])
			if success == false then
				return false
			end
		end
		return true
	end
end

function t.keys(check)
	assert(t.callback(check))
	return function(value)
		local tableSuccess = t.table(value)
		if tableSuccess == false then
			return false
		end

		for key in pairs(value) do
			local success = check(key)
			if success == false then
				return false
			end
		end

		return true
	end
end

function t.values(check)
	assert(t.callback(check))
	return function(value)
		local tableSuccess = t.table(value)
		if tableSuccess == false then
			return false
		end

		for _, val in pairs(value) do
			local success = check(val)
			if success == false then
				return false
			end
		end

		return true
	end
end

function t.map(keyCheck, valueCheck)
	assert(t.callback(keyCheck), t.callback(valueCheck))
	local keyChecker = t.keys(keyCheck)
	local valueChecker = t.values(valueCheck)
	return function(value)
		local keySuccess = keyChecker(value)
		if not keySuccess then
			return false
		end

		local valueSuccess = valueChecker(value)
		if not valueSuccess then
			return false
		end

		return true
	end
end

do
	local arrayKeysCheck = t.keys(t.integer)

	function t.array(check)
		assert(t.callback(check))
		local valuesCheck = t.values(check)
		return function(value)
			local keySuccess = arrayKeysCheck(value)
			if keySuccess == false then
				return false
			end

			-- # is unreliable for sparse arrays
			-- Count upwards using ipairs to avoid false positives from the behavior of #
			local arraySize = 0

			for _, _ in ipairs(value) do
				arraySize = arraySize + 1
			end

			for key in pairs(value) do
				if key < 1 or key > arraySize then
					return false
				end
			end

			local valueSuccess = valuesCheck(value)
			if not valueSuccess then
				return false
			end

			return true
		end
	end
end

do
	local callbackArray = t.array(t.callback)

	function t.union(...)
		local checks = {...}
		assert(callbackArray(checks))
		return function(value)
			for _, check in pairs(checks) do
				if check(value) then
					return true
				end
			end
			return false
		end
	end

	function t.intersection(...)
		local checks = {...}
		assert(callbackArray(checks))
		return function(value)
			for _, check in pairs(checks) do
				local success = check(value)
				if not success then
					return false
				end
			end
			return true
		end
	end
end

do
	local checkInterface = t.map(t.any, t.callback)

	function t.interface(checkTable)
		assert(checkInterface(checkTable))
		return function(value)
			local tableSuccess = t.table(value)
			if tableSuccess == false then
				return false
			end

			for key, check in pairs(checkTable) do
				local success = check(value[key])
				if success == false then
					return false
				end
			end
			return true
		end
	end

	function t.strictInterface(checkTable)
		assert(checkInterface(checkTable))
		return function(value)
			local tableSuccess = t.table(value)
			if tableSuccess == false then
				return false
			end

			for key, check in pairs(checkTable) do
				local success = check(value[key])
				if success == false then
					return false
				end
			end

			for key in pairs(value) do
				if not checkTable[key] then
					return false
				end
			end

			return true
		end
	end
end

function t.instance(className)
	assert(t.string(className))
	return function(value)
		local instanceSuccess = t.Instance(value)
		if not instanceSuccess then
			return false
		end

		if value.ClassName ~= className then
			return false
		end

		return true
	end
end

function t.instanceIsA(className)
	assert(t.string(className))
	return function(value)
		local instanceSuccess = t.Instance(value)
		if not instanceSuccess then
			return false
		end

		if not value:IsA(className) then
			return false
		end

		return true
	end
end

function t.enum(enum)
	assert(t.Enum(enum))
	return function(value)
		local enumItemSuccess = t.EnumItem(value)
		if not enumItemSuccess then
			return false
		end

		if value.EnumType == enum then
			return true
		else
			return false
		end
	end
end

do
	local checkWrap = t.tuple(t.callback, t.callback)

	function t.wrap(callback, checkArgs)
		assert(checkWrap(callback, checkArgs))
		return function(...)
			assert(checkArgs(...))
			return callback(...)
		end
	end
end

function t.strict(check)
	return function(...)
		assert(check(...))
	end
end

return t
