21#ifndef MTCORE_RESULT_H
22#define MTCORE_RESULT_H
43 template<
typename Underlying>
52 template<
typename T,
typename ErrType>
61 template<
typename Underlying>
79 bool operator==(const
Error &o) const noexcept {
return code == o.code; }
87 template<
typename ErrType>
91 std::variant<std::monostate, ErrVal>
val;
119 if (std::holds_alternative<Err>(
val) && std::holds_alternative<Err>(other.val)) {
120 return std::get<Err>(
val) == std::get<Err>(other.val);
122 else if (std::holds_alternative<Err>(
val) || std::holds_alternative<Err>(other.val)) {
133 [[nodiscard]]
bool is_error() const noexcept {
return std::holds_alternative<ErrVal>(
val); }
138 [[nodiscard]]
bool is_success() const noexcept {
return std::holds_alternative<std::monostate>(
val); }
145 ensure(
is_error(),
"CANNOT GET AN ERROR FROM A SUCCESSFUL RESUTL!");
146 return std::get<ErrVal>(
val);
169 template<
typename T,
typename ErrType>
176 std::variant<std::monostate, T, ErrVal> val;
193 Result(T &&val) : val(std::forward<T>(val)) {}
216 if (other.is_error()) {
217 return error() == other.error();
221 if (other.is_error()) {
226 if (other.is_success()) {
227 return value() == other.value();
245 return value() == other;
248 bool operator!=(
const T &other)
const noexcept {
return !(*
this == other); }
253 [[nodiscard]]
bool is_success() const noexcept {
return std::holds_alternative<T>(val); }
258 [[nodiscard]] T
value() const noexcept {
260 return std::get<T>(val);
266 [[nodiscard]]
bool is_error() const noexcept {
return std::holds_alternative<ErrVal>(val); }
283 out = std::move(std::get<T>(val));
284 val = std::monostate{};
295 ensure(
is_error(),
"CANNOT GET AN ERROR FROM A SUCCESSFUL RESUTL!");
296 return std::get<ErrVal>(val);
304 return std::get<T>(val);
312 return &std::get<T>(val);
320 return std::get<T>(val);
328 return &std::get<T>(val);
333 return this->
error();
364 template<
typename Err>
377 template<
typename Err>
400 template<
typename Err>
405 template<
typename Underlying>
406 template<
typename Err>
411 template<
typename Underlying>
424 template<
typename Underlying>
451 typename Err =
typename decltype(std::declval<F>()(
452 std::declval<std::remove_const_t<typename decltype(std::declval<I>().iter())::IterElem>>()))::Err>
454 auto iter = iterable.iter();
455 using Elem = std::remove_cv_t<
typename decltype(
iter)::IterElem>;
457 while (
iter.next().move_if_present(cur)) {
458 auto res = func(cur);
459 if (res.is_error()) {
462 initial = acc(initial, res.value());
481 typename Err =
typename decltype(std::declval<F>()(
482 std::declval<std::remove_const_t<typename decltype(std::declval<I>().iter())::IterElem>>()))::Err>
484 auto iter = iterable.iter();
485 using Elem = std::remove_cv_t<
typename decltype(
iter)::IterElem>;
487 while (
iter.next().move_if_present(cur)) {
488 auto res = func(cur);
489 if (res.is_error()) {
497 template<
typename Err,
typename F,
typename... Args>
500 template<
typename V,
typename T>
503 template<
typename Out,
typename Err,
typename F,
typename... Args>
506 template<
typename F,
typename Acc,
typename... Args>
509 template<
typename... Args>
510 struct FirstVariadic;
512 template<
typename A,
typename... Args>
513 struct FirstVariadic<A, Args...> {
518 struct FirstVariadic<> {
536 template<
typename F,
typename... Args,
538 typename decltype(std::declval<F>()(std::declval<
typename impl::FirstVariadic<Args...>::Type>()))::Err>
540 return impl::Chain<Err, F, Args...>::run(func, args...);
561 template<
typename Success,
typename Acc,
typename F,
typename... Args,
563 typename decltype(std::declval<F>()(std::declval<
typename impl::FirstVariadic<Args...>::Type>()))::Err>
565 return impl::Reduce<F, Acc, Args...>::template run<Success, Err>(initVal, func, acc, args...);
580 template<
typename F,
typename... Args,
582 typename decltype(std::declval<F>()(std::declval<
typename impl::FirstVariadic<Args...>::Type>()))::Value,
584 typename decltype(std::declval<F>()(std::declval<
typename impl::FirstVariadic<Args...>::Type>()))::Err>
585 auto map(
const F &func,
const Args &...args) {
586 return impl::Map<Out, Err, F, Args...>::run(func, args...);
590 template<
typename V,
typename... TA>
591 struct TupleAppend<V, std::tuple<TA...>> {
592 using Tuple = std::tuple<TA..., V>;
594 static Tuple append(
const V &v,
const std::tuple<TA...> &tuple) {
595 return append_impl(v, tuple, std::index_sequence_for<TA...>{});
598 template<
size_t... Indx>
599 static Tuple append_impl(
const V &v,
const std::tuple<TA...> &tuple, std::index_sequence<Indx...>) {
600 return {std::get<Indx>(tuple)..., v};
604 template<
typename L,
typename R>
607 template<
typename... LA,
typename... RA>
608 struct TupleConcat<std::tuple<LA...>, std::tuple<RA...>> {
609 using Tuple = std::tuple<LA..., RA...>;
612 template<
typename Out,
typename Err,
typename F>
613 struct Map<Out, Err, F> {
614 using Tuple = std::tuple<>;
616 static Result<std::tuple<>, Err> run(
const F &) {
return success(std::tuple{}); }
618 static Result<T, Err> run_impl(
const T &tuple,
const F &) {
623 template<
typename Out,
typename Err,
typename F,
typename A,
typename... Args>
624 struct Map<Out, Err, F, A, Args...> {
625 using Tuple =
typename TupleAppend<Out,
typename Map<Out, Err, F, Args...>::Tuple>::Tuple;
627 template<
typename... TA>
628 static Result<
typename TupleConcat<std::tuple<TA...>, Tuple>::Tuple, Err>
629 run_impl(
const std::tuple<TA...> &curTuple,
const F &func,
const A &arg,
const Args &...args) {
630 auto curRes = func(arg);
631 if (curRes.is_error()) {
632 return curRes.error();
634 auto newTuple = TupleAppend<Out, std::tuple<TA...>>::append(curRes.value(), curTuple);
635 return Map<Out, Err, F, Args...>::run_impl(newTuple, func, args...);
638 static Result<Tuple, Err> run(
const F &func,
const A &arg,
const Args &...args) {
639 auto curRes = func(arg);
640 if (curRes.is_error()) {
641 return curRes.error();
643 return Map<Out, Err, F, Args...>::run_impl(std::tuple<Out>{curRes.value()}, func, args...);
647 template<
typename Err,
typename F>
648 struct Chain<Err, F> {
649 static Result<void, Err> run(
const F &) {
return success(); }
652 template<
typename Err,
typename F,
typename A,
typename... Args>
653 struct Chain<Err, F, A, Args...> {
654 static Result<void, Err> run(
const F &func,
const A &arg,
const Args &...args) {
655 if (
auto curRes = func(arg); curRes.is_error()) {
656 return curRes.error();
658 return Chain<Err, F, Args...>::run(func, args...).to_void();
662 template<
typename F,
typename Acc>
663 struct Reduce<F, Acc> {
664 template<
typename Success,
typename Err>
665 static Result<Success, Err> run(Success curVal,
const F &,
const Acc &) {
670 template<
typename F,
typename Acc,
typename A,
typename... Args>
671 struct Reduce<F, Acc, A, Args...> {
672 template<
typename Success,
typename Err>
673 static Result<Success, Err> run(Success curVal,
const F &func,
const Acc &accumulator,
const A &arg,
674 const Args &...args) {
675 auto curRes = func(arg);
676 if (curRes.is_error()) {
677 return curRes.error();
679 curVal = accumulator(curVal, curRes.value());
680 return Reduce<F, Acc, Args...>::template run<Success, Err>(curVal, func, accumulator, args...);
The Iterable trait for types Something that implements this trait can give an iterator to iterate ove...
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
Success< T > success(const T &v)
Creates a successful Result.
Result< Success, Err > accumulate(Success initial, const Acc &acc, const F &func, const I &iterable)
Chains together the execution of an errorable function on a list of arguments If an error is encounte...
auto map(const F &func, const Args &...args)
Maps values with function that may error.
Success< void > success()
Creates a successful void Result object.
Result< Success, Err > reduce(Success initVal, const Acc &acc, const F &func, const Args &...args)
Reduces arguments with errorable function If an error is encountered, execution will stop and immedia...
Error< Underlying > error(Underlying err)
Creates an error.
Result< void, Err > chain(const F &func, const Args &...args)
Chains together the execution of an errorable function on a list of arguments If an error is encounte...
constexpr bool is_result_with_value
Checks if a type is result-like with a success value type.
constexpr bool is_result_void
Checks if a type is result-like with no success value.
Generic iterator defaults built on common contracts Does not guarantee performance of iterators Actua...
Additional algorithms and pipeline functionality that can be performed on groups of results.
Core library for C++ with Zig-related functionality.
A struct representing an error Auto convertible to a Result of any type.
bool operator!=(const Error &o) const noexcept
ErrVal error() const noexcept
Returns the associated error Fails if there is no error;.
static Result from_success()
Creates a Result object from a success.
bool operator==(const Result &other) const noexcept
Compares results.
bool operator!=(const Result &other) const noexcept
Result()
Creates a Result object from a success Allows for implicit casting by returning success value.
static Result from_error(ErrVal err)
Creates a Result object from an error.
Result< R, Err > with_success_val(const R &s)
bool is_error() const noexcept
Checks if is an error Result.
bool is_success() const noexcept
Checks if is a success Result.
std::variant< std::monostate, ErrVal > val
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
Result(const T &val)
Creates a Result object from a success Allows for implicit casting by returning success value.
bool operator==(const T &other) const noexcept
Compares Result to a value.
bool operator==(const Result &other) const noexcept
Compares results.
bool copy_if_present(std::remove_const_t< T > &out) const noexcept
Copies into a reference the successful value if there is one.
T value() const noexcept
Checks if is a successful Result (aka.
Result< R, Err > with_success_val(const R &s)
T const * operator->() const noexcept
Dereference the value (fails if an error value)
bool is_success() const noexcept
Checks if is a successful Result (aka.
T & operator*()
Dereference the value (fails if an error value)
Result(T &&val)
Creates a Result object from a success Allows for implicit casting by returning success value.
static Result from_success(const T &val)
Creates a Result object from a success.
bool operator!=(const T &other) const noexcept
const T & operator*() const noexcept
Dereference the value (fails if an error value)
static Result from_error(const ErrVal &err)
Creates a Result object from an error.
bool move_if_present(T &out) noexcept
Moves into a reference the successful value if there is one.
bool operator!=(const Result &other) const noexcept
bool is_error() const noexcept
Checks if is an error Result.
Result< void, Err > to_void() const
ErrVal error() const noexcept
Returns the associated error Fails if there is no error;.
T * operator->()
Dereference the value (fails if an error value)
Represents a success result (auto castable to Result)