1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
//! Zero-cost error handling for generic traits.
//!
//! # Rationale
//!
//! Assume we want to build a crate that defines a generic trait,
//! meant to be implemented by others.
//! Some implementations of that trait may always succeed,
//! others may sometimes fail.
//! The methods of of the generic trait should therefore return `Result<_,_>`,
//! but do not want that to create an overhead for infallible implementations
//! (per the *zero-cose abstraction* motto).
//!
//! See `README.md` for a more detailed explaination.

/// Sets up coercible_errors for a previously defined error type.
///
/// It re-exports the types [`Never`] and [`OkResult`],
/// and defines three new traits and types `CoercibleWith`,
/// `CoercedError` and `CoercedResult`.
///
/// [`Never`]: enum.Never.html
/// [`OkResult`]: type.OkResult.html
#[macro_export]
macro_rules! coercible_errors {
    () => {
        coercible_errors!(Error);
    };
    ($error: ty) => {
        coercible_errors!($error, CoercibleWith, CoercedError, CoercedResult);
    };
    ($error: ty, $coercible_with: ident, $coerced_error: ident, $coerced_result: ident) => {
        pub use $crate::{Never, OkResult};

        // This conversion can never happen (since Never can have no value),
        // but it is required for allowing $error and Never to coerce with each other.
        impl From<Never> for $error {
            fn from(_: Never) -> $error {
                unreachable!()
            }
        }

        /// A trait used to determine how to best coerce two error types.
        ///
        /// In practice, the only two error types that it handles are `$error` or `Never`.
        pub trait $coercible_with<E>:
            Sized + std::marker::Send + std::error::Error + 'static
        {
            type Into: std::marker::Send
                + std::error::Error
                + 'static
                + From<Self>
                + From<E>
                + $coercible_with<$error>;
        }
        impl $coercible_with<$error> for $error {
            type Into = $error;
        }
        impl $coercible_with<Never> for $error {
            type Into = $error;
        }
        impl $coercible_with<$error> for Never {
            type Into = $error;
        }
        impl $coercible_with<Never> for Never {
            type Into = Never;
        }

        /// A shortcut for building the coerced error type,
        /// given two error types,
        /// which must both be either `$error` or `Never`.
        pub type $coerced_error<E1, E2> = <E1 as $coercible_with<E2>>::Into;

        /// A shortcut for building the coerced result type,
        /// given one value type and two error types,
        /// which must both be either `$error` or `Never`.
        pub type $coerced_result<T, E1, E2> = std::result::Result<T, $coerced_error<E1, E2>>;
    };
}

/// An "error" type that can never happen.
///
/// NB: once the [`never`] types reaches *stable*,
/// this type will be an alias for the standard type.
///
/// [`never`]: https://doc.rust-lang.org/std/primitive.never.html
///
#[derive(Clone, Debug)]
pub enum Never {}
impl ::std::fmt::Display for Never {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "Never")
    }
}
impl std::error::Error for Never {}

/// Type alias for a result that will Never fail.
pub type OkResult<T> = std::result::Result<T, Never>;

#[cfg(feature = "example_generated")]
pub mod example_generated;

#[cfg(test)]
#[macro_use]
extern crate error_chain;

#[cfg(test)]
mod test;