unsize-1.1.0/.cargo_vcs_info.json0000644000000001120000000000000123410ustar { "git": { "sha1": "c46cebd76ad7f2c9dee268dc3339832e14e8e179" } } unsize-1.1.0/Cargo.toml0000644000000017420000000000000103510ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "unsize" version = "1.1.0" authors = ["Andreas Molzer "] description = "A stable alternative to CoerceUnsize" documentation = "https://docs.rs/unsize" readme = "Readme.md" categories = ["embedded", "no-std"] license = "MIT OR Apache-2.0 OR Zlib" repository = "https://github.com/HeroicKatora/static-alloc" [package.metadata.docs.rs] all-features = true [dependencies] [build-dependencies.autocfg] version = "1" unsize-1.1.0/Cargo.toml.orig000064400000000000000000000007170000000000000140110ustar 00000000000000[package] name = "unsize" version = "1.1.0" description = "A stable alternative to CoerceUnsize" authors = ["Andreas Molzer "] edition = "2018" license = "MIT OR Apache-2.0 OR Zlib" documentation = "https://docs.rs/unsize" repository = "https://github.com/HeroicKatora/static-alloc" readme = "Readme.md" categories = ["embedded", "no-std"] [dependencies] [build-dependencies] autocfg = "1" [package.metadata.docs.rs] all-features = true unsize-1.1.0/Changes.md000064400000000000000000000002250000000000000130060ustar 00000000000000# 1.1.0 * Implemented `CoerciblePtr` for raw pointers * Added `Coercion::to_future` and `Coercion::to_iterator` # 1.0.0 Initial base line release unsize-1.1.0/Readme.md000064400000000000000000000047240000000000000126430ustar 00000000000000# unsize [![Crates.io Status](https://img.shields.io/crates/v/unsize.svg)](https://crates.io/crates/static-alloc) [![Docs.rs Status](https://docs.rs/unsize/badge.svg)](https://docs.rs/unsize/) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/HeroicKatora/static-alloc/LICENSE) [![CI Status](https://api.cirrus-ci.com/github/HeroicKatora/static-alloc.svg)](https://cirrus-ci.com/github/HeroicKatora/static-alloc) ## Goals and Targets In embedded environments there are quite many use cases for custom smart pointers, for example to encapsulate ownership of objects on the stack or within a custom arena etc. One also wants to avoid unnecessary monomorphization that is for code size it is often desirable to use a dynamic trait object as indirection instead of instantiating a generic for a great number of type parameters. However, these can not be allocated (or often even constructed) directly. The standard library `Box` usually provides a sort of coercion: You can convert `Box<[T; N]>` to `Box<[T]>` for all array sizes or `Box` to `Box`. However, this does not work for custom smart pointers. The conversion is based on a nightly-only trait that one needs to explicitly opt-in to. This crate provides an alternative that works with `no_std` environments, for example to enable custom `Box` designs that avoid any dependency on a global allocator, or an arena based reference counted pointer, etc. For these use cases it is intended to replace the nightly unsizing mechanism with a stable and safe solution. ## Usage As a library developer you can implement the `CoerciblePtr` trait for your smart pointer type. This enables the use of all coercions with this pointer type. To provide custom unsize coercions to your own `?Sized` wrapper type you can provide a safe constructor for `Coercion`. As a user of a `unsize`-enabled pointer type, you should import the `CoerceUnsize` extension trait and the `Coercion` marker type. Then create an instance of `Coercion` to 'coerce' the pointee type of a smart pointer. The type defines a number of safe constructors and an `unsafe` escape hatch. The crate further defines a macro that provides safe coercion to other unsized types, if it compiles. ## Additional This project is licensed under Zlib OR Apache-2.0 OR MIT. You may alternatively choose the Unlicense instead in which case the copyright headers signify the parts dedicated to the public domain to the fullest possible extent instead. unsize-1.1.0/build.rs000064400000000000000000000001150000000000000125570ustar 00000000000000fn main() { let ac = autocfg::new(); ac.emit_rustc_version(1, 51); } unsize-1.1.0/src/coercion_impls.rs000064400000000000000000000027710000000000000152660ustar 00000000000000use super::*; use ::core::{ fmt, hash::{Hash, Hasher}, }; impl *const U> Clone for Coercion where F : Clone, { fn clone(&self) -> Self { Self { coerce: self.coerce.clone(), _phantom: PhantomData, } } } impl *const U> Copy for Coercion where F : Copy, {} impl *const U> PartialEq for Coercion where F : PartialEq, { fn eq(self: &Self, other: &Self) -> bool { match (self, other) { ( Self { coerce: coerce_left, _phantom: _, }, Self { coerce: coerce_right, _phantom: _, }, ) => coerce_left == coerce_right, } } } impl *const U> Eq for Coercion where F : Eq, {} impl *const U> fmt::Debug for Coercion where F : fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f .debug_struct("Coercion") .field("coerce", &self.coerce) .finish() } } impl *const U> Hash for Coercion where F : Hash, { fn hash(&self, state: &mut H) { (&self.coerce).hash(state) } } unsize-1.1.0/src/lib.rs000064400000000000000000000456420000000000000130330ustar 00000000000000//! This module encapsulates correct coercers and coercible pointers. //! //! The act of Coercion, a special kind of somewhat trivial pointer conversion, is not exposed as a //! _safe_ trait. There are two unsafe traits: The first captures which structs unsized to which //! dynamically sized types; which the second is applied to (wrappers around) pointers that can be //! coerced implicitly. //! //! We do not have the luxury of compiler builtin checks to enforce that a particular pointer //! conversion is sound, nor can we generate the tag of target fat pointer from thin air. Instead, //! we use a trick. Note that both of these safety issues occur in the context of the pointer //! conversion. Now, we can require the _user_ to _unsafely_ provide a function that implements the //! conversion correctly. The _using_ this function is safe and enables any particular user-defined //! pointer wrapper to safely transform itself. Note that for a limited selection of standard //! traits we can even go so far as offer pre-built converters that are safe to use in general. // Copyright 2019-2021 Andreas Molzer #![no_std] #![deny(missing_docs)] #![allow(unused_unsafe)] // Err on the side of caution. use core::{ alloc::Layout, future::Future, marker::PhantomData, }; mod impls { //! Safety: Provenance is always the same as self, pointer target is simply passed through. use core::ptr::NonNull; use super::CoerciblePtr; unsafe impl CoerciblePtr for *const T { type Pointee = T; type Output = *const U; fn as_sized_ptr(self: &mut *const T) -> *mut T { (*self) as *const T as *mut T } unsafe fn replace_ptr(self, new: *mut U) -> *const U { // See the mutable version. super::unsize_with(self as *mut T, |_| new) } } unsafe impl CoerciblePtr for *mut T { type Pointee = T; type Output = *mut U; fn as_sized_ptr(self: &mut *mut T) -> *mut T { *self } unsafe fn replace_ptr(self, new: *mut U) -> *mut U { // See the mutable version. super::unsize_with(self, |_| new) } } unsafe impl<'lt, T, U: ?Sized + 'lt> CoerciblePtr for &'lt T { type Pointee = T; type Output = &'lt U; fn as_sized_ptr(self: &mut &'lt T) -> *mut T { (*self) as *const T as *mut T } unsafe fn replace_ptr(self, new: *mut U) -> &'lt U { // See the mutable version. unsafe { &*super::unsize_with(self as *const T as *mut T, |_| new) } } } /// Safety: Provenance is always the same as self. unsafe impl<'lt, T, U: ?Sized + 'lt> CoerciblePtr for &'lt mut T { type Pointee = T; type Output = &'lt mut U; fn as_sized_ptr(self: &mut &'lt mut T) -> *mut T { &mut **self } unsafe fn replace_ptr(self, new: *mut U) -> &'lt mut U { // (Explanation should apply to the const version too). // We want the `new` pointer with provenance of `self`. This is because in // `as_sized_ptr` we had only borrowed the mutably reference and the usage of passing // it as argument to this method has invalidated this borrow. // We reuse `unsize_with` to set `self` as the pointer value in `new`. This is okay // because `new` should already be an unsized version, we merely make use of its // builtin provenance copy operation. unsafe { &mut *super::unsize_with(self, |_| new) } } } unsafe impl CoerciblePtr for core::pin::Pin where Ptr: CoerciblePtr + core::ops::DerefMut, Ptr::Output: core::ops::DerefMut, { type Pointee = T; type Output = core::pin::Pin; fn as_sized_ptr(&mut self) -> *mut Self::Pointee { unsafe { self.as_mut().get_unchecked_mut() } } unsafe fn replace_ptr(self, new: *mut U) -> Self::Output { let inner = core::pin::Pin::into_inner_unchecked(self); let new = inner.replace_ptr(new); core::pin::Pin::new_unchecked(new) } } unsafe impl CoerciblePtr for core::ptr::NonNull { type Pointee = T; type Output = NonNull; fn as_sized_ptr(&mut self) -> *mut T { self.as_ptr() } unsafe fn replace_ptr(self, new: *mut U) -> NonNull { // Safety: NonNull::new_unchecked(new) } } } /// Enables the unsizing of a sized pointer. #[repr(C)] pub struct Coercion *const U = fn(*const T) -> *const U> { pub(crate) coerce: F, pub(crate) _phantom: PhantomData *const U>, } /// Common trait impls for `Coercion`. mod coercion_impls; impl Coercion where F : FnOnce(*const T) -> *const U, { /// Construct a new coercer. /// /// # Safety /// /// The method must not perform any action other than unsizing the pointer. /// /// # Usage /// /// ``` /// use unsize::Coercion; /// use core::fmt::Debug; /// /// let c: Coercion = unsafe { /// Coercion::new(|x| x) /// }; /// ``` pub unsafe fn new(coerce: F) -> Self { Coercion { coerce, _phantom: PhantomData } } } macro_rules! coerce_to_dyn_trait { ( $(for <$($generics:ident),* $(,)?>)? $(#[$attr:meta])* fn $name:ident() -> $trait_type:path ) => { impl<'lt, T: $trait_type + 'lt, $($($generics),*)?> Coercion { $(#[$attr])* pub fn $name() -> Self { fn coerce_to_that_type<'lt, T: $trait_type + 'lt, $($($generics),*)?>( ptr: *const T ) -> *const (dyn $trait_type + 'lt) { ptr } unsafe { Coercion::new(coerce_to_that_type) } } } }; /* TODO: figure out how to make this work. * Then add Iterator, PartialEq, PartialOrd, etc. ($(#[$attr:meta])* fn $name:ident<$($param:ident),*>() -> $trait_type:ty) => { impl<'lt, $($param),*, T: $trait_type + 'lt> Coercion { $(#[$attr])* pub fn $name() -> Self { fn coerce_to_that_type<'lt, $($param),*, T: $trait_type + 'lt>( ptr: *const T ) -> *const (dyn $trait_type + 'lt) { ptr } Coercion { coerce: coerce_to_that_type } } } }; */ } coerce_to_dyn_trait!( /// Create a coercer that unsizes and keeps dynamic type information. /// /// # Usage /// /// ``` /// use unsize::{Coercion, CoerceUnsize}; /// use core::any::Any; /// /// fn generic(ptr: &T) -> &dyn Any { /// ptr.unsize(Coercion::to_any()) /// } /// ``` fn to_any() -> core::any::Any ); coerce_to_dyn_trait!( /// Create a coercer that unsizes a parameter to dynamically debug its fields. /// /// # Usage /// /// ``` /// use unsize::{Coercion, CoerceUnsize}; /// use core::fmt::Debug; /// /// fn generic(ptr: &T) -> &dyn Debug { /// ptr.unsize(Coercion::to_debug()) /// } /// ``` fn to_debug() -> core::fmt::Debug ); coerce_to_dyn_trait!( /// Create a coercer that unsizes a parameter to display it. /// /// # Usage /// /// ``` /// use unsize::{Coercion, CoerceUnsize}; /// use core::fmt::Display; /// /// fn generic(ptr: &T) -> &dyn Display { /// ptr.unsize(Coercion::to_display()) /// } /// ``` fn to_display() -> core::fmt::Display ); #[cfg(rustc_1_51)] impl Coercion<[T; N], [T]> { /// Create a coercer that unsizes an array to a slice. /// /// # Usage /// /// ``` /// use unsize::{Coercion, CoerceUnsize}; /// use core::fmt::Display; /// /// fn generic(ptr: &[T; 2]) -> &[T] { /// ptr.unsize(Coercion::to_slice()) /// } /// ``` pub fn to_slice() -> Self { fn coerce( ptr: *const [T; N] ) -> *const [T] { ptr } unsafe { Coercion::new(coerce) } } } macro_rules! coerce_to_dyn_fn { ( $(#![$attr:meta])? $($arg:ident),* ) => { coerce_to_dyn_fn!( $(#![$attr])? @<$($arg,)*>: (dyn Fn($($arg,)*) -> T + 'lt), (dyn FnMut($($arg,)*) -> T + 'lt), (dyn FnOnce($($arg,)*) -> T + 'lt) ); }; ( $(#![$attr:meta])? @<$($arg:ident,)*>: $dyn:ty, $dyn_mut:ty, $dyn_once:ty ) => { coerce_to_dyn_trait! { for $(#[$attr])? /// Create a coercer that unsizes to a dynamically dispatched function. /// /// This is implemented for function arities up to the shown one /// (other methods / impls are hidden in the docs for readability) fn to_fn() -> Fn($($arg),*) -> Ret } coerce_to_dyn_trait! { for $(#[$attr])? /// Create a coercer that unsizes to a dynamically dispatched mutable function. /// /// This is implemented for function arities up to the shown one /// (other methods / impls are hidden in the docs for readability) fn to_fn_mut() -> FnMut($($arg),*) -> Ret } coerce_to_dyn_trait! { for $(#[$attr])? /// Create a coercer that unsizes to a dynamically dispatched once function. /// /// This is implemented for function arities up to the shown one /// (other methods / impls are hidden in the docs for readability) fn to_fn_once() -> FnOnce($($arg),*) -> Ret } }; } coerce_to_dyn_fn!(#![doc(hidden)] ); coerce_to_dyn_fn!(#![doc(hidden)] A); coerce_to_dyn_fn!(#![doc(hidden)] A,B); coerce_to_dyn_fn!(#![doc(hidden)] A,B,C); coerce_to_dyn_fn!(#![doc(hidden)] A,B,C,D); coerce_to_dyn_fn!(#![doc(hidden)] A,B,C,D,E); coerce_to_dyn_fn!(A,B,C,D,E,G); coerce_to_dyn_trait! { for /// Create a coercer that unsizes to a dynamically dispatched iterator. /// /// This is implemented for all iterator types. It can type-erase the concrete type to wrap an /// otherwise unnameable adapter in a custom smart pointer, to store it within a struct. /// /// # Usage /// /// ``` /// # use unsize::CoerciblePtr; /// // A non-coercible box, for demonstration purposes /// struct MyBox(Box); /// /// unsafe impl<'lt, T, U: ?Sized + 'lt> CoerciblePtr for MyBox { /// // … /// # type Pointee = T; /// # type Output = MyBox; /// # fn as_sized_ptr(self: &mut MyBox) -> *mut T { /// # (&mut *self.0) as *mut T /// # } /// # unsafe fn replace_ptr(self, new: *mut U) -> MyBox { /// # let raw: *mut T = Box::into_raw(self.0); /// # let raw: *mut U = raw.replace_ptr(new); /// # MyBox(Box::from_raw(raw)) /// # } /// } /// # impl MyBox { /// # pub fn new(val: T) -> Self { MyBox(std::boxed::Box::new(val)) } /// # } /// /// use unsize::{Coercion, CoerceUnsize}; /// use core::fmt::Display; /// /// fn maybe_empty(item: &T) -> MyBox + '_> { /// if core::mem::size_of::() % 2 == 0 { /// MyBox::new(core::iter::empty()) /// .unsize(Coercion::to_iterator()) /// } else { /// MyBox::new(core::iter::repeat(item.clone())) /// .unsize(Coercion::to_iterator()) /// } /// } /// ``` fn to_iterator() -> Iterator } coerce_to_dyn_trait! { for /// Create a coercer that unsizes to a dynamically dispatched future. /// /// This is implemented for all iterator types. It can type-erase the concrete type to wrap an /// otherwise unnameable adapter in a custom smart pointer, to store it within a struct. /// /// # Usage /// /// ``` /// # use core::future::Future; /// # use unsize::CoerciblePtr; /// // A non-coercible box, for demonstration purposes /// struct MyBox(Box); /// /// unsafe impl<'lt, T, U: ?Sized + 'lt> CoerciblePtr for MyBox { /// // … /// # type Pointee = T; /// # type Output = MyBox; /// # fn as_sized_ptr(self: &mut MyBox) -> *mut T { /// # (&mut *self.0) as *mut T /// # } /// # unsafe fn replace_ptr(self, new: *mut U) -> MyBox { /// # let raw: *mut T = Box::into_raw(self.0); /// # let raw: *mut U = raw.replace_ptr(new); /// # MyBox(Box::from_raw(raw)) /// # } /// } /// # impl MyBox { /// # pub fn new(val: T) -> Self { MyBox(std::boxed::Box::new(val)) } /// # } /// /// use unsize::{Coercion, CoerceUnsize}; /// use core::fmt::Display; /// /// fn maybe_empty(val: T) -> MyBox> { /// if core::mem::size_of::() % 2 == 0 { /// MyBox::new(core::future::pending()) /// .unsize(Coercion::to_future()) /// } else { /// MyBox::new(core::future::ready(val)) /// .unsize(Coercion::to_future()) /// } /// } /// ``` fn to_future() -> Future } /// ``` /// use unsize::{Coercion, CoerceUnsize}; /// fn arg0(fptr: &F) -> &dyn FnOnce() { /// fptr.unsize(Coercion::<_, dyn FnOnce()>::to_fn_once()) /// } /// fn arg1(fptr: &F) -> &dyn FnOnce(u32) { /// fptr.unsize(Coercion::<_, dyn FnOnce(u32)>::to_fn_once()) /// } /// fn arg6(fptr: &F) /// -> &dyn FnOnce(u32,u32,u32,u32,u32,u32) /// { /// fptr.unsize(Coercion::<_, dyn FnOnce(u32,u32,u32,u32,u32,u32)>::to_fn_once()) /// } /// arg0(&|| {}); /// arg1(&|_| {}); /// arg6(&|_,_,_,_,_,_| {}); /// ``` extern {} /// Add unsizing methods to pointer-like types. /// /// # Safety /// A correct implementation must uphold, when calling `replace_ptr` with valid arguments, that the /// pointer target and the provenance of the pointer stay unchanged. This allows calling the /// coercion of inner fields of wrappers even when an invariant depends on the pointer target. pub unsafe trait CoerciblePtr: Sized { /// The type we point to. /// This influences which kinds of unsizing are possible. type Pointee; /// The output type when unsizing the pointee to `U`. type Output; /// Get the raw inner pointer. fn as_sized_ptr(&mut self) -> *mut Self::Pointee; /// Replace the container inner pointer with an unsized version. /// # Safety /// The caller guarantees that the replacement is the same pointer, just a fat pointer variant /// with a correct tag. unsafe fn replace_ptr(self, _: *mut U) -> Self::Output; } /// An extension trait using `CoerciblePtr` for a safe interface. pub trait CoerceUnsize: CoerciblePtr { /// Convert a pointer, as if with unsize coercion. /// /// See [`CoerciblePtr::unsize_with`][unsize_with] for details. /// /// [unsize_with]: struct.CoerciblePtr.html#method.unsize_with fn unsize(mut self, with: Coercion) -> Self::Output where F : FnOnce(*const Self::Pointee) -> *const U, { unsafe { let ptr = self.as_sized_ptr(); let new_ptr = unsize_with(ptr, with.coerce); self.replace_ptr(new_ptr) } } } impl CoerceUnsize for T where T: CoerciblePtr {} /// Convert a pointer, as if with unsize coercion. /// /// The result pointer will have the same provenance information as the argument `ptr`. /// /// # Safety /// /// The caller must guarantee that it is sound to dereference the argument and convert it into a /// reference. This also, very slightly, relies on some of Rust's internal layout but it will /// assert that they actually hold. If this sounds too risky, do not use this method. The caller /// must also guarantee that `with` will only execute a coercion and _not_ change the pointer /// itself. unsafe fn unsize_with( ptr: *mut T, with: impl FnOnce(*const T) -> *const U, ) -> *mut U { let mut raw_unsized = with(ptr) as *mut U; // Not a debug assert since it hopefully monomorphizes to a no-op (or an // unconditional panic should multi-trait objects end up happening). assert_eq!(Layout::for_value(&raw_unsized), Layout::new::<[usize; 2]>(), "Unexpected layout of unsized pointer."); debug_assert_eq!(raw_unsized as *const u8 as usize, ptr as usize, "Unsize coercion seemingly changed the pointer base"); let ptr_slot = &mut raw_unsized as *mut *mut U as *mut *const u8; // Safety: Not totally clear as it relies on the standard library implementation of pointers. // The layout is usually valid for such a write (we've asserted that above) and all pointers // are larger and at least as aligned as a single pointer to bytes. // It could be that this invalidates the representation of `raw_unsized` but all currently // pointers store their tag _behind_ the base pointer. // // There is an `unsafe`, unstable method (#75091) with the same effect and implementation. // // According to the `ptr::set_ptr_value` method we change provenance back to the `raw` pointer. // This can be used since we haven't used any pointer from which it was derived. This // invalidates the access tags of `temp_reference` and the original `raw_unsized` value but // both will no longer be used. unsafe { ptr_slot.write(ptr as *const u8) }; // Safety: the base pointer that we've just written was not null. raw_unsized } /// Ensure that using `CoerceUnsize` does not import as_sized_ptr. /// /// ```compile_fail /// use unsize::CoerceUnsize; /// use core::ptr::NonNull; /// /// let ptr = NonNull::from(&2u32); /// let _ = ptr.as_sized_ptr(); /// ``` extern {} #[cfg(test)] mod tests; /// Non-`unsafe` [`struct@Coercion`] constructor for arbitrary trait bounds. /// /// # Example // (and test!) /// /// ```rust /// use unsize::{Coercion, CoerceUnsize}; /// /// trait MyFancyTrait { /* … */ } /// /// fn generic(ptr: &T) -> &dyn MyFancyTrait { /// ptr.unsize(Coercion!(to dyn MyFancyTrait)) /// } /// ``` #[macro_export] macro_rules! Coercion { (to dyn $($bounds:tt)*) => ( #[allow(unused_unsafe)] unsafe { $crate::Coercion::new({ #[allow(unused_parens)] fn coerce<'lt> (p: *const (impl $($bounds)* + 'lt)) -> *const (dyn $($bounds)* + 'lt) { p } coerce }) } ); } unsize-1.1.0/src/tests.rs000064400000000000000000000020130000000000000134100ustar 00000000000000use super::*; macro_rules! assert_impls {( for [$($generics:tt)*] $T:ty : $($bounds:tt)* ) => ( const _: () = { fn _for<$($generics)*> () { fn bounds_check<__>() where __ : $($bounds)* {} let _ = bounds_check::<$T>; } }; )} assert_impls! { for[ // The pointees' lack of bounds should not make `Coercion` lack the bounds too. T, U : ?Sized, ] Coercion : Copy + Clone + PartialEq + Eq + ::core::hash::Hash + } // More generally, assert_impls! { for[ // The pointees' lack of bounds should not make `Coercion` lack the bounds too. T, U : ?Sized, F : FnOnce(*const T) -> *const U + Copy + Clone + PartialEq + Eq + ::core::hash::Hash + , ] Coercion : Copy + Clone + PartialEq + Eq + ::core::hash::Hash + } unsize-1.1.0/tests/unsize.rs000064400000000000000000000032520000000000000141440ustar 00000000000000use unsize::{Coercion, CoerceUnsize}; #[test] fn any() { use core::any::Any; fn generic(ptr: &T) -> &dyn Any { ptr.unsize(Coercion::to_any()) } generic(&0u32); fn generic_mut(ptr: &mut T) -> &mut dyn Any { ptr.unsize(Coercion::to_any()) } generic_mut(&mut 0u32); use core::pin::Pin; fn generic_mut_pinned(ptr: Pin<&mut T>) -> Pin<&mut dyn Any> { ptr.unsize(Coercion::to_any()) } let mut p = (0_u32, ::core::marker::PhantomPinned); let p = unsafe { Pin::new_unchecked(&mut p) }; generic_mut_pinned(p); } #[test] fn debug() { use core::fmt::Debug; fn generic(ptr: &T) -> &dyn Debug { ptr.unsize(Coercion::to_debug()) } generic(&0u32); } #[test] fn display() { use core::fmt::Display; fn generic(ptr: &T) -> &dyn Display { ptr.unsize(Coercion::to_display()) } generic(&0u32); } #[cfg(rustc_1_51)] #[test] fn to_slice() { fn generic(ptr: &[T; 4]) -> &[T] { ptr.unsize(Coercion::to_slice()) } generic(&[0u32; 4]); } #[test] fn functions() { fn arg0(fptr: &F) -> &dyn FnOnce() { fptr.unsize(Coercion::<_, dyn FnOnce()>::to_fn_once()) } fn arg1(fptr: &F) -> &dyn FnOnce(u32) { fptr.unsize(Coercion::<_, dyn FnOnce(u32)>::to_fn_once()) } fn arg6(fptr: &F) -> &dyn FnOnce(u32,u32,u32,u32,u32,u32) { fptr.unsize(Coercion::<_, dyn FnOnce(u32,u32,u32,u32,u32,u32)>::to_fn_once()) } arg0(&|| {}); arg1(&|_| {}); arg6(&|_,_,_,_,_,_| {}); }