use alloc::boxed::Box;
use core::alloc::AllocError;
use core::alloc::Allocator;
use core::alloc::Layout;
use core::marker::Tuple;
use core::ptr::NonNull;
use crate::InplaceBox;
impl<Args: Tuple, F: FnOnce<Args> + ?Sized, const SIZE: usize> FnOnce<Args>
for InplaceBox<F, SIZE>
{
type Output = <F as FnOnce<Args>>::Output;
#[inline]
extern "rust-call" fn call_once(mut self, args: Args) -> Self::Output {
let b = unsafe {
Box::from_raw_in(self.as_mut(), InplaceBoxFnOnceDummyAllocator)
};
core::mem::forget(self); <Box<_, _> as FnOnce<Args>>::call_once(b, args)
}
}
struct InplaceBoxFnOnceDummyAllocator;
unsafe impl Allocator for InplaceBoxFnOnceDummyAllocator {
#[inline]
fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
Err(AllocError) }
#[inline]
unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
}
}
impl<Args: Tuple, F: FnMut<Args> + ?Sized, const SIZE: usize> FnMut<Args>
for InplaceBox<F, SIZE>
{
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
<F as FnMut<Args>>::call_mut(self, args)
}
}
impl<Args: Tuple, F: Fn<Args> + ?Sized, const SIZE: usize> Fn<Args>
for InplaceBox<F, SIZE>
{
extern "rust-call" fn call(&self, args: Args) -> Self::Output {
<F as Fn<Args>>::call(self, args)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fn_once() {
let mut counter = 1;
let adder: InplaceBox<dyn FnOnce<(usize,), Output = usize>, 32> =
InplaceBox::new(|count| {
let res = counter;
counter = res + count;
res
});
let prev_value = adder(4);
assert_eq!(prev_value, 1);
assert_eq!(5, counter);
}
#[test]
fn fn_once_drop_or_call() {
struct Guard<'a>(&'a mut bool);
impl Drop for Guard<'_> {
fn drop(&mut self) {
*self.0 = true;
}
}
let mut called = false;
let mut dropped = false;
{
let called = &mut called;
let guard = Guard(&mut dropped);
let b: InplaceBox<dyn FnOnce(), 32> = InplaceBox::new(move || {
*called = true;
core::mem::forget(guard);
});
drop(b); }
assert!(!called);
assert!(dropped);
called = false;
dropped = false;
{
let called = &mut called;
let guard = Guard(&mut dropped);
let b: InplaceBox<dyn FnOnce<(), Output = ()>, 32> =
InplaceBox::new(move || {
*called = true;
core::mem::forget(guard);
});
b(); }
assert!(called);
assert!(!dropped);
}
}