//! Extension traits, global functions + macros. #![allow(unused)] use super::*; use std::convert::Infallible; pub use std::{ convert::{ TryFrom, TryInto, }, borrow::*, }; /// Add forwarding borrow + deref (+ optional `into_inner()`) impls for a type. /// /// # Usage /// For a mutable forwarding newtype: /// ``` /// # use crate::forward_newtype; /// # use core::borrow::*; /// /// /// A mutable buffer newtype over an array. /// struct Buffer([u8; 16]); /// forward_newtype!(mut Buffer => [u8], 0); // Generates `Borrow<[u8]>`, `BorrowMut<[u8]>`, `Deref`, and `DerefMut` impls for `Buffer` that return `<&[mut] self.>0` (as specified by `0`.) /// ``` /// /// For an immutable forwarding newtype: /// ``` /// # use crate::forward_newtype; /// # use core::borrow::*; /// /// /// A mutable buffer newtype over an array. /// struct Data([u8; 16]); /// forward_newtype!(ref Buffer => [u8], 0); // Generates `Borrow<[u8]>` and `Deref` impls for `Buffer` that return `<& self.>0` (as specified by `0`.) Immutable access only is specified by `ref`. /// ``` /// /// ## Consuming into inner /// To generate an `into_inner(self) -> T` inherent impl for the type, the syntax `forward_newtype!(move [const] Type => Inner, accessor)` can be used. /// If `const` is passed, then the `into_inner()` function will be a `const fn`, if not, then it won't be. /// /// To combine with ref-forwarding accessors, the syntax `forward_newtype!(move [const] {ref/mut} Type => Inner, accessor)` can be used to generate them all; the `Borrow`, `BorrowMut`, `Deref`, `DerefMut` and `pub [const] fn into_inner()`. /// This is the most likely to be useful. /// /// If you need a seperate `into_inner()` impl, you can either not use the `move` declarator, or use the `ref`/`mut` accessor generator in a different statement than the `move` one: /// ``` /// # use crate::forward_newtype; /// # use core::borrow::*; /// /// /// A mutable buffer newtype over an array. /// struct Buffer([u8; 16]); /// forward_newtype!(mut Buffer => [u8], 0); // Generate a mutable & immutable forwarding ref to a slice of bytes. /// forward_newtype!(move const Buffer => [u8; 16], 0); // Generate a seperately typed `into_inner()` that returns the sized array. /// ``` macro_rules! forward_newtype { (ref $type:ty => $inner:ty, $($expr:tt)+) => { impl Borrow<$inner> for $type { #[inline] fn borrow(&self) -> &$inner { &self.$($expr)+ } } impl ::std::ops::Deref for $type { type Target = $inner; #[inline] fn deref(&self) -> &Self::Target { self.borrow() } } }; (mut $type:ty => $inner:ty, $($expr:tt)+) => { forward_newtype!(ref $type => $inner, $($expr)+); impl BorrowMut<$inner> for $type { #[inline] fn borrow_mut(&mut self) -> &mut $inner { &mut self.$($expr)+ } } impl ::std::ops::DerefMut for $type { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.borrow_mut() } } }; (move const $type:ty => $inner:ty, $($expr:tt)+) => { impl $type { /// Consume into the inner value. pub const fn into_inner(self) -> $inner { self.$($expr)+ } } }; (move $type:ty => $inner:ty, $($expr:tt)+) => { impl $type { /// Consume into the inner value. pub fn into_inner(self) -> $inner { self.$($expr)+ } } }; (move const ref $type:ty => $inner:ty, $($expr:tt)+) => { forward_newtype!(move const $type => $inner, $($expr)+); forward_newtype!(ref $type => $inner, $($expr)+); }; (move ref $type:ty => $inner:ty, $($expr:tt)+) => { forward_newtype!(move $type => $inner, $($expr)+); forward_newtype!(ref $type => $inner, $($expr)+); }; (move const mut $type:ty => $inner:ty, $($expr:tt)+) => { forward_newtype!(move const $type => $inner, $($expr)+); forward_newtype!(mut $type => $inner, $($expr)+); }; (move mut $type:ty => $inner:ty, $($expr:tt)+) => { forward_newtype!(move $type => $inner, $($expr)+); forward_newtype!(mut $type => $inner, $($expr)+); }; } /// The default bottom type. /// /// To use the `unwrap_infallible()`-like interface, functions that return `-> !` should be changed to `-> Never`. /// When `unstable` is enabled, this is an alias to `!` and `-> !` is not special cased. /// /// # As return argument /// When feature `unstable` is enabled, `into_unreachable()` may not be required to ensure propogation to `!` from a function returning `-> Never`. #[cfg(feature="unstable")] pub type Never = !; /// The default bottom type. /// /// To use the `unwrap_infallible()`-like interface, functions special cased to `-> !` should be changed to `-> Never`. /// /// # As return argument /// When feature `unstable` is not enabled, `into_unreachable()` may be required to be used when dealing with return bottom types other than the special case `-> !`. /// This is a current limitation of the type system. #[cfg(not(feature="unstable"))] pub type Never = Infallible; /// Contractually ensures this type cannot exist (i.e. it is a bottom type.) /// /// # Safety /// Instances of the impl type **cannot exist**. /// They must be bottom types (i.e. empty enums, types contatining an `Infallible` / `!` object, etc.) /// /// # Auto-impl /// This trait is not intended to be implemented on any user-defined type other than empty enums. /// /// By default it is implemented for the following types: /// - `core::convert::Infallible` /// - `!` (**feature**: `unstable`) /// - `Box` *where* `T: ?Sized + Unreachable` pub unsafe trait Unreachable { /// Force control flow to terminate type checking here. /// /// # Note /// This function will never be executed, it is used to terminate the value's existence in the type system, by converting it from any `Unreachable` type into the bottom return type `!`. /// If this function ever **can** be called at all, it is undefined behaviour. #[inline] #[cold] fn into_unreachable(self) -> ! where Self: Sized { if cfg!(debug_assertions) { unreachable!("Unreachable conversion from {}!", std::any::type_name::()) } else { // SAFETY: Contractually enforced by the trait impl itself. unsafe { std::hint::unreachable_unchecked() } } } } unsafe impl Unreachable for Infallible { #[inline(always)] #[cold] fn into_unreachable(self) -> ! { match self {} } } #[cfg(feature="unstable")] unsafe impl Unreachable for ! { #[inline(always)] #[cold] fn into_unreachable(self) -> ! { match self {} } } unsafe impl Unreachable for Box {} pub trait UnwrapPanicExt { /// Unwrap the result `Ok` value or panic as described by the non-returning function `F`, with the `Unreachable` bottom type `N`. /// This will usually be an `-> !` function, (or an `-> Never` function using the `Unreachable` interface.) /// /// # Panic usage /// `func` must not return. It should panic, resume a panic, or exit the thread/program, trap, or terminate in an infinite loop. /// /// It does not *have* to call `panic!()` if it terminates in another way that is not a panic, however. fn unwrap_or_panic N>(self, func: F) -> T; /// Unwrap the result `Ok` value or panic as described by the non-returning function `func` with the default bottom type `Never`. #[inline(always)] fn unwrap_or_panic_unreachable Never>(self, func: F) -> T where Self: Sized { self.unwrap_or_panic::(func) } } pub trait UnwrapInfallibleExt { /// Unwrapping is infallible and therefore safe to do so without checking. fn unwrap_infallible(self) -> T; } pub trait UnwrapPanicResumeExt { /// Unwrap or resume a previous unwind, with the unwind payload in the `Err` variant. fn unwrap_or_resume(self) -> T; } impl UnwrapPanicExt for Result { #[inline] fn unwrap_or_panic N>(self, func: F) -> T { #[inline(never)] #[cold] fn _do_panic Nn>(error: Ee, func: Ff) -> ! { func(error).into_unreachable() } match self { Ok(v) => v, Err(e) => _do_panic(e, func) } } } impl UnwrapInfallibleExt for Result { #[inline] fn unwrap_infallible(self) -> T { match self { Ok(v) => v, Err(e) => if cfg!(debug_assertions) { e.into_unreachable() } else { // SAFETY: Contract bound of `E: Unreachable` ensures this path will never be taken. unsafe { std::hint::unreachable_unchecked() } } } } } /// The type of a caught unwind payload. pub type UnwindPayload = Box; #[cold] #[inline(never)] fn _resume_unwind>(e: E) -> ! { std::panic::resume_unwind(e.into()) } impl> UnwrapPanicResumeExt for Result { #[inline] fn unwrap_or_resume(self) -> T { match self { Ok(v) => v, Err(e) => _resume_unwind(e), } } }