|
/* |
|
Copyright (c) 2024 BB-301 <fw3dg3@gmail.com> |
|
[GitHub Gist](https://gist.github.com/BB-301/2f8855a8cc2fe07e38ef4eaa690c6fa4) |
|
|
|
Permission is hereby granted, free of charge, to any person |
|
obtaining a copy of this software and associated documentation |
|
files (the “Software”), to deal in the Software without restriction, |
|
including without limitation the rights to use, copy, modify, merge, |
|
publish, distribute, sublicense, and/or sell copies of the Software, |
|
and to permit persons to whom the Software is furnished to do so, |
|
subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included |
|
in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. |
|
*/ |
|
|
|
#include <format> |
|
#include <iostream> |
|
#include <string> |
|
#include <variant> |
|
|
|
namespace result_utils |
|
{ |
|
template <typename T> |
|
concept streamable = requires(std::ostream &os, const T &value) { |
|
{ |
|
os << value |
|
} -> std::same_as<std::ostream &>; |
|
}; |
|
|
|
template <typename T, typename E> |
|
requires streamable<T> && streamable<E> |
|
using result = std::variant<T, E>; |
|
|
|
template <typename T, typename E> |
|
bool is_success(const result<T, E> &res) |
|
{ |
|
return std::holds_alternative<T>(res); |
|
} |
|
|
|
template <typename T, typename E> |
|
bool is_error(const result<T, E> &res) |
|
{ |
|
return std::holds_alternative<E>(res); |
|
} |
|
|
|
template <typename T, typename E> |
|
const T &get_success(const result<T, E> &res) |
|
{ |
|
if (!is_success(res)) |
|
{ |
|
throw std::runtime_error("Result does not contain a success value."); |
|
} |
|
return std::get<T>(res); |
|
} |
|
|
|
template <typename T, typename E> |
|
const E &get_error(const result<T, E> &res) |
|
{ |
|
if (!is_error(res)) |
|
{ |
|
throw std::runtime_error("Result does not contain an error value."); |
|
} |
|
return std::get<E>(res); |
|
} |
|
|
|
template <typename T, typename E, typename SuccessFn, typename ErrorFn> |
|
auto match(const result<T, E> &res, SuccessFn success_fn, ErrorFn error_fn) |
|
{ |
|
if (is_success(res)) |
|
{ |
|
return success_fn(get_success(res)); |
|
} |
|
else |
|
{ |
|
return error_fn(get_error(res)); |
|
} |
|
} |
|
|
|
template <typename T, typename E> |
|
std::ostream &operator<<(std::ostream &os, const result<T, E> &res) |
|
{ |
|
if (is_success(res)) |
|
{ |
|
os << "Success: " << get_success(res); |
|
} |
|
else |
|
{ |
|
os << "Error: " << get_error(res); |
|
} |
|
return os; |
|
} |
|
} |
|
|
|
struct MySuccess |
|
{ |
|
std::string message; |
|
|
|
friend std::ostream &operator<<(std::ostream &os, const MySuccess &self) |
|
{ |
|
return os << std::format("Success {{ .message = {} }}", self.message); |
|
} |
|
}; |
|
|
|
enum class MyError |
|
{ |
|
unknown, |
|
invalid_argument |
|
}; |
|
|
|
std::ostream &operator<<(std::ostream &os, const MyError &self) |
|
{ |
|
switch (self) |
|
{ |
|
case MyError::invalid_argument: |
|
return os << "Error { Invalid argument }"; |
|
case MyError::unknown: |
|
return os << "Error { Unknown }"; |
|
} |
|
return os; |
|
} |
|
|
|
int main() |
|
{ |
|
using namespace result_utils; |
|
|
|
result<MySuccess, MyError> res1 = MySuccess{"Operation completed successfully"}; |
|
result<MySuccess, MyError> res2 = MyError::invalid_argument; |
|
|
|
std::cout << res1 << '\n'; |
|
std::cout << res2 << '\n'; |
|
|
|
match( |
|
res1, |
|
[](const MySuccess &s) |
|
{ std::cout << "Matched success: " << s << '\n'; }, |
|
[](const MyError &e) |
|
{ std::cout << "Matched error: " << e << '\n'; }); |
|
|
|
match( |
|
res2, |
|
[](const MySuccess &s) |
|
{ std::cout << "Matched success: " << s << '\n'; }, |
|
[](const MyError &e) |
|
{ std::cout << "Matched error: " << e << '\n'; }); |
|
|
|
return 0; |
|
} |