#![allow(clippy::let_unit_value)]
#![cfg_attr(
feature = "nightly",
feature(unsize, coerce_unsized, doc_auto_cfg, ptr_metadata)
)]
#![cfg_attr(all(feature = "nightly", feature = "alloc"), feature(allocator_api))]
#![cfg_attr(not(any(feature = "std", test)), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc as std_alloc;
use core::{
fmt::{Debug, Display, Formatter, Result as FmtResult},
iter::FusedIterator,
marker::PhantomData,
mem::{self, ManuallyDrop, MaybeUninit},
ops::{Deref, DerefMut},
pin::Pin,
ptr,
};
use cfg_if::cfg_if;
use static_assertions::{assert_impl_all, assert_not_impl_any};
use self::pointee::Metadata;
use self::storage::RawStorage;
assert_impl_all!(InlineDyn<dyn Debug + Unpin>: Unpin);
assert_impl_all!(InlineDyn<dyn Debug + Send>: Send);
assert_impl_all!(InlineDyn<dyn Debug + Sync>: Sync);
assert_not_impl_any!(InlineDyn<dyn Debug>: Unpin, Send, Sync);
#[cfg(feature = "nightly")]
mod nightly;
mod pointee;
mod storage;
pub use storage::{Align, Alignment, DEFAULT_SIZE};
struct AssertLayoutCompatible<T, const SIZE: usize, const ALIGN: usize>(PhantomData<T>);
impl<T, const SIZE: usize, const ALIGN: usize> AssertLayoutCompatible<T, SIZE, ALIGN> {
const OK: () = assert!(
(mem::size_of::<T>() <= SIZE) && (mem::align_of::<T>() <= ALIGN),
"size and/or alignment insufficient to store value"
);
}
struct AssertLarger<const X: usize, const Y: usize>;
impl<const X: usize, const Y: usize> AssertLarger<X, Y> {
const OK: () = assert!(X >= Y, "new value must not be smaller than old");
}
pub struct InlineDyn<D: ?Sized, const S: usize = DEFAULT_SIZE, const A: usize = S>
where
Align<A>: Alignment,
{
metadata: Metadata<D>,
storage: RawStorage<S, A>,
_marker: PhantomData<D>,
}
impl<D: ?Sized, const S: usize, const A: usize> Drop for InlineDyn<D, S, A>
where
Align<A>: Alignment,
{
fn drop(&mut self) {
unsafe {
(self.get_mut() as *mut D).drop_in_place();
}
}
}
impl<D: ?Sized, const S: usize, const A: usize> InlineDyn<D, S, A>
where
Align<A>: Alignment,
{
#[doc(hidden)]
#[cfg(not(feature = "nightly"))]
pub unsafe fn with_cast<T>(value: T, cast: fn(*const T) -> *const D) -> Self {
let metadata = Metadata::new(unsafe { mem::transmute(cast) });
unsafe { Self::with_metadata(metadata, value) }
}
#[doc(hidden)]
#[cfg(not(feature = "nightly"))]
pub unsafe fn try_with_cast<T>(value: T, cast: fn(*const T) -> *const D) -> Result<Self, T> {
let metadata = Metadata::new(unsafe { mem::transmute(cast) });
unsafe { Self::try_with_metadata(metadata, value) }
}
unsafe fn with_metadata<T>(metadata: Metadata<D>, val: T) -> Self {
let () = AssertLayoutCompatible::<T, S, A>::OK;
unsafe { Self::with_metadata_unchecked(metadata, val) }
}
unsafe fn try_with_metadata<T>(metadata: Metadata<D>, val: T) -> Result<Self, T> {
if RawStorage::<S, A>::is_layout_compatible::<T>(&val) {
unsafe { Ok(Self::with_metadata_unchecked(metadata, val)) }
} else {
Err(val)
}
}
unsafe fn with_metadata_unchecked<T>(metadata: Metadata<D>, val: T) -> Self {
let mut storage = RawStorage::new();
unsafe {
storage.as_mut_ptr().cast::<T>().write(val);
}
Self {
metadata,
storage,
_marker: PhantomData,
}
}
pub fn get_ref(&self) -> &D {
unsafe { &*pointee::from_raw_parts(self.storage.as_ptr().cast(), self.metadata) }
}
pub fn get_mut(&mut self) -> &mut D {
unsafe {
&mut *pointee::from_raw_parts_mut(self.storage.as_mut_ptr().cast(), self.metadata)
}
}
pub fn get_pinned_mut(self: Pin<&mut Self>) -> Pin<&mut D> {
unsafe { self.map_unchecked_mut(|x| x.get_mut()) }
}
unsafe fn resize_unchecked<const U: usize, const V: usize>(this: Self) -> InlineDyn<D, U, V>
where
Align<V>: Alignment,
{
let size = mem::size_of_val(this.get_ref());
let this = ManuallyDrop::new(this);
let mut storage = RawStorage::<U, V>::new();
unsafe {
this.storage
.as_ptr()
.copy_to_nonoverlapping(storage.as_mut_ptr(), size);
}
InlineDyn {
metadata: this.metadata,
storage,
_marker: PhantomData,
}
}
pub fn try_resize<const U: usize, const V: usize>(
this: Self,
) -> Result<InlineDyn<D, U, V>, Self>
where
Align<V>: Alignment,
{
if RawStorage::<U, V>::is_layout_compatible::<D>(this.get_ref()) {
unsafe { Ok(Self::resize_unchecked(this)) }
} else {
Err(this)
}
}
pub fn grow<const U: usize, const V: usize>(this: Self) -> InlineDyn<D, U, V>
where
Align<V>: Alignment,
{
let () = AssertLarger::<U, S>::OK;
let () = AssertLarger::<V, A>::OK;
unsafe { Self::resize_unchecked(this) }
}
}
impl<D: Unpin + ?Sized, const S: usize, const A: usize> Unpin for InlineDyn<D, S, A> where
Align<A>: Alignment
{
}
impl<D: ?Sized, const S: usize, const A: usize> Deref for InlineDyn<D, S, A>
where
Align<A>: Alignment,
{
type Target = D;
fn deref(&self) -> &Self::Target {
self.get_ref()
}
}
impl<D: ?Sized, const S: usize, const A: usize> DerefMut for InlineDyn<D, S, A>
where
Align<A>: Alignment,
{
fn deref_mut(&mut self) -> &mut Self::Target {
self.get_mut()
}
}
impl<D: Debug + ?Sized, const S: usize, const A: usize> Debug for InlineDyn<D, S, A>
where
Align<A>: Alignment,
{
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
Debug::fmt(self.get_ref(), f)
}
}
impl<D: Display + ?Sized, const S: usize, const A: usize> Display for InlineDyn<D, S, A>
where
Align<A>: Alignment,
{
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
Display::fmt(self.get_ref(), f)
}
}
pub unsafe trait DynClone {
#[doc(hidden)]
fn dyn_clone_into(&self, storage: &mut [MaybeUninit<u8>]);
}
unsafe impl<T> crate::DynClone for T
where
T: Clone,
{
fn dyn_clone_into(&self, storage: &mut [MaybeUninit<u8>]) {
assert!(mem::size_of::<Self>() <= storage.len());
let this = (*self).clone();
unsafe {
storage.as_mut_ptr().cast::<T>().write(this);
}
}
}
impl<D: DynClone + ?Sized, const S: usize, const A: usize> Clone for InlineDyn<D, S, A>
where
Align<A>: Alignment,
{
fn clone(&self) -> Self {
use core::slice;
let mut storage = RawStorage::new();
unsafe {
self.get_ref()
.dyn_clone_into(slice::from_raw_parts_mut(storage.as_mut_ptr(), S));
Self {
storage,
metadata: self.metadata,
_marker: PhantomData,
}
}
}
}
#[macro_export]
macro_rules! dyn_star {
($($trait:path),+ $(,)?) => {
$crate::InlineDyn::<dyn ($($trait)*)>
};
($($trait:path,)+ $l:lifetime $(,)?) => {
$crate::InlineDyn::<dyn $($trait)* + $l>
};
}
cfg_if! {
if #[cfg(feature = "nightly")] {
#[macro_export]
macro_rules! inline_dyn {
($e:expr) => {
$crate::InlineDyn::new($e)
};
}
#[macro_export]
macro_rules! inline_dyn_try {
($e:expr) => {
$crate::InlineDyn::try_new($e)
};
}
#[cfg(feature = "alloc")]
#[macro_export]
macro_rules! inline_dyn_box {
($e:expr) => {
$crate::InlineDyn::try_or_box($e)
};
}
} else {
#[macro_export]
macro_rules! inline_dyn {
($e:expr) => {{
let value = $e;
unsafe {
$crate::InlineDyn::with_cast(value, |p| p)
}
}};
}
#[macro_export]
macro_rules! inline_dyn_try {
($e:expr) => {{
let value = $e;
unsafe {
$crate::InlineDyn::try_with_cast(value, |p| p)
}
}};
}
#[cfg(feature = "alloc")]
#[macro_export]
macro_rules! inline_dyn_box {
($e:expr) => {{
$crate::inline_dyn_try!($e).unwrap_or_else(|v| $crate::inline_dyn!(Box::new(v)))
}};
}
impl<T, const S: usize, const A: usize> InlineDyn<[T], S, A>
where
Align<A>: Alignment,
{
pub fn new<const N: usize>(value: [T; N]) -> Self {
unsafe { Self::with_cast(value, |p| p) }
}
}
}
}
macro_rules! impl_new {
($trait:path $(, $arg:ident)*) => {
#[cfg(not(feature = "nightly"))]
impl<'a, const _S: usize, const _A: usize $(, $arg)*> $crate::InlineDyn<(dyn $trait + 'a), _S, _A>
where $crate::Align<_A>: $crate::Alignment {
pub fn new<_T: $trait + 'a>(value: _T) -> Self {
inline_dyn!(value)
}
pub fn try_new<_T: $trait + 'a>(value: _T) -> Result<Self, _T> {
inline_dyn_try!(value)
}
#[cfg(feature = "alloc")]
pub fn try_or_box<_T>(value: _T) -> Self
where _T: $trait + 'a, std_alloc::boxed::Box<_T>: $trait + 'a, {
Self::try_new(value).unwrap_or_else(|v| Self::new(std_alloc::boxed::Box::new(v)))
}
}
};
}
impl<T, const S: usize, const A: usize, const N: usize> TryFrom<InlineDyn<[T], S, A>> for [T; N]
where
Align<A>: Alignment,
{
type Error = InlineDyn<[T], S, A>;
fn try_from(value: InlineDyn<[T], S, A>) -> Result<Self, Self::Error> {
if value.len() != N {
return Err(value);
}
let value = ManuallyDrop::new(value);
unsafe { Ok(value.as_ptr().cast::<[T; N]>().read()) }
}
}
pub struct IntoIter<T, const S: usize, const A: usize>
where
Align<A>: Alignment,
{
storage: ManuallyDrop<InlineDyn<[T], S, A>>,
pos: usize,
}
impl<T, const S: usize, const A: usize> Drop for IntoIter<T, S, A>
where
Align<A>: Alignment,
{
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(&mut self.storage[self.pos..]);
}
}
}
impl<T, const S: usize, const A: usize> IntoIter<T, S, A>
where
Align<A>: Alignment,
{
pub fn new(inner: InlineDyn<[T], S, A>) -> Self {
Self {
storage: ManuallyDrop::new(inner),
pos: 0,
}
}
}
impl<T, const S: usize, const A: usize> Iterator for IntoIter<T, S, A>
where
Align<A>: Alignment,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.pos < self.storage.len() {
let ret = unsafe { self.storage.as_ptr().add(self.pos).read() };
self.pos += 1;
Some(ret)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let left = self.storage.len() - self.pos;
(left, Some(left))
}
}
impl<T, const S: usize, const A: usize> ExactSizeIterator for IntoIter<T, S, A> where
Align<A>: Alignment
{
}
impl<T, const S: usize, const A: usize> FusedIterator for IntoIter<T, S, A> where Align<A>: Alignment
{}
#[cfg(all(feature = "nightly", feature = "alloc"))]
pub mod alloc {
use core::{
alloc::{AllocError, Allocator, Layout},
ptr::NonNull,
};
use crate::{Align, Alignment, InlineDyn, DEFAULT_SIZE};
pub type InlineDynAllocator<const S: usize = DEFAULT_SIZE, const A: usize = S> =
InlineDyn<dyn Allocator, S, A>;
unsafe impl<D, const S: usize, const A: usize> Allocator for InlineDyn<D, S, A>
where
D: Allocator,
Align<A>: Alignment,
{
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.get_ref().allocate(layout)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe { self.get_ref().deallocate(ptr, layout) }
}
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.get_ref().allocate_zeroed(layout)
}
unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { self.get_ref().grow(ptr, old_layout, new_layout) }
}
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { self.get_ref().grow_zeroed(ptr, old_layout, new_layout) }
}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { self.get_ref().shrink(ptr, old_layout, new_layout) }
}
}
}
pub mod any {
use core::{
any::{Any, TypeId},
mem::ManuallyDrop,
};
use crate::{Align, Alignment, InlineDyn, DEFAULT_SIZE};
pub type InlineDynAny<const S: usize = DEFAULT_SIZE, const A: usize = S> =
InlineDyn<dyn Any, S, A>;
#[cfg(not(feature = "nightly"))]
impl<const S: usize, const A: usize> InlineDynAny<S, A>
where
Align<A>: Alignment,
{
pub fn new<T: Any>(value: T) -> Self {
inline_dyn![value]
}
}
impl<D, const S: usize, const A: usize> InlineDyn<D, S, A>
where
D: Any + ?Sized,
Align<A>: Alignment,
{
pub fn downcast<T: Any>(self) -> Result<T, Self> {
if self.get_ref().type_id() == TypeId::of::<T>() {
let this = ManuallyDrop::new(self);
unsafe { Ok((this.get_ref() as *const D).cast::<T>().read()) }
} else {
Err(self)
}
}
}
}
pub mod convert {
use crate::{InlineDyn, DEFAULT_SIZE};
pub type InlineDynAsRef<'a, U, const S: usize = DEFAULT_SIZE, const A: usize = S> =
InlineDyn<dyn core::convert::AsRef<U> + 'a, S, A>;
pub type InlineDynAsMut<'a, U, const S: usize = DEFAULT_SIZE, const A: usize = S> =
InlineDyn<dyn core::convert::AsMut<U> + 'a, S, A>;
impl_new!(AsRef<U>, U);
impl_new!(AsMut<U>, U);
}
pub mod fmt {
use crate::{InlineDyn, DEFAULT_SIZE};
pub type InlineDynDebug<'a, const S: usize = DEFAULT_SIZE, const A: usize = S> =
InlineDyn<dyn core::fmt::Debug + 'a, S, A>;
pub type InlineDynDisplay<'a, const S: usize = DEFAULT_SIZE, const A: usize = S> =
InlineDyn<dyn core::fmt::Display + 'a, S, A>;
impl_new!(core::fmt::Debug);
impl_new!(core::fmt::Display);
}
pub mod future {
use crate::{Align, Alignment, InlineDyn, DEFAULT_SIZE};
use core::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
pub type InlineDynFuture<'a, O, const S: usize = DEFAULT_SIZE, const A: usize = S> =
InlineDyn<dyn Future<Output = O> + 'a, S, A>;
impl_new!(Future<Output = O>, O);
impl<F, const S: usize, const A: usize> Future for InlineDyn<F, S, A>
where
F: Future + ?Sized,
Align<A>: Alignment,
{
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.get_pinned_mut().poll(cx)
}
}
}
pub mod hash {
use core::hash::Hasher;
use crate::{Align, Alignment, InlineDyn, DEFAULT_SIZE};
pub type InlineDynHasher<'a, const S: usize = DEFAULT_SIZE, const A: usize = S> =
InlineDyn<dyn Hasher + 'a, S, A>;
impl_new!(Hasher);
impl<H, const S: usize, const A: usize> Hasher for InlineDyn<H, S, A>
where
H: Hasher + ?Sized,
Align<A>: Alignment,
{
fn write(&mut self, bytes: &[u8]) {
self.get_mut().write(bytes)
}
fn finish(&self) -> u64 {
self.get_ref().finish()
}
}
}
pub mod iter {
use crate::{Align, Alignment, InlineDyn, DEFAULT_SIZE};
pub type InlineDynIterator<'a, I, const S: usize = DEFAULT_SIZE, const A: usize = S> =
InlineDyn<dyn Iterator<Item = I> + 'a, S, A>;
pub type InlineDynDoubleEndedIterator<
'a,
I,
const S: usize = DEFAULT_SIZE,
const A: usize = S,
> = InlineDyn<dyn DoubleEndedIterator<Item = I> + 'a, S, A>;
impl_new!(Iterator<Item = I>, I);
impl_new!(DoubleEndedIterator<Item = I>, I);
impl<I, const S: usize, const A: usize> Iterator for InlineDyn<I, S, A>
where
I: Iterator + ?Sized,
Align<A>: Alignment,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
self.get_mut().next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.get_ref().size_hint()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.get_mut().nth(n)
}
}
impl<I, const S: usize, const A: usize> DoubleEndedIterator for InlineDyn<I, S, A>
where
I: DoubleEndedIterator + ?Sized,
Align<A>: Alignment,
{
fn next_back(&mut self) -> Option<Self::Item> {
self.get_mut().next_back()
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.get_mut().nth_back(n)
}
}
impl<I, const S: usize, const A: usize> ExactSizeIterator for InlineDyn<I, S, A>
where
I: ExactSizeIterator + ?Sized,
Align<A>: Alignment,
{
fn len(&self) -> usize {
self.get_ref().len()
}
}
impl<I, const S: usize, const A: usize> core::iter::FusedIterator for InlineDyn<I, S, A>
where
I: core::iter::FusedIterator + ?Sized,
Align<A>: Alignment,
{
}
}
pub mod ops {
#[macro_export]
macro_rules! InlineDynFn {
(($($Args:ty),*) $(-> $R:ty)?) => {
$crate::InlineDynFn!(($($Args),*) $(-> $R)?; $crate::DEFAULT_SIZE)
};
(($($Args:ty),*) $(-> $R:ty)?; $S:ty) => {
$crate::InlineDynFn!(($($Args),*) $(-> $R)?; $S, $S)
};
(($($Args:ty),*) $(-> $R:ty)?; $S:ty, $A:ty) => {
$crate::InlineDyn<dyn Fn($($Args),*)$(-> $R)?, $S, $A>
};
}
#[macro_export]
macro_rules! InlineDynFnMut {
(($($Args:ty),*) $(-> $R:ty)?) => {
$crate::InlineDynFnMut!(($($Args),*) $(-> $R)?; $crate::DEFAULT_SIZE)
};
(($($Args:ty),*) $(-> $R:ty)?; $S:ty) => {
$crate::InlineDyn<dyn FnMut($($Args),*)$(-> $R)?, $S, $S>
};
(($($Args:ty),*) $(-> $R:ty)?; $S:ty, $A:ty) => {
$crate::InlineDyn<dyn FnMut($($Args),*)$(-> $R)?, $S, $A>
};
}
}
cfg_if! {
if #[cfg(feature = "std")] {
pub mod error {
use std::error::Error;
use crate::{Align, Alignment, InlineDyn, DEFAULT_SIZE};
pub type InlineDynError<'a, const S: usize = DEFAULT_SIZE, const A: usize = S> = InlineDyn<dyn Error + 'a, S, A>;
impl_new!(Error);
#[allow(deprecated)]
impl<E, const S: usize, const A: usize> Error for InlineDyn<E, S, A>
where
E: Error + ?Sized,
Align<A>: Alignment,
{
fn description(&self) -> &str {
self.get_ref().description()
}
fn cause(&self) -> Option<&dyn Error> {
self.get_ref().cause()
}
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.get_ref().source()
}
}
}
pub mod io {
use crate::{Align, Alignment, InlineDyn, DEFAULT_SIZE};
use std::io;
pub type InlineDynRead<'a, const S: usize = DEFAULT_SIZE, const A: usize = S> = InlineDyn<dyn io::Read + 'a, S, A>;
pub type InlineDynWrite<'a, const S: usize = DEFAULT_SIZE, const A: usize = S> = InlineDyn<dyn io::Write + 'a, S, A>;
pub type InlineDynSeek<'a, const S: usize = DEFAULT_SIZE, const A: usize = S> = InlineDyn<dyn io::Seek + 'a, S, A>;
pub type InlineDynBufRead<'a, const S: usize = DEFAULT_SIZE, const A: usize = S> = InlineDyn<dyn io::BufRead + 'a, S, A>;
impl_new!(io::Read);
impl_new!(io::Write);
impl_new!(io::Seek);
impl_new!(io::BufRead);
impl<T, const S: usize, const A: usize> io::Read for InlineDyn<T, S, A>
where
T: io::Read + ?Sized,
Align<A>: Alignment,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.get_mut().read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.get_mut().read_vectored(bufs)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.get_mut().read_exact(buf)
}
}
impl<T, const S: usize, const A: usize> io::Write for InlineDyn<T, S, A>
where
T: io::Write + ?Sized,
Align<A>: Alignment,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.get_mut().write(buf)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.get_mut().write_vectored(bufs)
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.get_mut().write_all(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.get_mut().flush()
}
}
impl<T, const S: usize, const A: usize> io::Seek for InlineDyn<T, S, A>
where
T: io::Seek + ?Sized,
Align<A>: Alignment,
{
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
self.get_mut().seek(pos)
}
}
impl<T, const S: usize, const A: usize> io::BufRead for InlineDyn<T, S, A>
where
T: io::BufRead + ?Sized,
Align<A>: Alignment,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.get_mut().fill_buf()
}
fn consume(&mut self, amt: usize) {
self.get_mut().consume(amt)
}
}
}
}
}
#[cfg(test)]
mod tests {
use core::cell::Cell;
use super::{fmt::InlineDynDebug, *};
macro_rules! assert_matches {
($left:expr, $(|)? $($pattern:pat_param)|+ $(if $guard:expr)? $(,)?) => {
match $left {
$($pattern)|+ $(if $guard)? => {}
ref left_val => {
panic!(r#"assertion failed: `(left matches right)`
left: `{left_val:?}`
right: `{}`"#, stringify!($($pattern)|+ $(if $guard)?))
}
}
};
}
#[test]
fn test_simple() {
let val = <dyn_star!(Debug)>::new(42usize);
assert_eq!(format!("{val:?}"), "42");
}
#[test]
fn test_drop() {
#[derive(Debug)]
struct Dropper<'a>(&'a mut bool);
impl Drop for Dropper<'_> {
fn drop(&mut self) {
*self.0 = true;
}
}
let mut dropped = false;
{
let dbg = <dyn_star!(Debug, '_)>::new(Dropper(&mut dropped));
assert_eq!(format!("{dbg:?}"), "Dropper(false)");
}
assert!(dropped);
}
#[test]
fn test_resize() {
let val = <dyn_star!(Debug)>::new(42u8);
assert_eq!(format!("{val:?}"), "42");
let val: InlineDynDebug<1> = <dyn_star!(Debug)>::try_resize(val).ok().unwrap();
assert_eq!(format!("{val:?}"), "42");
}
#[test]
fn test_resize_insufficient() {
let val = <dyn_star!(Debug)>::new(42u32);
assert_eq!(format!("{val:?}"), "42");
let res: Result<InlineDynDebug<1>, _> = <dyn_star!(Debug)>::try_resize(val);
assert_matches!(res, Err(_));
}
#[test]
fn test_slice() {
let val = InlineDyn::<[u8], 4>::new([1, 2, 3, 4]);
assert_eq!(val.get_ref(), [1, 2, 3, 4]);
}
#[test]
fn test_interior_mutability() {
trait Foo {
fn foo(&self) -> u32;
}
struct Bar(Cell<u32>);
impl Foo for Bar {
fn foo(&self) -> u32 {
let r = self.0.get();
self.0.set(r + 1);
r
}
}
let val: dyn_star!(Foo) = inline_dyn![Bar(Cell::new(0))];
assert_eq!(val.foo(), 0);
assert_eq!(val.foo(), 1);
assert_eq!(val.foo(), 2);
}
#[test]
fn test_not_unpin() {
use super::future::InlineDynFuture;
use core::{
future::{poll_fn, Future},
pin::pin,
ptr,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
};
struct NoopWaker;
impl From<NoopWaker> for RawWaker {
fn from(_: NoopWaker) -> Self {
RawWaker::new(
ptr::null(),
&RawWakerVTable::new(|_| NoopWaker.into(), |_| (), |_| (), |_| ()),
)
}
}
impl From<NoopWaker> for Waker {
fn from(value: NoopWaker) -> Self {
unsafe { Waker::from_raw(value.into()) }
}
}
async fn delay(mut amt: usize) {
let amt = &mut amt; poll_fn(|cx| {
cx.waker().wake_by_ref();
match amt {
0 => Poll::Ready(()),
_ => {
*amt -= 1;
Poll::Pending
}
}
})
.await
}
let waker = Waker::from(NoopWaker);
let mut cx = Context::from_waker(&waker);
let mut fut = pin!(<InlineDynFuture<u32, 1024, 16>>::new(async {
delay(3).await;
42
}));
assert_matches!(fut.as_mut().poll(&mut cx), Poll::Pending);
assert_matches!(fut.as_mut().poll(&mut cx), Poll::Pending);
assert_matches!(fut.as_mut().poll(&mut cx), Poll::Pending);
assert_matches!(fut.as_mut().poll(&mut cx), Poll::Ready(42));
}
}