#![no_std]
#![deny(
bad_style,
dead_code,
improper_ctypes,
non_shorthand_field_patterns,
no_mangle_generic_items,
overflowing_literals,
path_statements,
patterns_in_fns_without_body,
private_in_public,
unconditional_recursion,
unused,
unused_allocation,
unused_comparisons,
unused_parens,
while_true,
missing_debug_implementations,
missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results
)]
#![forbid(unsafe_code)]
#![feature(try_trait_v2)]
#![feature(const_trait_impl)]
#![feature(const_mut_refs)]
#![feature(const_replace)]
use core::convert::Infallible;
use core::fmt::Debug;
use core::marker::Destruct;
use core::mem;
use core::ops::{ControlFlow, Deref, DerefMut, FromResidual, Try};
#[must_use]
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Fallible<E> {
Success,
Fail(E),
}
use Fallible::{Fail, Success};
impl<E> Fallible<E> {
#[inline]
pub const fn as_deref(&self) -> Fallible<&<E as Deref>::Target>
where
E: ~const Deref,
{
match self {
Success => Success,
Fail(e) => Fail(e.deref()),
}
}
#[inline]
pub const fn as_deref_mut(&mut self) -> Fallible<&mut <E as Deref>::Target>
where
E: ~const DerefMut,
{
match self {
Success => Success,
Fail(e) => Fail(e.deref_mut()),
}
}
#[inline]
pub const fn as_mut(&mut self) -> Fallible<&mut E> {
match self {
Success => Success,
Fail(ref mut e) => Fail(e),
}
}
#[inline]
pub const fn as_ref(&self) -> Fallible<&E> {
match self {
Success => Success,
Fail(ref e) => Fail(e),
}
}
#[inline]
pub const fn is_successful(&self) -> bool {
matches!(self, Success)
}
#[inline]
pub const fn is_fail(&self) -> bool {
matches!(self, Fail(_))
}
#[inline]
pub fn unwrap_fail(self) -> E {
match self {
Success => panic!("called `Fallible::unwrap_fail()` on a `Fallible::Success` value"),
Fail(err) => err,
}
}
#[inline]
pub const fn contains<U: ~const PartialEq<E>>(&self, x: &U) -> bool {
match self {
Success => false,
Fail(e) => x.eq(e),
}
}
#[inline]
pub const fn map<F, U>(self, op: F) -> Fallible<U>
where
F: ~const FnOnce(E) -> U,
F: ~const Destruct,
E: ~const Destruct,
{
match self {
Success => Success,
Fail(e) => Fail(op(e)),
}
}
#[inline]
pub const fn result(self) -> Result<(), E>
where
E: ~const Destruct,
{
match self {
Success => Ok(()),
Fail(e) => Err(e),
}
}
#[inline]
pub const fn err(&self) -> Option<&E> {
match self {
Success => None,
Fail(err) => Some(err),
}
}
#[inline]
pub const fn err_or<T>(self, value: T) -> Result<T, E>
where
E: ~const Destruct,
T: ~const Destruct,
{
match self {
Success => Ok(value),
Fail(e) => Err(e),
}
}
#[inline]
pub const fn take(&mut self) -> Option<E>
where
E: ~const Destruct,
{
match mem::replace(self, Success) {
Success => None,
Fail(e) => Some(e),
}
}
}
impl<E> Fallible<&E>
where
E: ~const Clone,
{
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
pub const fn cloned(self) -> Fallible<E> {
match self {
Success => Success,
Fail(e) => Fail(e.clone()),
}
}
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
pub const fn copied(self) -> Fallible<E>
where
E: Copy,
{
match self {
Success => Success,
Fail(&e) => Fail(e),
}
}
}
impl<E> Fallible<&mut E>
where
E: ~const Clone,
{
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
pub const fn cloned(self) -> Fallible<E> {
match self {
Success => Success,
Fail(e) => Fail(e.clone()),
}
}
#[inline]
#[must_use = "`self` will be dropped if the result is not used"]
pub const fn copied(self) -> Fallible<E>
where
E: Copy,
{
match self {
Success => Success,
Fail(&mut e) => Fail(e),
}
}
}
impl<E> Fallible<E>
where
E: Debug,
{
#[inline]
pub fn unwrap(self) {
match self {
Success => (),
Fail(e) => {
panic!("called `Fallible::unwrap()` on a `Fallible::Fail` value: {e:?}")
}
}
}
}
impl<E> Fallible<Fallible<E>> {
#[inline]
pub const fn flatten(self) -> Fallible<E>
where
E: ~const Destruct,
{
match self {
Success => Success,
Fail(inner) => inner,
}
}
}
impl<E> const From<E> for Fallible<E> {
#[inline]
fn from(value: E) -> Self {
Fail(value)
}
}
impl<T, E> const From<Result<T, E>> for Fallible<E>
where
E: ~const Destruct,
T: ~const Destruct,
{
#[inline]
fn from(value: Result<T, E>) -> Self {
match value {
Ok(_) => Success,
Err(e) => Fail(e),
}
}
}
impl<'a, E> const From<&'a Fallible<E>> for Fallible<&'a E> {
#[inline]
fn from(value: &'a Fallible<E>) -> Self {
value.as_ref()
}
}
impl<'a, E> const From<&'a mut Fallible<E>> for Fallible<&'a mut E> {
#[inline]
fn from(value: &'a mut Fallible<E>) -> Self {
value.as_mut()
}
}
impl<E> const Default for Fallible<E> {
#[inline]
fn default() -> Self {
Success
}
}
impl<E> const Clone for Fallible<E>
where
E: ~const Clone + ~const Destruct,
{
#[inline]
fn clone(&self) -> Self {
match self {
Fail(x) => Fail(x.clone()),
Success => Success,
}
}
#[inline]
fn clone_from(&mut self, source: &Self) {
match (self, source) {
(Fail(to), Fail(from)) => to.clone_from(from),
(to, from) => *to = from.clone(),
}
}
}
impl<E> Try for Fallible<E> {
type Output = ();
type Residual = Fallible<E>;
#[inline]
fn from_output(_: Self::Output) -> Self {
Success
}
#[inline]
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
match self {
Success => ControlFlow::Continue(()),
Fail(e) => ControlFlow::Break(Fail(e)),
}
}
}
impl<E, U> FromResidual<Fallible<U>> for Fallible<E>
where
E: From<U>,
{
#[inline]
fn from_residual(residual: Fallible<U>) -> Self {
match residual {
Success => Success,
Fail(u) => Fail(u.into()),
}
}
}
impl<T, E, U> FromResidual<Fallible<U>> for Result<T, E>
where
E: From<U>,
{
#[inline]
fn from_residual(residual: Fallible<U>) -> Self {
match residual {
Success => unreachable!(),
Fail(e) => Err(e.into()),
}
}
}
impl<E, U> FromResidual<Result<(), U>> for Fallible<E>
where
E: From<U>,
{
#[inline]
fn from_residual(residual: Result<(), U>) -> Self {
match residual {
Ok(()) => Success,
Err(e) => Fail(e.into()),
}
}
}
impl<E, U> FromResidual<Result<Infallible, U>> for Fallible<E>
where
E: From<U>,
{
#[inline]
fn from_residual(residual: Result<Infallible, U>) -> Self {
match residual {
Ok(_) => Success,
Err(e) => Fail(e.into()),
}
}
}
#[cfg(test)]
mod tests {
use crate::Fallible::{self, Fail, Success};
#[derive(Debug, PartialEq)]
struct InnerError(pub u8);
#[derive(Debug, PartialEq)]
enum OuterError {
Inner(InnerError),
}
impl From<InnerError> for OuterError {
fn from(value: InnerError) -> Self {
OuterError::Inner(value)
}
}
#[test]
fn fallible_residual_conversion() {
fn inner_error() -> Fallible<InnerError> {
Fail(InnerError(1))
}
fn outer_error() -> Fallible<OuterError> {
inner_error()?;
Success
}
assert_eq!(
outer_error().unwrap_fail(),
OuterError::Inner(InnerError(1))
);
}
#[test]
fn result_residual_conversion() {
fn inner_error() -> Fallible<InnerError> {
Fail(InnerError(1))
}
fn outer_error() -> Result<(), OuterError> {
inner_error()?;
Ok(())
}
assert_eq!(outer_error(), Err(OuterError::Inner(InnerError(1))));
}
}