You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
305 lines
9.5 KiB
305 lines
9.5 KiB
//! 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<Target=[u8]>`, 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<Target=[u8]>` 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<T>` *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::<Self>())
|
|
} 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<T: ?Sized + Unreachable> Unreachable for Box<T> {}
|
|
|
|
pub trait UnwrapPanicExt<T, E> {
|
|
/// 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: Unreachable, F: FnOnce(E) -> 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<F: FnOnce(E) -> Never>(self, func: F) -> T
|
|
where Self: Sized {
|
|
self.unwrap_or_panic::<Never, _>(func)
|
|
}
|
|
}
|
|
|
|
pub trait UnwrapInfallibleExt<T> {
|
|
/// Unwrapping is infallible and therefore safe to do so without checking.
|
|
fn unwrap_infallible(self) -> T;
|
|
}
|
|
|
|
pub trait UnwrapPanicResumeExt<T> {
|
|
/// Unwrap or resume a previous unwind, with the unwind payload in the `Err` variant.
|
|
fn unwrap_or_resume(self) -> T;
|
|
}
|
|
|
|
impl<T, E> UnwrapPanicExt<T, E> for Result<T, E>
|
|
{
|
|
#[inline]
|
|
fn unwrap_or_panic<N: Unreachable, F: FnOnce(E) -> N>(self, func: F) -> T {
|
|
#[inline(never)]
|
|
#[cold]
|
|
fn _do_panic<Nn: Unreachable, Ee, Ff: FnOnce(Ee) -> Nn>(error: Ee, func: Ff) -> !
|
|
{
|
|
func(error).into_unreachable()
|
|
}
|
|
|
|
match self {
|
|
Ok(v) => v,
|
|
Err(e) => _do_panic(e, func)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T, E: Unreachable> UnwrapInfallibleExt<T> for Result<T, E>
|
|
{
|
|
#[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<dyn std::any::Any + Send>;
|
|
|
|
#[cold]
|
|
#[inline(never)]
|
|
fn _resume_unwind<E: Into<UnwindPayload>>(e: E) -> !
|
|
{
|
|
std::panic::resume_unwind(e.into())
|
|
}
|
|
|
|
impl<T, E: Into<UnwindPayload>> UnwrapPanicResumeExt<T> for Result<T, E>
|
|
{
|
|
#[inline]
|
|
fn unwrap_or_resume(self) -> T {
|
|
match self {
|
|
Ok(v) => v,
|
|
Err(e) => _resume_unwind(e),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait ArcExt
|
|
{
|
|
/// If the strong-count == 1 and the weak-count is 0.
|
|
fn is_fully_unique(self: &std::sync::Arc<Self>) -> bool;
|
|
/// If the strong-count == 1.
|
|
///
|
|
/// If there are alive `Weak`s pointing to this object, those are not considered.
|
|
fn is_currently_unique(self: &std::sync::Arc<Self>) -> bool;
|
|
}
|
|
|
|
impl<T: ?Sized> ArcExt for T
|
|
{
|
|
#[inline]
|
|
fn is_fully_unique(self: &std::sync::Arc<Self>) -> bool {
|
|
std::sync::Arc::strong_count(&self) == 1 &&
|
|
std::sync::Arc::weak_count(&self) == 0
|
|
}
|
|
#[inline]
|
|
fn is_currently_unique(self: &std::sync::Arc<Self>) -> bool {
|
|
std::sync::Arc::strong_count(&self) == 1
|
|
}
|
|
}
|