use std::mem;
use rstest::rstest;
use crate::utils::*;
use crate::{from_closure, Dynify, Emplace, PinDynify};
struct UnsafePinnedContainer<C>(C);
unsafe impl<T, D> Emplace<T> for UnsafePinnedContainer<D>
where
T: ?Sized,
D: Emplace<T>,
{
type Ptr = D::Ptr;
type Err = D::Err;
fn emplace<C>(self, constructor: C) -> Result<Self::Ptr, Self::Err>
where
C: crate::Construct<Object = T>,
{
self.0.emplace(constructor)
}
}
unsafe impl<T, C> crate::PinEmplace<T> for UnsafePinnedContainer<C>
where
T: ?Sized,
C: Emplace<T>,
{
}
impl<C: ?Sized> UnsafePinnedContainer<&'_ mut C> {
fn as_mut(&mut self) -> UnsafePinnedContainer<&mut C> {
UnsafePinnedContainer(self.0)
}
}
#[rstest]
#[case(0, randarr::<0>())]
#[case(1, randarr::<0>())]
#[case(4, randarr::<4>())]
#[case(7, randarr::<5>())]
fn init_ok<const N: usize>(#[case] stk_size: usize, #[case] data: [u8; N]) {
let mut stk = newheap_fixed(stk_size);
let init = from_closure(|slot| slot.write(data) as &mut OpqAny);
let out = init.init(&mut *stk);
assert_eq!(out.downcast_ref::<[u8; N]>(), Some(&data));
drop(out);
let mut stk = UnsafePinnedContainer(&mut *stk);
let init = from_closure(|slot| slot.write(data) as &mut OpqAny);
let out = init.pin_init(stk.as_mut());
assert_eq!(out.downcast_ref::<[u8; N]>(), Some(&data));
}
#[rstest]
#[case(0, 4, randarr::<4>())]
#[case(4, 5, randarr::<5>())]
#[case(0, 8, randarr::<6>())]
#[case(6, 9, randarr::<7>())]
fn init2_ok<const N: usize>(
#[case] stk1_size: usize,
#[case] stk2_size: usize,
#[case] data: [u8; N],
) {
let mut stk1 = newheap_fixed(stk1_size);
let mut stk2 = newheap_fixed(stk2_size);
let mut init = from_closure(|slot| slot.write(data) as &mut OpqAny);
(init, _) = init.try_init(&mut *stk1).unwrap_err();
let out = init.init2(&mut *stk1, &mut *stk2);
assert_eq!(out.downcast_ref::<[u8; N]>(), Some(&data));
drop(out);
let mut stk1 = UnsafePinnedContainer(&mut *stk1);
let mut stk2 = UnsafePinnedContainer(&mut *stk2);
let mut init = from_closure(|slot| slot.write(data) as &mut OpqAny);
(init, _) = init.try_pin_init(stk1.as_mut()).unwrap_err();
let out = init.pin_init2(stk1.as_mut(), stk2.as_mut());
assert_eq!(out.downcast_ref::<[u8; N]>(), Some(&data));
}
#[rstest]
#[case(0, 0, randarr::<7>())]
#[case(6, 0, randarr::<7>())]
#[case(0, 8, randarr::<9>())]
#[case(7, 8, randarr::<9>())]
#[should_panic = "failed to initialize"]
fn panic_on_init_fail(
#[case] stk1_size: usize,
#[case] stk2_size: usize,
#[case] val: impl DebugAny,
) {
let mut stk1 = newheap_fixed(stk1_size);
let mut stk2 = newheap_fixed(stk2_size);
let init = from_closure(|slot| slot.write(val));
if stk2_size == 0 {
init.init(&mut *stk1);
} else {
init.init2(&mut *stk1, &mut *stk2);
}
}
#[rstest]
#[case(0, 0, randarr::<7>())]
#[case(6, 0, randarr::<7>())]
#[case(0, 8, randarr::<9>())]
#[case(7, 8, randarr::<9>())]
#[should_panic = "failed to initialize"]
fn panic_on_pin_init_fail(
#[case] stk1_size: usize,
#[case] stk2_size: usize,
#[case] val: impl DebugAny,
) {
let mut stk1 = newheap_fixed(stk1_size);
let mut stk1 = UnsafePinnedContainer(&mut *stk1);
let mut stk2 = newheap_fixed(stk2_size);
let mut stk2 = UnsafePinnedContainer(&mut *stk2);
let init = from_closure(|slot| slot.write(val));
if stk2_size == 0 {
init.init(stk1.as_mut());
} else {
init.init2(stk1.as_mut(), stk2.as_mut());
}
}
#[test]
fn drop_boxed() {
assert_eq!(DropCounter::count(), 0);
let init = from_closure(|slot| slot.write(DropCounter) as &mut OpqAny);
drop(init.boxed());
assert_eq!(DropCounter::count(), 1);
let init = from_closure(|slot| slot.write(DropCounter) as &mut OpqAny);
drop(init.pin_boxed());
assert_eq!(DropCounter::count(), 2);
}
#[rstest]
#[case(randarr::<4>())]
#[case(randarr::<8>())]
#[case(randarr::<16>())]
#[case(randarr::<32>())]
fn fallible_constructor(#[case] val: impl DebugAny) {
use crate::utils::newstk;
let mut stack = newstk::<8>();
let mut heap = newheap(0);
let val_size = mem::size_of_val(&val);
let mut init = Some(from_closure(|slot| slot.write(val)));
let init = &mut init;
if val_size <= stack.len() {
assert!(init.try_init(&mut stack).is_ok());
} else {
assert!(init.try_init(&mut stack).is_err());
assert!(init.try_init2(&mut stack, &mut heap).is_ok());
}
}