realloc 0.1.0

A re-implementation of various ::alloc features
Documentation
pub(crate) const FAILURE_MESSAGE: &str = "failed to allocate";

/// A method for handling allocation failure.
///
/// All implementors, while not strictly required, are expected to be
/// zero-sized.
///
/// While you can create your own (likely through [`strategy!`]), it's
/// recommended to use one of [`Abort`], [`Panic`], [`Optional`], or
/// [`Fallible`].
pub trait Strategy {
    /// The type this strategy returns from fallible methods.
    type Result<T, E>;

    /// The "unit value" for this type.
    ///
    /// Used to store it in collections.
    const UNIT: Self;

    /// Transform a full `Result` into the desired output.
    ///
    /// This is the core of the trait; it's what actually performs the error
    /// handling this strategy prescribes.
    fn create<T, E>(value: Result<T, E>) -> Self::Result<T, E>;

    /// Transform an ok result of one type to an ok result of another.
    fn map<T, E, U, F>(value: Self::Result<T, E>, f: F) -> Self::Result<U, E>
    where
        F: FnOnce(T) -> U;

    /// Transform an error result of one type to an error result of another.
    fn map_err<T, E, V, F>(value: Self::Result<T, E>, f: F) -> Self::Result<T, V>
    where
        F: FnOnce(E) -> V;

    /// If `value` is an ok result, transform it through `f`, flattening the
    /// results.
    fn and_then<T, E, U, F>(value: Self::Result<T, E>, f: F) -> Self::Result<U, E>
    where
        F: FnOnce(T) -> Self::Result<U, E>;

    /// Create an ok result from a value.
    fn ok<T, E>(value: T) -> Self::Result<T, E> {
        Self::create(Ok(value))
    }

    /// Create an error result from an error.
    fn err<T, E>(error: E) -> Self::Result<T, E> {
        Self::create(Err(error))
    }

    /// If `value` is an ok result, run `f` on it, returning `value` unchanged.
    fn inspect<T, E, F>(value: Self::Result<T, E>, f: F) -> Self::Result<T, E>
    where
        F: FnOnce(&T),
    {
        Self::and_then(value, |value| {
            f(&value);
            Self::ok(value)
        })
    }
}

