/* * Copyright 2015 - 2025 gary@drinkingtea.net * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #if __has_include() #include #else namespace std { class exception { public: virtual ~exception() = default; [[nodiscard]] virtual char const*what() const noexcept { return ""; } }; } #endif #include "defines.hpp" #include "def.hpp" #include "source_location.hpp" #include "typetraits.hpp" #include "utility.hpp" namespace ox { using ErrorCode = uint16_t; struct [[nodiscard]] Error { std::source_location src; ox::CString msg = nullptr; ErrorCode errCode = 0; constexpr Error() noexcept = default; explicit constexpr Error( ErrorCode const errCode, std::source_location const&src = std::source_location::current()) noexcept: src{src}, errCode{errCode} {} explicit constexpr Error( ErrorCode const errCode, ox::CString msg, std::source_location const&src = std::source_location::current()) noexcept: src{src}, msg{msg}, errCode{errCode} {} constexpr operator uint64_t() const noexcept { return errCode; } }; [[nodiscard]] constexpr auto errCode(Error const&err) noexcept { return err.errCode; } template [[nodiscard]] constexpr auto toStr(Error const&err) noexcept { return err.msg ? T{err.msg} : ""; } struct Exception: public std::exception { std::source_location src; ox::CString msg = nullptr; ErrorCode errCode = 0; explicit Exception( ErrorCode const errCode, std::source_location const&src = std::source_location::current()) noexcept: src{src}, errCode{errCode} {} explicit Exception( ErrorCode const errCode, ox::CString msg, std::source_location const&src = std::source_location::current()) noexcept: src{src}, msg{msg}, errCode{errCode} {} explicit Exception(Error const&err) noexcept: src{err.src}, msg{err.msg ? err.msg : ""}, errCode{err.errCode} {} constexpr Error toError() const noexcept { return Error(errCode, msg, src); } [[nodiscard]] char const*what() const noexcept override { return msg; } }; [[noreturn]] void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept; template struct [[nodiscard]] Result { using type = typename remove_reference::type; T value; Error error; constexpr Result() noexcept: value(), error(0) { } template constexpr Result(Result const&other) noexcept: value(other.value), error(other.error) { } template constexpr Result(Result &&other) noexcept: value(std::move(other.value)), error(std::move(other.error)) { } constexpr Result(Error const&error) noexcept: value(), error(error) { } constexpr Result(type const&value, Error const&error = {}) noexcept: value(value), error(error) { } constexpr Result(type &&value, Error const&error = {}) noexcept: value(std::move(value)), error(error) { } constexpr ~Result() noexcept = default; explicit constexpr operator type const&() const noexcept { return value; } explicit constexpr operator type&() noexcept { return value; } [[nodiscard]] constexpr bool ok() const noexcept { return error == 0; } template constexpr Error copyTo(U &val) const& noexcept { if (!error) [[likely]] { val = value; } return error; } template constexpr Error copyTo(U &val) && noexcept { if (!error) [[likely]] { val = std::move(value); } return error; } template constexpr Error moveTo(U &val) noexcept { if (!error) [[likely]] { val = std::move(value); } return error; } [[nodiscard]] constexpr T &unwrap() & noexcept { if (error) { oxPanic(error, "Failed unwrap"); } return value; } [[nodiscard]] constexpr T &&unwrap() && noexcept { if (error) { oxPanic(error, "Failed unwrap"); } return std::move(value); } [[nodiscard]] constexpr T const&unwrap() const & noexcept { if (error) [[unlikely]] { oxPanic(error, "Failed unwrap"); } return value; } [[nodiscard]] constexpr T &unwrapThrow() & { if (error) { throw ox::Exception(error); } return value; } [[nodiscard]] constexpr T &&unwrapThrow() && { if (error) { throw ox::Exception(error); } return std::move(value); } [[nodiscard]] constexpr T const&unwrapThrow() const & { if (error) { throw ox::Exception(error); } return value; } template constexpr ox::Result to() & noexcept { if (error) [[unlikely]] { return error; } return U(value); } template constexpr ox::Result to() && noexcept { if (error) [[unlikely]] { return error; } return U(std::move(value)); } template constexpr ox::Result to(auto const&f) & noexcept { if (error) [[unlikely]] { return error; } return f(value); } template constexpr ox::Result to(auto const&f) && noexcept { if (error) [[unlikely]] { return error; } return f(std::move(value)); } /** * Returns parameter alt if Result contains an error. * @param alt * @return value of Result or alt */ constexpr T or_value(T &&alt) const& noexcept { if (error) { return std::move(alt); } return value; } /** * Returns parameter alt if Result contains an error. * @param alt * @return value of Result or alt */ constexpr T or_value(T &&alt) && noexcept { if (error) { return std::move(alt); } return std::move(value); } /** * Returns parameter alt if Result contains an error. * @param alt * @return value of Result or alt */ constexpr T or_value(T const&alt) const& noexcept { if (error) { return alt; } return value; } /** * Returns parameter alt if Result contains an error. * @param alt * @return value of Result or alt */ constexpr T or_value(T const&alt) && noexcept { if (error) { return alt; } return std::move(value); } }; namespace detail { constexpr Error toError(Error const&e) noexcept { return e; } template constexpr Error toError(Result const&r) noexcept { return r.error; } } constexpr void primitiveAssert(char const*file, int line, bool pass, char const*msg) noexcept { if constexpr(ox::defines::Debug) { if (!pass) [[unlikely]] { panic(file, line, msg, ox::Error(1)); } } } constexpr void boundsCheck( char const*file, int const line, size_t const i, size_t const sz, char const*msg) noexcept { if constexpr(defines::CheckBounds) { if (i >= sz) [[unlikely]] { panic(file, line, msg, ox::Error{1}); } } } }