diff --git a/lib/utils/mu-option.hh b/lib/utils/mu-option.hh index ce9b4d74..e6085fbf 100644 --- a/lib/utils/mu-option.hh +++ b/lib/utils/mu-option.hh @@ -23,20 +23,41 @@ #include #include #include +#include +#include namespace Mu { /// Either a value of type T, or None +/// +/// Note: unlike std::optional, tl::optional also supports _references_ +/// (Option), which we use in various places; std:: only gets those with +/// C++26. template using Option = tl::optional; +/** + * Some() wraps a value in an Option, mostly to help the reader. + * + * @param t the value; copied when passed an lvalue, moved when passed an + * rvalue. + * + * @return an Option containing the value + */ template -Option +[[nodiscard]] Option> Some(T&& t) { - return std::move(t); + return std::forward(t); } constexpr auto Nothing = tl::nullopt; // 'None' is already taken. +/** + * Get the value from an Option, or throw + * + * @param res an Option + * + * @return the value (moved out of @p res) + */ template T unwrap(Option&& res) { @@ -54,8 +75,9 @@ unwrap(Option&& res) * * @return option with either the string or nothing if str was NULL. */ -Option -inline to_string_opt(const char* str) { +inline Option +to_string_opt(const char* str) +{ if (str) return std::string{str}; else diff --git a/lib/utils/mu-result.hh b/lib/utils/mu-result.hh index 34b24451..7304ec4e 100644 --- a/lib/utils/mu-result.hh +++ b/lib/utils/mu-result.hh @@ -20,12 +20,19 @@ #ifndef MU_RESULT_HH__ #define MU_RESULT_HH__ +#include +#include + #include #include "utils/mu-error.hh" namespace Mu { /** * A little Rust-envy...a Result is _either_ some value of type T, _or_ a Mu::Error + * + * Note: nothing outside this header uses tl:: directly, and Result only uses + * the std::expected subset of the API; so once mu requires C++23, this can + * simply become std::expected (with tl::unexpected -> std::unexpected below). */ template using Result = tl::expected; @@ -33,14 +40,15 @@ template using Result = tl::expected; * Ok() is not typically strictly needed (unlike Err), but imitates Rust's Ok * and it helps the reader. * - * @param t the value to return + * @param t the value to return; copied when passed an lvalue, moved when + * passed an rvalue. * * @return a success Result */ -template Result +template [[nodiscard]] Result> Ok(T&& t) { - return std::move(t); + return std::forward(t); } /** @@ -48,7 +56,7 @@ Ok(T&& t) * * @return a success Result */ -inline Result +[[nodiscard]] inline Result Ok() { return {}; @@ -61,68 +69,71 @@ Ok() * * @return error */ -template Result -Err(Error&& err) -{ - return tl::unexpected(std::move(err)); -} -template Result -Err(const Error& err) -{ - return tl::unexpected(err); -} - -inline tl::unexpected +[[nodiscard]] inline tl::unexpected Err(Error&& err) { return tl::unexpected(std::move(err)); } -inline tl::unexpected +[[nodiscard]] inline tl::unexpected Err(const Error& err) { return tl::unexpected(err); } +/** + * Get the error from some error Result + * + * @param res a Result; must hold an error (checking that is up to the + * caller) + * + * @return the error + */ template -inline tl::unexpected +[[nodiscard]] inline tl::unexpected Err(const Result& res) { - return res.error(); + return tl::unexpected(res.error()); } template -inline tl::unexpected +[[nodiscard]] inline tl::unexpected Err(Result&& res) { - return std::move(res.error()); + return tl::unexpected(std::move(res.error())); } /* * convenience */ template -tl::unexpected +[[nodiscard]] tl::unexpected Err(Error::Code code, fmt::format_string frm, T&&... args) { return Err(Error{code, frm, std::forward(args)...}); } template -tl::unexpected +[[nodiscard]] tl::unexpected Err(Error::Code code, GError **err, fmt::format_string frm, T&&... args) { return Err(Error{code, err, frm, std::forward(args)...}); } - +/** + * Get the value from a Result, or throw its error + * + * @param res a Result + * + * @return the value (moved out of @p res) + */ template T unwrap(Result&& res) { if (!!res) return std::move(res.value()); else - throw res.error(); + throw std::move(res.error()); } /**