local C={}C.__index=C function C.new(K,y)assert(type(K)=="\098\111\111\108\101\097\110")return setmetatable({[C]=true,__success=K;__value=y},C)end function C.ok(K)return C.new(true,K)end function C.error(K)return C.new(false,K)end function C.isResult(K)return type(K)=="\116\097\098\108\101"and K[C]end function C.unpack(K)assert(C.isResult(K),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \082\101\115\117\108\116")return K.__success,K.__value end function C.unwrapOrDie(y,K)assert(C.isResult(y),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \082\101\115\117\108\116")assert(K==nil or type(K)=="\115\116\114\105\110\103","\'\109\101\115\115\097\103\101\' \109\117\115\116 \098\101 \110\105\108 \111\114 \097 \115\116\114\105\110\103")if not y.__success then if K~=nil then error(("\082\101\115\117\108\116\058\117\110\119\114\097\112\079\114\068\105\101\040\041 \102\097\105\108\101\100 \119\105\116\104 \037\115\058 \037\115"):format(tostring(y.__value),K),2)else error(("\082\101\115\117\108\116\058\117\110\119\114\097\112\079\114\068\105\101\040\041 \102\097\105\108\101\100 \119\105\116\104 \037\115"):format(tostring(y.__value)),2)end end return y.__value end function C.unwrapErrorOrDie(y,K)assert(C.isResult(y),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \082\101\115\117\108\116")assert(K==nil or type(K)=="\115\116\114\105\110\103","\'\109\101\115\115\097\103\101\' \109\117\115\116 \098\101 \110\105\108 \111\114 \097 \115\116\114\105\110\103")if y.__success then if K~=nil then error(("\082\101\115\117\108\116\058\117\110\119\114\097\112\069\114\114\111\114\079\114\068\105\101\040\041 \102\097\105\108\101\100 \119\105\116\104 \037\115\058 \037\115"):format(tostring(y.__value),K),2)else error(("\082\101\115\117\108\116\058\117\110\119\114\097\112\069\114\114\111\114\079\114\068\105\101\040\041 \102\097\105\108\101\100 \119\105\116\104 \037\115"):format(tostring(y.__value)),2)end end return y.__value end function C.isOk(C)return C.__success end function C.isError(C)return not C.__success end function C.map(y,K)assert(C.isResult(y),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \082\101\115\117\108\116")if y.__success then return C.ok(K(y.__value))else return y end end function C.mapError(y,K)assert(C.isResult(y),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \082\101\115\117\108\116")if y.__success then return y else return C.error(K(y.__value))end end function C.andThen(y,K)assert(C.isResult(y),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \082\101\115\117\108\116")if y.__success then local E=K(y.__value)assert(C.isResult(E))return E else return y end end function C.orElse(y,K)assert(C.isResult(y),"\'\115\101\108\102\' \109\117\115\116 \098\101 \097 \082\101\115\117\108\116")if y.__success then return y else local E=K(y.__value)assert(C.isResult(E))return E end end function C.__tostring(C)if C.__success then return("\082\101\115\117\108\116\040\115\117\099\099\101\115\115\058 \037\115\041"):format(tostring(C.__value))else return("\082\101\115\117\108\116\040\102\097\105\108\117\114\101\058 \037\115\041"):format(tostring(C.__value))end end return C
local Result = {}

Result.__index = Result

function Result.new(success, value)
	assert(type(success) == "boolean")

	return setmetatable({
		[Result] = true,
		__success = success,
		__value = value,
	}, Result)
end

function Result.ok(value)
	return Result.new(true, value)
end

function Result.error(value)
	return Result.new(false, value)
end

function Result.isResult(value)
	return type(value) == "table" and value[Result]
end

function Result:unpack()
	assert(Result.isResult(self), "'self' must be a Result")

	return self.__success, self.__value
end

function Result:unwrapOrDie(message)
	assert(Result.isResult(self), "'self' must be a Result")
	assert(message == nil or type(message) == "string", "'message' must be nil or a string")

	if not self.__success then
		if message ~= nil then
			error(("Result:unwrapOrDie() failed with %s: %s"):format(tostring(self.__value), message), 2)
		else
			error(("Result:unwrapOrDie() failed with %s"):format(tostring(self.__value)), 2)
		end
	end

	return self.__value
end

function Result:unwrapErrorOrDie(message)
	assert(Result.isResult(self), "'self' must be a Result")
	assert(message == nil or type(message) == "string", "'message' must be nil or a string")

	if self.__success then
		if message ~= nil then
			error(("Result:unwrapErrorOrDie() failed with %s: %s"):format(tostring(self.__value), message), 2)
		else
			error(("Result:unwrapErrorOrDie() failed with %s"):format(tostring(self.__value)), 2)
		end
	end

	return self.__value
end

function Result:isOk()
	return self.__success
end

function Result:isError()
	return not self.__success
end

-- Result<T, E>
-- param functor: T -> U
-- returns Result<U, E>
function Result:map(functor)
	assert(Result.isResult(self), "'self' must be a Result")

	if self.__success then
		return Result.ok(functor(self.__value))
	else
		return self
	end
end

-- Result<T, E>
-- param functor: E -> F
-- returns Result<T, F>
function Result:mapError(functor)
	assert(Result.isResult(self), "'self' must be a Result")

	if self.__success then
		return self
	else
		return Result.error(functor(self.__value))
	end
end

-- Result<T, E>
-- param functor: T -> Result<U, E>
-- returns Result<U, E>
function Result:andThen(functor)
	assert(Result.isResult(self), "'self' must be a Result")

	if self.__success then
		local result = functor(self.__value)
		assert(Result.isResult(result))

		return result
	else
		return self
	end
end

-- Result<T, E>
-- param functor: E -> Result<T, F>
-- returns Result<T, F>
function Result:orElse(functor)
	assert(Result.isResult(self), "'self' must be a Result")

	if self.__success then
		return self
	else
		local result = functor(self.__value)
		assert(Result.isResult(result))

		return result
	end
end

function Result:__tostring()
	if self.__success then
		return ("Result(success: %s)"):format(tostring(self.__value))
	else
		return ("Result(failure: %s)"):format(tostring(self.__value))
	end
end

return Result