#ifndef RUST_CXX_ENUMEXT_H
#define RUST_CXX_ENUMEXT_H
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <functional>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
namespace rust {
namespace enm {
template <std::size_t I, typename... Ts> struct variant_alternative;
template <std::size_t I> struct variant_alternative<I> {};
template <std::size_t I, typename First, typename... Remainder>
struct variant_alternative<I, First, Remainder...>
: variant_alternative<I - 1, Remainder...> {};
template <typename First, typename... Remainder>
struct variant_alternative<0, First, Remainder...> {
using type = First;
};
template <std::size_t I, typename... Ts>
using variant_alternative_t = typename variant_alternative<I, Ts...>::type;
template <bool... Values> constexpr size_t compile_time_count() noexcept {
return 0 + (static_cast<std::size_t>(Values) + ...);
}
template <bool... Values>
struct count
: std::integral_constant<std::size_t, compile_time_count<Values...>()> {};
template <bool... Values>
struct exactly_once : std::conditional_t<count<Values...>::value == 1,
std::true_type, std::false_type> {};
template <std::size_t I, bool... Values> struct index_from_booleans;
template <std::size_t I> struct index_from_booleans<I> {};
template <std::size_t I, bool First, bool... Remainder>
struct index_from_booleans<I, First, Remainder...>
: index_from_booleans<I + 1, Remainder...> {};
template <std::size_t I, bool... Remainder>
struct index_from_booleans<I, true, Remainder...>
: std::integral_constant<std::size_t, I> {};
template <typename Type, typename... Ts>
struct index_from_type
: index_from_booleans<0, std::is_same_v<std::decay_t<Type>, Ts>...> {
static_assert(exactly_once<std::is_same_v<std::decay_t<Type>, Ts>...>::value,
"Index must be unique");
};
template <typename... Ts> struct visitor_type;
template <typename... Ts> struct variant_base;
template <std::size_t I, typename... Ts>
constexpr decltype(auto) get(variant_base<Ts...> &);
template <std::size_t I, typename... Ts>
constexpr decltype(auto) get(const variant_base<Ts...> &);
template <std::size_t I, typename... Ts>
constexpr std::add_pointer_t<variant_alternative_t<I, Ts...>>
get_if(variant_base<Ts...> *variant);
template <std::size_t I, typename... Ts>
constexpr const std::add_pointer_t<variant_alternative_t<I, Ts...>>
get_if(const variant_base<Ts...> *variant);
template <typename Visitor, typename... Ts>
constexpr decltype(auto) visit(Visitor &&visitor, variant_base<Ts...> &);
template <typename Visitor, typename... Ts>
constexpr decltype(auto) visit(Visitor &&visitor, const variant_base<Ts...> &);
template <typename... Ts> struct variant_base {
static_assert(sizeof...(Ts) > 0,
"variant_base must hold at least one alternative");
variant_base() = delete;
constexpr static bool all_copy_constructible_v =
std::conjunction_v<std::is_copy_constructible<Ts>...>;
variant_base(const variant_base &other) {
static_assert(
all_copy_constructible_v,
"Copy constructor requires that all types are copy constructable");
m_Index = other.m_Index;
visit(
[this](const auto &value) {
using type = std::decay_t<decltype(value)>;
new (static_cast<void *>(m_Buff)) type(value);
},
other);
};
variant_base(variant_base &&other) = delete;
template <typename T>
constexpr static bool is_unique_v =
exactly_once<std::is_same_v<Ts, std::decay_t<T>>...>::value;
template <typename T>
constexpr static std::size_t index_from_type_v =
index_from_type<T, Ts...>::value;
template <typename T, typename D = std::decay_t<T>,
typename = std::enable_if_t<is_unique_v<T> &&
std::is_constructible_v<D, T>>>
variant_base(T &&other) noexcept(std::is_nothrow_constructible_v<D, T>) {
m_Index = index_from_type_v<D>;
new (static_cast<void *>(m_Buff)) D(std::forward<T>(other));
}
template <typename T, typename... Args,
typename = std::enable_if_t<is_unique_v<T>>,
typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
explicit variant_base(
[[maybe_unused]] std::in_place_type_t<T> type,
Args &&...args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
: variant_base{std::in_place_index<index_from_type_v<T>>,
std::forward<Args>(args)...} {}
template <std::size_t I>
using type_from_index_t = variant_alternative_t<I, Ts...>;
template <std::size_t I, typename... Args, typename T = type_from_index_t<I>,
typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
explicit variant_base(
[[maybe_unused]] std::in_place_index_t<I> index,
Args &&...args) noexcept(std::is_nothrow_constructible_v<T, Args...>) {
m_Index = I;
new (static_cast<void *>(m_Buff)) T(std::forward<Args>(args)...);
}
template <typename... Rs>
constexpr static bool all_same_v =
std::conjunction_v<std::is_same<Rs, Ts>...>;
template <typename... Rs, typename = std::enable_if_t<
all_same_v<Rs...> && all_copy_constructible_v>>
variant_base(const std::variant<Rs...> &other) {
m_Index = other.index();
std::visit(
[this](const auto &value) {
using type = std::decay_t<decltype(value)>;
new (static_cast<void *>(m_Buff)) type(value);
},
other);
}
constexpr static bool all_move_constructible_v =
std::conjunction_v<std::is_move_constructible<Ts>...>;
template <typename... Rs, typename = std::enable_if_t<
all_same_v<Rs...> && all_move_constructible_v>>
variant_base(std::variant<Rs...> &&other) {
m_Index = other.index();
std::visit(
[this](auto &&value) {
using type = std::decay_t<decltype(value)>;
new (static_cast<void *>(m_Buff)) type(std::move(value));
},
other);
}
~variant_base() { destroy(); }
variant_base &operator=(const variant_base &other) {
static_assert(
all_copy_constructible_v,
"Copy assignment requires that all types are copy constructable");
visit([this](const auto &value) { *this = value; }, other);
return *this;
};
variant_base &operator=(variant_base &&other) = delete;
template <typename T, typename = std::enable_if_t<
is_unique_v<T> && std::is_constructible_v<T &&, T>>>
variant_base &operator=(T &&other) {
constexpr auto index = index_from_type_v<T>;
if (m_Index == index) {
if constexpr (std::is_nothrow_assignable_v<T, T &&>) {
get<index>(*this) = std::forward<T>(other);
return *this;
}
}
this->emplace<std::decay_t<T>>(std::forward<T>(other));
return *this;
}
template <typename... Rs, typename = std::enable_if_t<
all_same_v<Rs...> && all_copy_constructible_v>>
variant_base &operator=(const std::variant<Rs...> &other) {
std::visit(
[this](const auto &value) {
using type = decltype(value);
emplace<std::decay_t<type>>(value);
},
other);
return *this;
}
template <typename... Rs, typename = std::enable_if_t<
all_same_v<Rs...> && all_move_constructible_v>>
variant_base &operator=(std::variant<Rs...> &&other) {
std::visit(
[this](auto &&value) {
using type = decltype(value);
emplace<std::decay_t<type>>(std::move(value));
},
other);
return *this;
}
template <typename T, typename... Args,
typename = std::enable_if_t<is_unique_v<T>>,
typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
T &emplace(Args &&...args) {
constexpr std::size_t index = index_from_type_v<T>;
return this->emplace<index>(std::forward<Args>(args)...);
}
template <std::size_t I, typename... Args, typename T = type_from_index_t<I>,
typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
T &emplace(Args &&...args) {
if constexpr (std::is_nothrow_constructible_v<T, Args...>) {
destroy();
new (static_cast<void *>(m_Buff)) T(std::forward<Args>(args)...);
} else if constexpr (std::is_nothrow_move_constructible_v<T>) {
const T tmp{std::forward<Args>(args)...};
destroy();
new (static_cast<void *>(m_Buff)) T(std::move(tmp));
} else {
alignas(Ts...) std::byte old_buff[std::max({sizeof(Ts)...})];
std::memcpy(old_buff, m_Buff, sizeof(m_Buff));
try {
new (static_cast<void *>(m_Buff)) T(std::forward<Args>(args)...);
} catch (...) {
std::memcpy(m_Buff, old_buff, sizeof(m_Buff));
throw;
}
std::swap_ranges(m_Buff, m_Buff + sizeof(m_Buff), old_buff);
destroy();
std::memcpy(m_Buff, old_buff, sizeof(m_Buff));
}
m_Index = I;
return get<I>(*this);
}
constexpr std::size_t index() const noexcept { return m_Index; }
void swap(variant_base &other) {
std::swap_ranges(m_Buff, m_Buff + sizeof(m_Buff), other.m_Buff);
std::swap(m_Index, other.m_Index);
}
struct bad_rust_variant_access : std::runtime_error {
bad_rust_variant_access(std::size_t index)
: std::runtime_error{"The index should be " + std::to_string(index)} {}
};
protected:
template <std::size_t I> void throw_if_invalid() const {
static_assert(I < (sizeof...(Ts)), "Invalid index");
if (m_Index != I)
throw bad_rust_variant_access(m_Index);
}
template <std::size_t I> bool is_valid() const {
static_assert(I < (sizeof...(Ts)), "Invalid index");
return m_Index == I;
}
void destroy() {
visit(
[](const auto &value) {
using type = std::decay_t<decltype(value)>;
value.~type();
},
*this);
}
int m_Index;
alignas(Ts...) std::byte m_Buff[std::max({sizeof(Ts)...})];
private:
template <std::size_t I, typename... Rs>
friend constexpr decltype(auto) get(variant_base<Rs...> &variant);
template <std::size_t I, typename... Rs>
friend constexpr decltype(auto) get(const variant_base<Rs...> &variant);
template <std::size_t I, typename... Rs>
friend constexpr std::add_pointer_t<variant_alternative_t<I, Rs...>>
get_if(variant_base<Rs...> *variant);
template <std::size_t I, typename... Rs>
friend constexpr const std::add_pointer_t<variant_alternative_t<I, Rs...>>
get_if(const variant_base<Rs...> *variant);
template <typename... Rs> friend struct visitor_type;
};
template <typename First, typename... Remainder>
struct visitor_type<First, Remainder...> {
template <typename Visitor, typename Variant>
constexpr static decltype(auto) visit(Visitor &&visitor, Variant &&variant) {
return visit(std::forward<Visitor>(visitor), variant.m_Index,
variant.m_Buff);
}
template <typename Visitor>
constexpr static auto visit(Visitor &&visitor, std::size_t index,
std::byte *data)
-> decltype(visitor(*reinterpret_cast<First *>(data))) {
if (index == 0) {
return visitor(*reinterpret_cast<First *>(data));
}
if constexpr (sizeof...(Remainder) != 0) {
return visitor_type<Remainder...>::visit(std::forward<Visitor>(visitor),
--index, data);
}
throw std::out_of_range("invalid");
}
template <typename Visitor>
constexpr static auto visit(Visitor &&visitor, std::size_t index,
const std::byte *data)
-> decltype(visitor(*reinterpret_cast<const First *>(data))) {
if (index == 0) {
return visitor(*reinterpret_cast<const First *>(data));
}
if constexpr (sizeof...(Remainder) != 0) {
return visitor_type<Remainder...>::visit(std::forward<Visitor>(visitor),
--index, data);
}
throw std::out_of_range("invalid");
}
};
template <typename Visitor, typename... Ts>
constexpr decltype(auto) visit(Visitor &&visitor,
variant_base<Ts...> &variant) {
return visitor_type<Ts...>::visit(std::forward<Visitor>(visitor), variant);
}
template <typename Visitor, typename... Ts>
constexpr decltype(auto) visit(Visitor &&visitor,
const variant_base<Ts...> &variant) {
return visitor_type<Ts...>::visit(std::forward<Visitor>(visitor), variant);
}
template <std::size_t I, typename... Ts>
constexpr decltype(auto) get(variant_base<Ts...> &variant) {
variant.template throw_if_invalid<I>();
return *reinterpret_cast<variant_alternative_t<I, Ts...> *>(variant.m_Buff);
}
template <std::size_t I, typename... Ts>
constexpr decltype(auto) get(const variant_base<Ts...> &variant) {
variant.template throw_if_invalid<I>();
return *reinterpret_cast<const variant_alternative_t<I, Ts...> *>(
variant.m_Buff);
}
template <typename T, typename... Ts,
typename = std::enable_if_t<
exactly_once<std::is_same_v<Ts, std::decay_t<T>>...>::value>>
constexpr const T &get(const variant_base<Ts...> &variant) {
constexpr auto index = index_from_type<T, Ts...>::value;
return get<index>(variant);
}
template <typename T, typename... Ts,
typename = std::enable_if_t<
exactly_once<std::is_same_v<Ts, std::decay_t<T>>...>::value>>
constexpr T &get(variant_base<Ts...> &variant) {
constexpr auto index = index_from_type<T, Ts...>::value;
return get<index>(variant);
}
template <std::size_t I, typename... Ts>
constexpr std::add_pointer_t<variant_alternative_t<I, Ts...>>
get_if(variant_base<Ts...> *variant) {
if (!variant->template is_valid<I>())
return nullptr;
return reinterpret_cast<variant_alternative_t<I, Ts...> *>(variant->m_Buff);
}
template <std::size_t I, typename... Ts>
constexpr const std::add_pointer_t<variant_alternative_t<I, Ts...>>
get_if(const variant_base<Ts...> *variant) {
if (!variant->template is_valid<I>())
return nullptr;
return reinterpret_cast<const variant_alternative_t<I, Ts...> *>(
variant->m_Buff);
}
template <typename T, typename... Ts,
typename = std::enable_if_t<
exactly_once<std::is_same_v<Ts, std::decay_t<T>>...>::value>>
constexpr const std::add_pointer_t<T>
get_if(const variant_base<Ts...> *variant) {
constexpr auto index = index_from_type<T, Ts...>::value;
return get_if<index>(variant);
}
template <typename T, typename... Ts,
typename = std::enable_if_t<
exactly_once<std::is_same_v<Ts, std::decay_t<T>>...>::value>>
constexpr std::add_pointer_t<T> get_if(variant_base<Ts...> *variant) {
constexpr auto index = index_from_type<T, Ts...>::value;
return get_if<index>(variant);
}
template <std::size_t I, typename... Ts>
constexpr bool holds_alternative(const variant_base<Ts...> &variant) {
return variant.index() == I;
}
template <typename T, typename... Ts,
typename = std::enable_if_t<
exactly_once<std::is_same_v<Ts, std::decay_t<T>>...>::value>>
constexpr bool holds_alternative(const variant_base<Ts...> &variant) {
return variant.index() == index_from_type<T, Ts...>::value;
}
template <bool> struct copy_control;
template <> struct copy_control<true> {
copy_control() = default;
copy_control(const copy_control &other) = default;
copy_control &operator=(const copy_control &) = default;
};
template <> struct copy_control<false> {
copy_control() = default;
copy_control(const copy_control &other) = delete;
copy_control &operator=(const copy_control &) = delete;
};
template <typename... Ts>
using allow_copy =
copy_control<std::conjunction_v<std::is_copy_constructible<Ts>...>>;
template <typename... Ts>
struct variant : public variant_base<Ts...>, private allow_copy<Ts...> {
using base = variant_base<Ts...>;
variant() = delete;
variant(const variant &) = default;
variant(variant &&) = delete;
using base::base;
variant &operator=(const variant &) = default;
variant &operator=(variant &&) = delete;
using base::operator=;
};
struct monostate {};
} }
namespace rust {
namespace enm {
template <typename T> struct optional;
namespace detail {
template <class T> struct is_std_optional_impl : std::false_type {};
template <class T>
struct is_std_optional_impl<std::optional<T>> : std::true_type {};
template <class T>
using is_std_optional = is_std_optional_impl<std::decay_t<T>>;
template <class T> struct is_rust_optional_impl : std::false_type {};
template <class T>
struct is_rust_optional_impl<optional<T>> : std::true_type {};
template <class T>
using is_rust_optional = is_rust_optional_impl<std::decay_t<T>>;
}
struct bad_rust_optional_access : std::runtime_error {
bad_rust_optional_access() : std::runtime_error{"Optional has no value"} {}
};
template <typename T> struct optional : public variant<monostate, T> {
using base = variant<monostate, T>;
optional() : base(monostate{}) {};
optional(std::nullopt_t) : base(monostate{}) {};
optional(const optional &) = default;
optional(optional &&) = delete;
using base::base;
using base::operator=;
using Some = T;
using None = monostate;
constexpr explicit operator bool() { return this->m_Index == 1; }
constexpr bool has_value() const noexcept { return this->m_Index == 1; }
constexpr bool is_some() const noexcept { return this->m_Index == 1; }
constexpr bool is_none() const noexcept { return this->m_Index == 0; }
constexpr T &value() & {
if (has_value()) {
return *reinterpret_cast<T *>(this->m_Buff);
} else {
throw bad_rust_optional_access();
}
}
constexpr const T &value() const & {
if (has_value()) {
return *reinterpret_cast<const T *>(this->m_Buff);
} else {
throw bad_rust_optional_access();
}
}
constexpr void reset() noexcept {
if (has_value()) {
this->destroy();
*this = monostate{};
}
}
constexpr const T *operator->() const noexcept {
reinterpret_cast<const T *>(this->m_Buff);
}
constexpr T *operator->() noexcept { reinterpret_cast<T *>(this->m_Buff); }
constexpr const T &operator*() const & noexcept {
*reinterpret_cast<const T *>(this->m_Buff);
}
constexpr T &operator*() & noexcept { *reinterpret_cast<T *>(this->m_Buff); }
template <class U = std::remove_cv_t<T>>
constexpr T value_or(U &&default_value) const & {
return has_value() ? *reinterpret_cast<const T *>(this->m_Buff)
: static_cast<T>(std::forward<U>(default_value));
}
template <class F> constexpr auto and_then(F &&f) & {
using result = std::invoke_result_t<F, T &>;
static_assert(detail::is_std_optional<result>::value ||
detail::is_rust_optional<result>::value,
"F must return an std::optional or rust::variant::optional");
return (has_value()) ? std::invoke(std::forward<F>(f), value()) : result{};
}
template <class F> constexpr auto and_then(F &&f) const & {
using result = std::invoke_result_t<F, const T &>;
static_assert(detail::is_std_optional<result>::value ||
detail::is_rust_optional<result>::value,
"F must return an std::optional or rust::variant::optional");
return (has_value()) ? std::invoke(std::forward<F>(f), value()) : result{};
}
template <class F> constexpr auto transform(F &&f) & {
using result =
std::optional<std::remove_cv_t<std::invoke_result_t<F, T &>>>;
return has_value() ? std::invoke(std::forward<F>(f), value())
: result(std::nullopt);
}
template <class F> constexpr auto transform(F &&f) const & {
using result =
std::optional<std::remove_cv_t<std::invoke_result_t<F, const T &>>>;
return has_value() ? std::invoke(std::forward<F>(f), value())
: result(std::nullopt);
}
template <class F> constexpr T &or_else(F &&f) & {
return has_value() ? *this : std::forward<F>(f)();
}
template <class F> constexpr const T &or_else(F &&f) const & {
return has_value() ? *this : std::forward<F>(f)();
}
using IsRelocatable = ::std::true_type;
};
template <class T, class U>
inline constexpr bool operator==(const optional<T> &lhs,
const optional<U> &rhs) {
return lhs.has_value == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs);
}
template <class T, class U>
inline constexpr bool operator!=(const optional<T> &lhs,
const optional<U> &rhs) {
return lhs.has_value != rhs.has_value() && (!lhs.has_value() || *lhs != *rhs);
}
template <class T, class U>
inline constexpr bool operator<(const optional<T> &lhs,
const optional<U> &rhs) {
return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
}
template <class T, class U>
inline constexpr bool operator>(const optional<T> &lhs,
const optional<U> &rhs) {
return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
}
template <class T, class U>
inline constexpr bool operator<=(const optional<T> &lhs,
const optional<U> &rhs) {
return !lhs.has_value() || (rhs.has_value() || *lhs <= *rhs);
}
template <class T, class U>
inline constexpr bool operator>=(const optional<T> &lhs,
const optional<U> &rhs) {
return !rhs.has_value() || (lhs.has_value() || *lhs <= *rhs);
}
template <class T>
inline constexpr bool operator==(const optional<T> &lhs,
std::nullopt_t) noexcept {
return !lhs.has_value();
}
template <class T>
inline constexpr bool operator==(std::nullopt_t,
const optional<T> &rhs) noexcept {
return !rhs.has_value();
}
template <class T>
inline constexpr bool operator!=(const optional<T> &lhs,
std::nullopt_t) noexcept {
return lhs.has_value();
}
template <class T>
inline constexpr bool operator!=(std::nullopt_t,
const optional<T> &rhs) noexcept {
return rhs.has_value();
}
template <class T>
inline constexpr bool operator<(const optional<T> &, std::nullopt_t) noexcept {
return false;
}
template <class T>
inline constexpr bool operator<(std::nullopt_t,
const optional<T> &rhs) noexcept {
return rhs.has_value();
}
template <class T>
inline constexpr bool operator<=(const optional<T> &lhs,
std::nullopt_t) noexcept {
return !lhs.has_value();
}
template <class T>
inline constexpr bool operator<=(std::nullopt_t, const optional<T> &) noexcept {
return true;
}
template <class T>
inline constexpr bool operator>(const optional<T> &lhs,
std::nullopt_t) noexcept {
return lhs.has_value();
}
template <class T>
inline constexpr bool operator>(std::nullopt_t, const optional<T> &) noexcept {
return false;
}
template <class T>
inline constexpr bool operator>=(const optional<T> &, std::nullopt_t) noexcept {
return true;
}
template <class T>
inline constexpr bool operator>=(std::nullopt_t,
const optional<T> &rhs) noexcept {
return !rhs.has_value();
}
template <class T, class U>
inline constexpr bool operator==(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs == rhs : false;
}
template <class T, class U>
inline constexpr bool operator==(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs == *rhs : false;
}
template <class T, class U>
inline constexpr bool operator!=(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs != rhs : true;
}
template <class T, class U>
inline constexpr bool operator!=(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs != *rhs : true;
}
template <class T, class U>
inline constexpr bool operator<(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs < rhs : true;
}
template <class T, class U>
inline constexpr bool operator<(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs < *rhs : false;
}
template <class T, class U>
inline constexpr bool operator<=(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs <= rhs : true;
}
template <class T, class U>
inline constexpr bool operator<=(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs <= *rhs : false;
}
template <class T, class U>
inline constexpr bool operator>(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs > rhs : false;
}
template <class T, class U>
inline constexpr bool operator>(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs > *rhs : true;
}
template <class T, class U>
inline constexpr bool operator>=(const optional<T> &lhs, const U &rhs) {
return lhs.has_value() ? *lhs >= rhs : false;
}
template <class T, class U>
inline constexpr bool operator>=(const U &lhs, const optional<T> &rhs) {
return rhs.has_value() ? lhs >= *rhs : true;
}
template <class T>
constexpr optional<std::decay_t<T>> make_optional(T &&value) {
return optional<std::decay_t<T>>(std::forward<T>(value));
}
} }
namespace rust {
namespace enm {
template <typename T, typename E> struct expected;
namespace detail {
template <typename T> struct is_rust_expected_impl : std::false_type {};
template <typename T, typename E>
struct is_rust_expected_impl<expected<T, E>> : std::true_type {};
template <typename T>
using is_rust_expected = is_rust_expected_impl<std::decay_t<T>>;
}
template <typename E> struct bad_rust_expected_access : std::runtime_error {
bad_rust_expected_access(const E &err)
: std::runtime_error{"Expected is the unexpected value"}, error(err) {}
E error;
};
template <typename T, typename E> struct expected : public variant<T, E> {
using base = variant<T, E>;
expected() = delete;
expected(const expected &) = default;
expected(expected &&) = delete;
using base::base;
using base::operator=;
using Ok = T;
using Err = E;
constexpr explicit operator bool() { return this->m_Index == 0; }
constexpr bool has_value() const noexcept { return this->m_Index == 0; }
constexpr T &value() & {
if (has_value()) {
return *reinterpret_cast<T *>(this->m_Buff);
} else {
throw bad_rust_expected_access(*reinterpret_cast<E *>(this->m_Buff));
}
}
constexpr const T &value() const & {
if (has_value()) {
return *reinterpret_cast<const T *>(this->m_Buff);
} else {
throw bad_rust_expected_access(*reinterpret_cast<E *>(this->m_Buff));
}
}
constexpr E &error() & { return *reinterpret_cast<E *>(this->m_Buff); }
constexpr const E &error() const & {
return *reinterpret_cast<const E *>(this->m_Buff);
}
constexpr const T *operator->() const noexcept {
reinterpret_cast<const T *>(this->m_Buff);
}
constexpr T *operator->() noexcept { reinterpret_cast<T *>(this->m_Buff); }
constexpr const T &operator*() const & noexcept {
*reinterpret_cast<const T *>(this->m_Buff);
}
constexpr T &operator*() & noexcept { *reinterpret_cast<T *>(this->m_Buff); }
template <class U = std::remove_cv_t<T>>
constexpr T value_or(U &&default_value) const & {
return has_value() ? *reinterpret_cast<const T *>(this->m_Buff)
: static_cast<T>(std::forward<U>(default_value));
}
template <class G = E> constexpr E error_or(G &&default_value) const & {
return has_value() ? std::forward<G>(default_value) : error();
}
template <class F> constexpr auto and_then(F &&f) & {
using result = std::invoke_result_t<F, T &>;
static_assert(detail::is_rust_expected<result>::value,
"F must return a rust::variant::expected");
return (has_value()) ? std::invoke(std::forward<F>(f), value())
: result(error());
}
template <class F> constexpr auto and_then(F &&f) const & {
using result = std::invoke_result_t<F, const T &>;
static_assert(detail::is_rust_expected<result>::value,
"F must return a rust::variant::expected");
return (has_value()) ? std::invoke(std::forward<F>(f), value())
: result(error());
}
template <class F> constexpr auto transform(F &&f) & {
using result = expected<std::remove_cv_t<std::invoke_result_t<F, T &>>, E>;
return has_value() ? std::invoke(std::forward<F>(f), value())
: result(error());
}
template <class F> constexpr auto transform(F &&f) const & {
using result =
expected<std::remove_cv_t<std::invoke_result_t<F, const T &>>, E>;
return has_value() ? std::invoke(std::forward<F>(f), value())
: result(error());
}
template <class F> constexpr auto &or_else(F &&f) & {
using result =
expected<std::remove_cv_t<std::invoke_result_t<F, decltype(error())>>,
E>;
return has_value() ? result(*this) : std::invoke(std::forward<F>(f), error());
}
template <class F> constexpr const auto &or_else(F &&f) const & {
using result =
expected<std::remove_cv_t<std::invoke_result_t<F, decltype(error())>>,
E>;
return has_value() ? result(*this) : std::invoke(std::forward<F>(f), error());
}
template <class F> constexpr auto transform_error(F &&f) & {
using result = expected<std::remove_cv_t<std::invoke_result_t<F, T &>>, E>;
return has_value() ? result(*this)
: std::invoke(std::forward<F>(f), error());
}
template <class F> constexpr auto transform_error(F &&f) const & {
using result =
expected<std::remove_cv_t<std::invoke_result_t<F, const T &>>, E>;
return has_value() ? result(*this)
: std::invoke(std::forward<F>(f), error());
}
using IsRelocatable = ::std::true_type;
};
template <typename E> struct expected<void, E> : public variant<monostate, E> {
using base = variant<monostate, E>;
expected() : base(monostate{}) {};
expected(const expected &) = default;
expected(expected &&) = delete;
using base::base;
using base::operator=;
using Ok = monostate;
using Err = E;
constexpr explicit operator bool() { return this->m_Index == 0; }
constexpr bool has_value() const noexcept { return this->m_Index == 0; }
constexpr void value() & {
if (has_value()) {
return;
} else {
throw bad_rust_expected_access(*reinterpret_cast<E *>(this->m_Buff));
}
}
constexpr E &error() & { return *reinterpret_cast<E *>(this->m_Buff); }
constexpr const E &error() const & {
return *reinterpret_cast<const E *>(this->m_Buff);
}
constexpr void operator*() const noexcept {}
template <class G = E> constexpr E error_or(G &&default_value) const & {
return has_value() ? std::forward<G>(default_value) : error();
}
template <class F> constexpr auto and_then(F &&f) & {
using result = std::invoke_result_t<F>;
static_assert(detail::is_rust_expected<result>::value,
"F must return a rust::variant::expected");
return (has_value()) ? std::invoke(std::forward<F>(f)) : result(error());
}
template <class F> constexpr auto and_then(F &&f) const & {
using result = std::invoke_result_t<F>;
static_assert(detail::is_rust_expected<result>::value,
"F must return a rust::variant::expected");
return (has_value()) ? std::invoke(std::forward<F>(f)) : result(error());
}
template <class F> constexpr auto transform(F &&f) & {
using result = expected<std::remove_cv_t<std::invoke_result_t<F>>, E>;
return has_value() ? std::invoke(std::forward<F>(f)) : result(error());
}
template <class F> constexpr auto transform(F &&f) const & {
using result = expected<std::remove_cv_t<std::invoke_result_t<F>>, E>;
return has_value() ? std::invoke(std::forward<F>(f)) : result(error());
}
template <class F> constexpr auto &or_else(F &&f) & {
using result =
expected<std::remove_cv_t<std::invoke_result_t<F, decltype(error())>>,
E>;
return has_value() ? result(*this)
: std::invoke(std::forward<F>(f), error());
}
template <class F> constexpr const auto &or_else(F &&f) const & {
using result =
expected<std::remove_cv_t<std::invoke_result_t<F, decltype(error())>>,
E>;
return has_value() ? result(*this)
: std::invoke(std::forward<F>(f), error());
}
template <class F> constexpr auto transform_error(F &&f) & {
using result =
expected<std::remove_cv_t<std::invoke_result_t<F, decltype(error())>>,
E>;
return has_value() ? result(*this)
: std::invoke(std::forward<F>(f), error());
}
template <class F> constexpr auto transform_error(F &&f) const & {
using result =
expected<std::remove_cv_t<std::invoke_result_t<F, decltype(error())>>,
E>;
return has_value() ? result(*this)
: std::invoke(std::forward<F>(f), error());
}
using IsRelocatable = ::std::true_type;
};
} }
#endif