#ifndef BASE_TYPES_EXPECTED_H_
#define BASE_TYPES_EXPECTED_H_
#include <concepts>
#include <string_view>
#include <type_traits>
#include <utility>
#include <variant>
#include "base/check.h"
#include "base/strings/strcat.h"
#include "base/strings/to_string.h"
#include "base/types/expected_internal.h"
namespace base {
template <typename T>
class ok final {
public:
template <typename U = T>
requires(internal::IsOkValueConstruction<T, U>)
constexpr explicit ok(U&& val) noexcept : value_(std::forward<U>(val)) {}
template <typename... Args>
constexpr explicit ok(std::in_place_t, Args&&... args) noexcept
: value_(std::forward<Args>(args)...) {}
template <typename U, typename... Args>
constexpr ok(std::in_place_t,
std::initializer_list<U> il,
Args&&... args) noexcept
: value_(il, std::forward<Args>(args)...) {}
constexpr T& value() & noexcept { return value_; }
constexpr const T& value() const& noexcept { return value_; }
constexpr T&& value() && noexcept { return std::move(value()); }
constexpr const T&& value() const&& noexcept { return std::move(value()); }
constexpr void swap(ok& other) noexcept {
using std::swap;
swap(value(), other.value());
}
friend constexpr void swap(ok& x, ok& y) noexcept { x.swap(y); }
std::string ToString() const {
return StrCat({"ok(", base::ToString(value()), ")"});
}
private:
T value_;
};
template <typename T>
requires(std::is_void_v<T>)
class ok<T> final {
public:
constexpr ok() noexcept = default;
std::string ToString() const { return "ok()"; }
};
template <typename T, typename U>
constexpr bool operator==(const ok<T>& lhs, const ok<U>& rhs) noexcept {
if constexpr (std::is_void_v<T> && std::is_void_v<U>) {
return true;
} else if constexpr (std::is_void_v<T> || std::is_void_v<U>) {
return false;
} else {
return lhs.value() == rhs.value();
}
}
template <typename T>
ok(T) -> ok<T>;
ok() -> ok<void>;
template <typename E>
class unexpected final {
public:
template <typename Err = E>
requires(internal::IsUnexpectedValueConstruction<E, Err>)
constexpr explicit unexpected(Err&& err) noexcept
: error_(std::forward<Err>(err)) {}
template <typename... Args>
constexpr explicit unexpected(std::in_place_t, Args&&... args) noexcept
: error_(std::forward<Args>(args)...) {}
template <typename U, typename... Args>
constexpr unexpected(std::in_place_t,
std::initializer_list<U> il,
Args&&... args) noexcept
: error_(il, std::forward<Args>(args)...) {}
constexpr E& error() & noexcept { return error_; }
constexpr const E& error() const& noexcept { return error_; }
constexpr E&& error() && noexcept { return std::move(error()); }
constexpr const E&& error() const&& noexcept { return std::move(error()); }
constexpr void swap(unexpected& other) noexcept {
using std::swap;
swap(error(), other.error());
}
friend constexpr void swap(unexpected& x, unexpected& y) noexcept {
x.swap(y);
}
std::string ToString() const noexcept {
return StrCat({"Unexpected(", base::ToString(error()), ")"});
}
private:
E error_;
};
template <typename E, typename G>
constexpr bool operator==(const unexpected<E>& lhs,
const unexpected<G>& rhs) noexcept {
return lhs.error() == rhs.error();
}
template <typename E, typename G>
constexpr bool operator!=(const unexpected<E>& lhs,
const unexpected<G>& rhs) noexcept {
return !(lhs == rhs);
}
template <typename E>
unexpected(E) -> unexpected<E>;
template <typename T, typename E>
class [[nodiscard, gsl::Owner]] expected final {
static_assert(!std::is_void_v<T>, "Error: T must not be void");
public:
using value_type = T;
using error_type = E;
using unexpected_type = unexpected<E>;
template <typename U>
using rebind = expected<U, E>;
template <typename U, typename G>
friend class expected;
constexpr expected() noexcept = default;
template <typename U, typename G>
requires(internal::IsValidConversion<T, E, const U&, const G&>)
explicit(!std::convertible_to<const U&, T> ||
!std::convertible_to<const G&, E>)
constexpr expected(const expected<U, G>& rhs) noexcept
: impl_(rhs.impl_) {}
template <typename U, typename G>
requires(internal::IsValidConversion<T, E, U, G>)
explicit(!std::convertible_to<U, T> || !std::convertible_to<G, E>)
constexpr expected(expected<U, G>&& rhs) noexcept
: impl_(std::move(rhs.impl_)) {}
template <typename U = std::remove_cv_t<T>>
requires(internal::IsValidValueConstruction<T, E, U>)
explicit(!std::convertible_to<U, T> || std::convertible_to<U, E>)
constexpr expected(U&& v) noexcept
: impl_(kValTag, std::forward<U>(v)) {}
template <typename U>
requires(std::constructible_from<T, const U&>)
explicit(!std::convertible_to<const U&, T>)
constexpr expected(const ok<U>& o) noexcept
: impl_(kValTag, o.value()) {}
template <typename U>
requires(std::constructible_from<T, U>)
explicit(!std::convertible_to<U, T>)
constexpr expected(ok<U>&& o) noexcept
: impl_(kValTag, std::move(o.value())) {}
template <typename G>
requires(std::constructible_from<E, const G&>)
explicit(!std::convertible_to<const G&, E>)
constexpr expected(const unexpected<G>& e) noexcept
: impl_(kErrTag, e.error()) {}
template <typename G>
requires(std::constructible_from<E, G>)
explicit(!std::convertible_to<G, E>)
constexpr expected(unexpected<G>&& e) noexcept
: impl_(kErrTag, std::move(e.error())) {}
template <typename... Args>
constexpr explicit expected(std::in_place_t, Args&&... args) noexcept
: impl_(kValTag, std::forward<Args>(args)...) {}
template <typename U, typename... Args>
constexpr expected(std::in_place_t,
std::initializer_list<U> il,
Args&&... args) noexcept
: impl_(kValTag, il, std::forward<Args>(args)...) {}
template <typename... Args>
constexpr explicit expected(unexpect_t, Args&&... args) noexcept
: impl_(kErrTag, std::forward<Args>(args)...) {}
template <typename U, typename... Args>
constexpr expected(unexpect_t,
std::initializer_list<U> il,
Args&&... args) noexcept
: impl_(kErrTag, il, std::forward<Args>(args)...) {}
template <typename U = std::remove_cv_t<T>>
requires(internal::IsValueAssignment<T, E, U>)
constexpr expected& operator=(U&& v) noexcept {
emplace(std::forward<U>(v));
return *this;
}
template <typename U>
constexpr expected& operator=(const ok<U>& o) noexcept {
emplace(o.value());
return *this;
}
template <typename U>
constexpr expected& operator=(ok<U>&& o) noexcept {
emplace(std::move(o.value()));
return *this;
}
template <typename G>
constexpr expected& operator=(const unexpected<G>& e) noexcept {
impl_.emplace_error(e.error());
return *this;
}
template <typename G>
constexpr expected& operator=(unexpected<G>&& e) noexcept {
impl_.emplace_error(std::move(e.error()));
return *this;
}
template <typename... Args>
constexpr T& emplace(Args&&... args) noexcept {
return impl_.emplace_value(std::forward<Args>(args)...);
}
template <typename U, typename... Args>
constexpr T& emplace(std::initializer_list<U> il, Args&&... args) noexcept {
return impl_.emplace_value(il, std::forward<Args>(args)...);
}
constexpr void swap(expected& rhs) noexcept { impl_.swap(rhs.impl_); }
friend constexpr void swap(expected& x, expected& y) noexcept { x.swap(y); }
constexpr T* operator->() noexcept { return std::addressof(value()); }
constexpr const T* operator->() const noexcept {
return std::addressof(value());
}
constexpr T& operator*() & noexcept { return value(); }
constexpr const T& operator*() const& noexcept { return value(); }
constexpr T&& operator*() && noexcept { return std::move(value()); }
constexpr const T&& operator*() const&& noexcept {
return std::move(value());
}
constexpr bool has_value() const noexcept { return impl_.has_value(); }
constexpr T& value() & noexcept { return impl_.value(); }
constexpr const T& value() const& noexcept { return impl_.value(); }
constexpr T&& value() && noexcept { return std::move(value()); }
constexpr const T&& value() const&& noexcept { return std::move(value()); }
constexpr E& error() & noexcept { return impl_.error(); }
constexpr const E& error() const& noexcept { return impl_.error(); }
constexpr E&& error() && noexcept { return std::move(error()); }
constexpr const E&& error() const&& noexcept { return std::move(error()); }
template <typename U = std::remove_cv_t<T>>
constexpr T value_or(U&& v) const& noexcept {
static_assert(std::copy_constructible<T>,
"expected<T, E>::value_or: T must be copy constructible");
static_assert(std::convertible_to<U&&, T>,
"expected<T, E>::value_or: U must be convertible to T");
return has_value() ? value() : static_cast<T>(std::forward<U>(v));
}
template <typename U = std::remove_cv_t<T>>
constexpr T value_or(U&& v) && noexcept {
static_assert(std::move_constructible<T>,
"expected<T, E>::value_or: T must be move constructible");
static_assert(std::convertible_to<U&&, T>,
"expected<T, E>::value_or: U must be convertible to T");
return has_value() ? std::move(value())
: static_cast<T>(std::forward<U>(v));
}
template <typename G = E>
constexpr E error_or(G&& e) const& noexcept {
static_assert(std::copy_constructible<E>,
"expected<T, E>::error_or: E must be copy constructible");
static_assert(std::convertible_to<G&&, E>,
"expected<T, E>::error_or: G must be convertible to E");
return has_value() ? static_cast<E>(std::forward<G>(e)) : error();
}
template <typename G = E>
constexpr E error_or(G&& e) && noexcept {
static_assert(std::move_constructible<E>,
"expected<T, E>::error_or: E must be move constructible");
static_assert(std::convertible_to<G&&, E>,
"expected<T, E>::error_or: G must be convertible to E");
return has_value() ? static_cast<E>(std::forward<G>(e))
: std::move(error());
}
template <typename F>
requires(std::copy_constructible<E>)
constexpr auto and_then(F&& f) & noexcept {
return internal::AndThen(*this, std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<E>)
constexpr auto and_then(F&& f) const& noexcept {
return internal::AndThen(*this, std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<E>)
constexpr auto and_then(F&& f) && noexcept {
return internal::AndThen(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<E>)
constexpr auto and_then(F&& f) const&& noexcept {
return internal::AndThen(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<T>)
constexpr auto or_else(F&& f) & noexcept {
return internal::OrElse(*this, std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<T>)
constexpr auto or_else(F&& f) const& noexcept {
return internal::OrElse(*this, std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<T>)
constexpr auto or_else(F&& f) && noexcept {
return internal::OrElse(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<T>)
constexpr auto or_else(F&& f) const&& noexcept {
return internal::OrElse(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<E>)
constexpr auto transform(F&& f) & noexcept {
return internal::Transform(*this, std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<E>)
constexpr auto transform(F&& f) const& noexcept {
return internal::Transform(*this, std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<E>)
constexpr auto transform(F&& f) && noexcept {
return internal::Transform(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<E>)
constexpr auto transform(F&& f) const&& noexcept {
return internal::Transform(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<T>)
constexpr auto transform_error(F&& f) & noexcept {
return internal::TransformError(*this, std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<T>)
constexpr auto transform_error(F&& f) const& noexcept {
return internal::TransformError(*this, std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<T>)
constexpr auto transform_error(F&& f) && noexcept {
return internal::TransformError(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<T>)
constexpr auto transform_error(F&& f) const&& noexcept {
return internal::TransformError(std::move(*this), std::forward<F>(f));
}
std::string ToString() const {
return has_value() ? StrCat({"Expected(", base::ToString(value()), ")"})
: StrCat({"Unexpected(", base::ToString(error()), ")"});
}
private:
using Impl = internal::ExpectedImpl<T, E>;
static constexpr auto kValTag = Impl::kValTag;
static constexpr auto kErrTag = Impl::kErrTag;
Impl impl_;
};
template <typename T, typename E>
requires(std::is_void_v<T>)
class [[nodiscard]] expected<T, E> final {
static_assert(std::is_void_v<T>, "Error: T must be void");
public:
using value_type = T;
using error_type = E;
using unexpected_type = unexpected<E>;
template <typename U>
using rebind = expected<U, E>;
template <typename U, typename G>
friend class expected;
constexpr expected() noexcept = default;
template <typename U, typename G>
requires(internal::IsValidVoidConversion<E, U, const G&>)
explicit(!std::convertible_to<const G&, E>)
constexpr expected(const expected<U, G>& rhs) noexcept
: impl_(rhs.impl_) {}
template <typename U, typename G>
requires(internal::IsValidVoidConversion<E, U, G>)
explicit(!std::convertible_to<G, E>)
constexpr expected(expected<U, G>&& rhs) noexcept
: impl_(std::move(rhs.impl_)) {}
constexpr expected(base::ok<T>) noexcept {}
template <typename G>
requires(std::constructible_from<E, const G&>)
explicit(!std::convertible_to<const G&, E>)
constexpr expected(const unexpected<G>& e) noexcept
: impl_(kErrTag, e.error()) {}
template <typename G>
requires(std::constructible_from<E, G>)
explicit(!std::convertible_to<G, E>)
constexpr expected(unexpected<G>&& e) noexcept
: impl_(kErrTag, std::move(e.error())) {}
constexpr explicit expected(std::in_place_t) noexcept {}
template <typename... Args>
constexpr explicit expected(unexpect_t, Args&&... args) noexcept
: impl_(kErrTag, std::forward<Args>(args)...) {}
template <typename U, typename... Args>
constexpr expected(unexpect_t,
std::initializer_list<U> il,
Args&&... args) noexcept
: impl_(kErrTag, il, std::forward<Args>(args)...) {}
template <typename G>
constexpr expected& operator=(const unexpected<G>& e) noexcept {
impl_.emplace_error(e.error());
return *this;
}
template <typename G>
constexpr expected& operator=(unexpected<G>&& e) noexcept {
impl_.emplace_error(std::move(e.error()));
return *this;
}
constexpr void emplace() noexcept { impl_.emplace_value(); }
constexpr void swap(expected& rhs) noexcept { impl_.swap(rhs.impl_); }
friend constexpr void swap(expected& x, expected& y) noexcept { x.swap(y); }
constexpr bool has_value() const noexcept { return impl_.has_value(); }
constexpr void operator*() const { CHECK(has_value()); }
constexpr void value() const { CHECK(has_value()); }
constexpr E& error() & { return impl_.error(); }
constexpr const E& error() const& { return impl_.error(); }
constexpr E&& error() && { return std::move(error()); }
constexpr const E&& error() const&& { return std::move(error()); }
template <typename G>
constexpr E error_or(G&& e) const& noexcept {
static_assert(std::copy_constructible<E>,
"expected<T, E>::error_or: E must be copy constructible");
static_assert(std::convertible_to<G&&, E>,
"expected<T, E>::error_or: G must be convertible to E");
return has_value() ? static_cast<E>(std::forward<G>(e)) : error();
}
template <typename G>
constexpr E error_or(G&& e) && noexcept {
static_assert(std::move_constructible<E>,
"expected<T, E>::error_or: E must be move constructible");
static_assert(std::convertible_to<G&&, E>,
"expected<T, E>::error_or: G must be convertible to E");
return has_value() ? static_cast<E>(std::forward<G>(e))
: std::move(error());
}
template <typename F>
requires(std::copy_constructible<E>)
constexpr auto and_then(F&& f) & noexcept {
return internal::AndThen(*this, std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<E>)
constexpr auto and_then(F&& f) const& noexcept {
return internal::AndThen(*this, std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<E>)
constexpr auto and_then(F&& f) && noexcept {
return internal::AndThen(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<E>)
constexpr auto and_then(F&& f) const&& noexcept {
return internal::AndThen(std::move(*this), std::forward<F>(f));
}
template <typename F>
constexpr auto or_else(F&& f) & noexcept {
return internal::OrElse(*this, std::forward<F>(f));
}
template <typename F>
constexpr auto or_else(F&& f) const& noexcept {
return internal::OrElse(*this, std::forward<F>(f));
}
template <typename F>
constexpr auto or_else(F&& f) && noexcept {
return internal::OrElse(std::move(*this), std::forward<F>(f));
}
template <typename F>
constexpr auto or_else(F&& f) const&& noexcept {
return internal::OrElse(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<E>)
constexpr auto transform(F&& f) & noexcept {
return internal::Transform(*this, std::forward<F>(f));
}
template <typename F>
requires(std::copy_constructible<E>)
constexpr auto transform(F&& f) const& noexcept {
return internal::Transform(*this, std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<E>)
constexpr auto transform(F&& f) && noexcept {
return internal::Transform(std::move(*this), std::forward<F>(f));
}
template <typename F>
requires(std::move_constructible<E>)
constexpr auto transform(F&& f) const&& noexcept {
return internal::Transform(std::move(*this), std::forward<F>(f));
}
template <typename F>
constexpr auto transform_error(F&& f) & noexcept {
return internal::TransformError(*this, std::forward<F>(f));
}
template <typename F>
constexpr auto transform_error(F&& f) const& noexcept {
return internal::TransformError(*this, std::forward<F>(f));
}
template <typename F>
constexpr auto transform_error(F&& f) && noexcept {
return internal::TransformError(std::move(*this), std::forward<F>(f));
}
template <typename F>
constexpr auto transform_error(F&& f) const&& noexcept {
return internal::TransformError(std::move(*this), std::forward<F>(f));
}
std::string ToString() const {
return has_value() ? "Expected()"
: StrCat({"Unexpected(", base::ToString(error()), ")"});
}
private:
using Impl = internal::ExpectedImpl<std::monostate, E>;
static constexpr auto kErrTag = Impl::kErrTag;
Impl impl_;
};
template <typename T, typename E, typename U, typename G>
constexpr bool operator==(const expected<T, E>& x,
const expected<U, G>& y) noexcept {
if (x.has_value() != y.has_value()) {
return false;
}
if (x.has_value()) {
if constexpr (std::is_void_v<T> && std::is_void_v<U>) {
return true;
} else {
return x.value() == y.value();
}
}
return x.error() == y.error();
}
template <typename T, typename E, typename U>
requires(!std::is_void_v<T>)
constexpr bool operator==(const expected<T, E>& x, const U& v) noexcept {
return x.has_value() && x.value() == v;
}
template <typename T, typename E, typename U>
constexpr bool operator==(const expected<T, E>& x, const ok<U>& o) noexcept {
if constexpr (std::is_void_v<T> && std::is_void_v<U>) {
return x.has_value();
} else if constexpr (std::is_void_v<T> || std::is_void_v<U>) {
return false;
} else {
return x.has_value() && x.value() == o.value();
}
}
template <typename T, typename E, typename G>
constexpr bool operator==(const expected<T, E>& x,
const unexpected<G>& e) noexcept {
return !x.has_value() && x.error() == e.error();
}
}
#endif