use core::alloc::Layout;
use core::marker::PhantomData;
use core::ptr::NonNull;
use crate::constructor::{Construct, Opaque, PinConstruct, Slot};
use crate::receiver::Receiver;
#[must_use = "constructor must be initialized"]
pub struct Fn<Args, Ret: ?Sized> {
layout: Layout,
init: unsafe fn(Slot, Args) -> &mut Opaque<Ret>,
args: Args,
}
unsafe impl<Args, Ret: ?Sized> PinConstruct for Fn<Args, Ret> {
type Object = Ret;
unsafe fn construct(self, slot: Slot) -> NonNull<Self::Object> {
let ptr = (self.init)(slot, self.args);
NonNull::from(ptr.as_mut())
}
fn layout(&self) -> Layout {
self.layout
}
}
unsafe impl<Args, Ret: ?Sized> Construct for Fn<Args, Ret> {}
pub struct MustNotBeClosure;
#[inline(always)]
pub unsafe fn from_bare_fn<F, Args, Ret>(
_: fn(MustNotBeClosure) -> F,
args: Args,
init: unsafe fn(Slot, Args) -> &mut Opaque<Ret>,
) -> Fn<Args, Ret>
where
F: Function<Args>,
Ret: ?Sized,
{
Fn {
layout: Layout::new::<F::Ret>(),
init,
args,
}
}
#[inline(always)]
pub unsafe fn from_method<F, Args, Ret>(
_: fn(MustNotBeClosure) -> F,
args: Args,
init: unsafe fn(Slot, F::SealedArgs) -> &mut Opaque<Ret>,
) -> Fn<F::SealedArgs, Ret>
where
F: Method<Args>,
Ret: ?Sized,
{
pub struct MethodAsBareFn<Args, F>(PhantomData<(fn(Args), F)>);
impl<Args, F> Function<F::SealedArgs> for MethodAsBareFn<Args, F>
where
F: Method<Args>,
{
type Ret = F::Ret;
}
let args = F::seal_args(args);
from_bare_fn(|_| MethodAsBareFn::<Args, F>(PhantomData), args, init)
}
pub trait Function<Args> {
type Ret;
}
pub trait Method<Args>: Function<Args> {
type SealedArgs;
fn seal_args(args: Args) -> Self::SealedArgs;
}
macro_rules! impl_function {
(-> $R:ident) => {
impl<Fn: FnOnce() -> $R, $R> Function<()> for Fn {
type Ret = $R;
}
};
($A:ident $(,$Args:ident)* -> $R:ident) => {
impl<Fn, $A, $($Args,)* $R> Function<($A, $($Args,)*)> for Fn
where
Fn: FnOnce($A, $($Args,)*) -> $R,
{
type Ret = $R;
}
impl<Fn, $A, $($Args,)* $R> Method<($A, $($Args,)*)> for Fn
where
$A: Receiver,
Fn: FnOnce($A, $($Args,)*) -> $R,
{
type SealedArgs = (<$A as Receiver>::Sealed, $($Args,)*);
#[allow(non_snake_case)]
#[inline(always)]
fn seal_args(($A, $($Args,)*): ($A, $($Args,)*)) -> Self::SealedArgs {
(Receiver::seal($A), $($Args,)*)
}
}
impl_function!($($Args),* -> $R);
};
}
impl_function!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P -> R);
doc_macro! {
#[macro_export]
macro from_fn {
($f:expr, $self:ident $(,$args:ident)*) => {};
($f:expr $(,$args:ident)*) => {};
} {
($f:expr, $self:ident $(,$args:ident)* $(,)?) => { $crate::__from_fn!([$self] $f, $self, $($args,)*) };
($f:expr $(,$args:ident)* $(,)?) => { $crate::__from_fn!([] $f, $($args,)*) };
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __from_fn {
([self] $f:expr, $self:ident, $($args:ident,)*) => {
unsafe {
$crate::r#priv::from_method(
|_| $f,
($self, $($args,)*),
|slot, (this, $($args,)*)| {
let this = $crate::r#priv::Receiver::unseal(this);
let return_value = ($f)(this, $($args,)*);
let object = slot.cast().write(return_value);
object as &mut $crate::Opaque::<_>
},
)
}
};
([$($_:ident)?] $f:expr, $($args:ident,)*) => {
unsafe {
$crate::r#priv::from_bare_fn(
|_| $f,
($($args,)*),
|slot, ($($args,)*)| {
let return_value = ($f)($($args,)*);
let object = slot.cast().write(return_value);
object as &mut $crate::Opaque::<_>
},
)
}
};
}
doc_macro! {
#[macro_export]
macro Fn {
(_ => $ret:ty) => {};
($Self:ty $(,$args:ty)* => $ret:ty) => {};
($($args:ty),* => $ret:ty) => {};
} {
(_ => $ret:ty) => { $crate::r#priv::Fn<_, $ret> };
($($args:tt)*) => { $crate::__Fn!($($args)*) };
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __Fn {
(&$($lt:lifetime)? Self $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::RefSelf$(<$lt>)*, $($args,)*), $ret> };
(&$($lt:lifetime)? mut Self $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::RefMutSelf$(<$lt>)*, $($args,)*), $ret> };
(Box<Self> $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::BoxSelf, $($args,)*), $ret> };
(Rc<Self> $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::RcSelf, $($args,)*), $ret> };
(Arc<Self> $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::ArcSelf, $($args,)*), $ret> };
(Pin<&$($lt:lifetime)? Self> $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::PinRefSelf$(<$lt>)*, $($args,)*), $ret> };
(Pin<&$($lt:lifetime)? mut Self> $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::PinRefMutSelf$(<$lt>)*, $($args,)*), $ret> };
(Pin<Box<Self>> $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::PinBoxSelf, $($args,)*), $ret> };
(Pin<Rc<Self>> $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::PinRcSelf, $($args,)*), $ret> };
(Pin<Arc<Self>> $(,$args:ty)* => $ret:ty) => { $crate::r#priv::Fn<($crate::r#priv::PinArcSelf, $($args,)*), $ret> };
($($args:ty),* => $ret:ty) => { $crate::r#priv::Fn<($($args,)*), $ret> };
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
#[path = "function_tests.rs"]
mod tests;