use std::any::Any;
use std::marker::PhantomPinned;
use std::pin::pin;
use rstest::rstest;
#[cfg(feature = "smallvec")]
use smallvec::SmallVec;
use super::*;
use crate::utils::*;
use crate::{from_closure, Dynify, Opaque};
trait DebugEmplace: Emplace<dyn Any, Err = Self::__Err> {
type __Err: std::fmt::Debug;
}
impl<C> DebugEmplace for C
where
C: Emplace<dyn Any>,
C::Err: std::fmt::Debug,
{
type __Err = C::Err;
}
#[rstest]
#[case(&mut MaybeUninit::<[u8; 12]>::uninit())]
#[case(&mut [MaybeUninit::new(0u8); 12])]
#[case(&mut [MaybeUninit::new(0u8); 12] as &mut [MaybeUninit<u8>])]
fn fix_sized_containers<C>(#[case] c: &mut C)
where
C: ?Sized,
for<'a> &'a mut C: DebugEmplace,
{
let inp = randarr::<8>();
let init = from_closure(|slot| slot.write(inp) as &mut OpqAny);
let out = c.emplace(init).unwrap();
assert_eq!(out.downcast_ref::<[u8; 8]>(), Some(&inp), "init ok");
drop(out);
let inp = randarr::<14>();
let init = from_closure(|slot| slot.write(inp) as &mut OpqAny);
assert!(c.emplace(init).is_err(), "init err");
}
#[rstest]
#[case(Boxed)]
#[case(&mut Vec::<MaybeUninit<u8>>::new())]
#[cfg_attr(feature = "smallvec", case(&mut SmallVec::<[MaybeUninit<u8>; 0]>::new()) )]
#[cfg_attr(feature = "smallvec", case(&mut SmallVec::<[MaybeUninit<u8>; 12]>::new()) )]
fn allocated_containers(#[case] c: impl DebugEmplace) {
let inp = randarr::<16>();
let init = from_closure(|slot| slot.write(inp) as &mut OpqAny);
let out = c.emplace(init).unwrap();
assert_eq!(out.downcast_ref::<[u8; 16]>(), Some(&inp));
}
#[rstest]
#[case(Boxed)]
#[case(&mut [MaybeUninit::new(0u8); 64])]
#[case(&mut [MaybeUninit::uninit(); 64] as &mut [MaybeUninit<u8>])]
#[case(&mut Vec::<MaybeUninit<u8>>::new())]
#[cfg_attr(feature = "smallvec", case(&mut SmallVec::<[MaybeUninit<u8>; 0]>::new()) )]
#[cfg_attr(feature = "smallvec", case(&mut SmallVec::<[MaybeUninit<u8>; 12]>::new()) )]
fn init_object_of_random_layout(#[case] c: impl DebugEmplace) {
macro_rules! select_layout {
($rand:ident, $($align:literal),+) => {$(
if $rand == $align {
#[repr(align($align))]
struct Test<T>(T);
let inp = randarr::<16>();
let init = from_closure(|slot| slot.write(Test(inp)) as &mut OpqAny);
let out = c.emplace(init).unwrap();
let out = out.downcast_ref::<Test<[u8; 16]>>().unwrap();
assert_eq!(&out.0, &inp);
return;
}
)*};
}
let rand = 1 << fastrand::usize(..6);
select_layout!(rand, 1, 2, 4, 8, 16, 32);
unreachable!();
}
#[rstest]
#[case(Boxed)]
#[case(&mut Vec::<MaybeUninit<u8>>::new())]
#[case(&mut [] as &mut [MaybeUninit<u8>])]
#[case(&mut [] as &mut [MaybeUninit<u8>; 0])]
#[cfg_attr(feature = "smallvec", case(&mut SmallVec::<[MaybeUninit<u8>; 0]>::new()) )]
#[cfg_attr(feature = "smallvec", case(&mut SmallVec::<[MaybeUninit<u8>; 12]>::new()) )]
fn never_fail_on_zst(#[case] c: impl DebugEmplace) {
#[repr(align(4096))]
struct Zst;
let init = from_closure(|slot| slot.write(Zst) as &mut OpqAny);
let out = c.emplace(init).unwrap();
let out = out.downcast_ref::<Zst>().unwrap();
assert!(std::ptr::from_ref(out).is_aligned());
}
#[rstest]
#[case(&mut newstk::<24>())]
#[case(&mut newstk::<24>() as &mut [MaybeUninit<u8>])]
#[case(&mut Vec::<MaybeUninit<u8>>::new())]
#[cfg_attr(feature = "smallvec", case(&mut SmallVec::<[MaybeUninit<u8>; 0]>::new()) )]
#[cfg_attr(feature = "smallvec", case(&mut SmallVec::<[MaybeUninit<u8>; 12]>::new()) )]
fn drop_buffered<'a>(#[case] c: impl 'a + DebugEmplace<Ptr = Buffered<'a, dyn Any>>) {
let init = from_closure(|slot| slot.write(DropCounter) as &mut OpqAny);
let out = c.emplace(init).unwrap();
assert_eq!(DropCounter::count(), 0);
drop(out);
assert_eq!(DropCounter::count(), 1);
}
#[test]
fn unpin_buffered() {
let mut stack = newstk::<16>();
let init = from_closure(|slot| slot.write(123));
let val: Pin<&mut Buffered<usize>> = pin!(init.init(&mut stack));
let _: &mut Buffered<usize> = Pin::into_inner(val);
}
#[test]
fn send_buffered() {
let mut stack = newstk::<16>();
let init = from_closure(|slot| slot.write(123));
let val: Buffered<usize> = init.init(&mut stack);
fn ensure_send(_: impl Send) {}
ensure_send(val);
}
#[test]
fn sync_buffered() {
let mut stack = newstk::<16>();
let init = from_closure(|slot| slot.write(123));
let val: Buffered<usize> = init.init(&mut stack);
fn ensure_sync(_: impl Sync) {}
ensure_sync(val);
}
#[test]
fn project_buffered() {
let mut stack = newstk::<16>();
let init = from_closure(|slot| slot.write(PhantomPinned));
let mut buf: Pin<&mut Buffered<PhantomPinned>> = pin!(init.init(&mut stack));
let _: Pin<&mut PhantomPinned> = buf.as_mut().project();
let _: Pin<&PhantomPinned> = buf.as_ref().project_ref();
}
#[test]
fn project_pinned_buffered() {
let mut stack = newstk::<16>();
let init = from_closure(|slot| slot.write(123));
let mut val: Pin<&mut Buffered<usize>> = pin!(init.init(&mut stack));
let _: Pin<&mut usize> = val.as_mut().project();
let _: Pin<&usize> = val.as_ref().project_ref();
}
#[pollster::test]
async fn buffered_future() {
let mut stack = newstk::<16>();
let inp = randstr(8..64);
let init = from_closure(|slot| slot.write(async { inp.clone() }) as &mut OpqStrFut);
let fut: Buffered<StrFut> = stack.emplace(init).unwrap();
let out = fut.await;
assert_eq!(out, inp);
}
#[test]
fn buffered_raw_ptr() {
let mut stack = newstk::<16>();
let stack_ptr = std::ptr::from_ref(&stack);
let init = from_closure(|slot| slot.write([0u8; 4]));
let val: Buffered<[u8; 4]> = stack.emplace(init).unwrap();
let val_ptr = val.into_raw().as_ptr();
assert_eq!(val_ptr as *const (), stack_ptr as *const ());
}
#[test]
fn default_pin_emplace() {
let inp = randarr::<16>();
let init = from_closure(|slot| slot.write(inp) as &mut OpqAny);
let out = Boxed.pin_emplace(init).unwrap();
assert_eq!(out.downcast_ref::<[u8; 16]>(), Some(&inp));
}
#[test]
#[should_panic = "just panic"]
fn clean_up_boxed_zst_on_panic() {
let _ = from_closure::<(), (), _>(|_| panic!("just panic")).boxed();
}
#[test]
#[should_panic = "just panic"]
fn clean_up_boxed_on_panic() {
let _ = from_closure::<usize, usize, _>(|_| panic!("just panic")).boxed();
}
#[rstest]
#[case(fastrand::i32(..))]
#[case(randstr(16..32))]
fn downcast_buffered<T>(#[case] data: T)
where
T: Any + Clone + core::fmt::Debug + Eq + Send + Sync,
{
struct Impossbile;
let mut stack = newstk::<32>();
let init = from_closure(|slot| slot.write(data.clone()) as &mut Opaque<dyn Any>);
let val = stack.emplace(init).unwrap();
let val = val.downcast::<Impossbile>().err().unwrap();
let val = val.downcast().ok().map(Buffered::into_inner);
assert_eq!(val, Some(data.clone()));
let init = from_closure(|slot| slot.write(data.clone()) as &mut Opaque<dyn Any + Send>);
let val = stack.emplace(init).unwrap();
let val = val.downcast::<Impossbile>().err().unwrap();
let val = val.downcast().ok().map(Buffered::into_inner);
assert_eq!(val, Some(data.clone()));
let init = from_closure(|slot| slot.write(data.clone()) as &mut Opaque<dyn Any + Send + Sync>);
let val = stack.emplace(init).unwrap();
let val = val.downcast::<Impossbile>().err().unwrap();
let val = val.downcast().ok().map(Buffered::into_inner);
assert_eq!(val, Some(data.clone()));
}