/// Create a custom [`Strategy`].
///
/// # Examples
///
/// ```
/// # struct Logger;
/// # impl Logger { const fn new() -> Self { Self } fn log<E>(&self, _: &str, _: &E) {} }
///
/// strategy! {
///     // The name and visibility of the strategy, plus whatever docs/attrs you
///     // want to put on it.
///     //
///     // If it's not a unit struct, it has to have a `const` default value.
///     #[derive(Debug, Copy)]
///     pub struct Log(Logger) = Log(Logger::new());
///
///     // The result of applying the transformation. In this case, we're just
///     // logging, so we don't want to remove the errors.
///     type Result<T, E> = Result<T, E>;
///
///     // How to transform an `Ok`/`Err` value to an ok/error result of our
///     // `Result` type. In our case, we don't want to change anything, just
///     // log any errors.
///     Ok(val) => Ok(val);
///     Err(err) => {
///         self.0.log("encountered an error", &err);
///         Err(err)
///     };
///
///     // How to apply various transformations to our result type. Since this
///     // is just a plain `Result`, we can delegate to its implementations.
///     fn map(value, f) => value.map(f);
///     fn map_err(value, f) => value.map_err(f);
///     fn and_then(value, f) => value.and_then(f);
/// }
/// ```
#[macro_export]
macro_rules! strategy {
    (
        $(#[$attr:meta])*
        $vis:vis struct $name:ident
            $( ($($tuple_fields:tt)*) = $tuple_unit:expr; )?
            $( {$($struct_fields:tt)*} = $struct_unit:expr; )?
            $(;)?

        type Result<$t:ident, $e:ident> = $output:ty;

        Ok($ok_val:pat) => $ok:expr;
        Err($err_val:pat) => $err:expr;

        fn map($map_val:pat, $map_f:pat) => $map:expr;
        fn map_err($map_err_val:pat, $map_err_f:pat) => $map_err:expr;
        fn and_then($and_then_val:pat, $and_then_f:pat) => $and_then:expr;
    ) => {
        $(#[$attr])*
        $vis struct $name
            $( ($($tuple_fields)*) )?
            // in order to make the trailing semicolon acceptable, we must
            // insert an item here that will consume it without causing
            // potential conflicts
            $( {$($struct_fields)*} const _: () = () )?
        ;

        impl $crate::Strategy for $name {
            type Result<$t, $e> = $output;

            const UNIT: Self = $crate::__if_else!([
                $($tuple_unit)?
            ] || [
                $($struct_unit)?
            ] else [
                Self
            ] else "must either be a tuple struct or regular struct, not both"
            );

            fn create<$t, $e>(
                __strategy_impl_value: ::core::result::Result<$t, $e>
            ) -> <Self as $crate::Strategy>::Result<$t, $e> {
                match __strategy_impl_value {
                    ::core::result::Result::Ok($ok_val) => $ok,
                    ::core::result::Result::Err($err_val) => $err,
                }
            }

            #[allow(non_camel_case_types)]
            fn map<$t, $e, __STRATEGY_IMPL_U, __STRATEGY_IMPL_F>(
                $map_val: <Self as $crate::Strategy>::Result<$t, $e>,
                $map_f: __STRATEGY_IMPL_F,
            ) -> <Self as $crate::Strategy>::Result<__STRATEGY_IMPL_U, $e>
            where
                __STRATEGY_IMPL_F: ::core::ops::FnOnce($t) -> __STRATEGY_IMPL_U,
            {
                $map
            }

            #[allow(non_camel_case_types)]
            fn map_err<$t, $e, __STRATEGY_IMPL_V, __STRATEGY_IMPL_F>(
                $map_err_val: <Self as $crate::Strategy>::Result<$t, $e>,
                $map_err_f: __STRATEGY_IMPL_F,
            ) -> <Self as $crate::Strategy>::Result<$t, __STRATEGY_IMPL_V>
            where
                __STRATEGY_IMPL_F: core::ops::FnOnce($e) -> __STRATEGY_IMPL_V,
            {
                $map_err
            }

            #[allow(non_camel_case_types)]
            fn and_then<$t, $e, __STRATEGY_IMPL_U, __STRATEGY_IMPL_F>(
                $and_then_val: <Self as $crate::Strategy>::Result<$t, $e>,
                $and_then_f: __STRATEGY_IMPL_F,
            ) -> <Self as $crate::Strategy>::Result<__STRATEGY_IMPL_U, $e>
            where
                __STRATEGY_IMPL_F: core::ops::FnOnce(T)
                    -> <Self as $crate::Strategy>::Result<__STRATEGY_IMPL_U, $e>,
            {
                $and_then
            }
        }
    }
}

/// A "true" abort, without relying on `core::intrinsics::abort` or pulling in
/// the panic machinery of `unreachable!`.
fn abort() -> ! {
    // SAFETY:
    // - the assembly does not violate Rust's AM
    // - the assembly guarantees `unreachable_unchecked` will never be reached
    unsafe {
        core::arch::asm!("ud2");
        core::hint::unreachable_unchecked()
    }
}

strategy! {
    /// A [`Strategy`] prescribing that the program immediately abort on
    /// failure.
    ///
    /// See also [`Panic`].
    pub struct Abort;

    type Result<T, E> = T;

    Ok(v) => v;
    Err(_) => abort();

    fn map(v, f) => f(v);
    fn map_err(v, _) => v;
    fn and_then(v, f) => f(v);
}

strategy! {
    /// A [`Strategy`] prescribing that the program panic on failure.
    ///
    /// See also [`Abort`] and [`Fallible`].
    pub struct Panic;

    type Result<T, E> = T;

    Ok(v) => v;
    Err(_) => panic!("{}", FAILURE_MESSAGE);

    fn map(v, f) => f(v);
    fn map_err(v, _) => v;
    fn and_then(v, f) => f(v);
}

strategy! {
    /// A [`Strategy`] prescribing that errors be discarded, and `Option`s
    /// returned instead.
    ///
    /// See also [`Fallible`] and [`Panic`].
    pub struct Optional;

    type Result<T, E> = Option<T>;

    Ok(v) => Some(v);
    Err(_) => None;

    fn map(v, f) => v.map(f);
    fn map_err(v, _) => v;
    fn and_then(v, f) => v.and_then(f);
}

strategy! {
    /// A [`Strategy`] prescribing that all fallible methods return `Result`s.
    ///
    /// See also [`Optional`] and [`Panic`].
    pub struct Fallible;

    type Result<T, E> = Result<T, E>;

    Ok(v) => Ok(v);
    Err(e) => Err(e);

    fn map(v, f) => v.map(f);
    fn map_err(v, f) => v.map_err(f);
    fn and_then(v, f) => v.and_then(f);
}

#[macro_export]
#[doc(hidden)]
macro_rules! __if_else {
    ([] || [] else [$($t:tt)*] else $err:literal) => {$($t)*};
    ([] || [$($t:tt)*] else [$($_:tt)*] else $err:literal) => {$($t)*};
    ([$($t:tt)*] || [] else [$($_:tt)*] else $err:literal) => {$($t)*};
    ([$($_:tt)*] || [$($__:tt)*] else [$($___:tt)*] else $err:literal) => {
        compile_error!($err);
    };

    ([] else [$($t:tt)*]) => {$($t)*};
    ([$($t:tt)*] else [$($_:tt)*]) => {$($t)*};
}