use crate::{relocation::RelocatablePtr, Object};
use paste::paste;
use std::marker::PhantomData;
use std::ops::Deref;
macro_rules! impl_fn {
(
impl[$($generic_bounds:tt)*] FnOnce<$args_ty:ty, Output = $output:ty> for $target:ty $(where[$($where:tt)*])? =
$(#[$attr:meta])*
|$self:tt, $args:tt| {
$($body:tt)*
}
) => {
#[cfg(feature = "nightly")]
impl<$($generic_bounds)*> std::ops::FnOnce<$args_ty> for $target $(where $($where)*)? {
type Output = $output;
$(#[$attr])*
#[allow(unused_mut)]
extern "rust-call" fn call_once(mut $self, $args: $args_ty) -> Self::Output {
$($body)*
}
}
#[cfg(not(feature = "nightly"))]
impl<$($generic_bounds)*> FnOnceObject<$args_ty> for $target $(where $($where)*)? {
type Output = $output;
$(#[$attr])*
#[allow(unused_mut)]
fn call_object_once(mut $self, $args: $args_ty) -> Self::Output {
$($body)*
}
fn call_object_box(self: Box<Self>, args: $args_ty) -> Self::Output {
(*self).call_object_once(args)
}
}
};
(
impl[$($generic_bounds:tt)*] FnMut<$args_ty:ty> for $target:ty $(where[$($where:tt)*])? =
$(#[$attr:meta])*
|$self:tt, $args:tt| {
$($body:tt)*
}
) => {
#[cfg(feature = "nightly")]
impl<$($generic_bounds)*> std::ops::FnMut<$args_ty> for $target $(where $($where)*)? {
$(#[$attr])*
extern "rust-call" fn call_mut(&mut $self, $args: $args_ty) -> Self::Output {
$($body)*
}
}
#[cfg(not(feature = "nightly"))]
impl<$($generic_bounds)*> FnMutObject<$args_ty> for $target $(where $($where)*)? {
$(#[$attr])*
fn call_object_mut(&mut $self, $args: $args_ty) -> Self::Output {
$($body)*
}
}
};
(
impl[$($generic_bounds:tt)*] Fn<$args_ty:ty> for $target:ty $(where[$($where:tt)*])?=
$(#[$attr:meta])*
|$self:tt, $args:tt| {
$($body:tt)*
}
) => {
#[cfg(feature = "nightly")]
impl<$($generic_bounds)*> std::ops::Fn<$args_ty> for $target $(where $($where)*)? {
$(#[$attr])*
extern "rust-call" fn call(&$self, $args: $args_ty) -> Self::Output {
$($body)*
}
}
#[cfg(not(feature = "nightly"))]
impl<$($generic_bounds)*> FnObject<$args_ty> for $target $(where $($where)*)? {
$(#[$attr])*
fn call_object(&$self, $args: $args_ty) -> Self::Output {
$($body)*
}
}
};
}
#[allow(missing_debug_implementations)]
#[doc(hidden)]
#[derive(Object)]
pub struct CallWrapper<T: Object>(pub T);
#[cfg(feature = "nightly")]
pub trait Tuple: std::marker::Tuple {}
#[cfg(feature = "nightly")]
impl<T: std::marker::Tuple> Tuple for T {}
#[cfg(not(feature = "nightly"))]
mod private {
pub trait Sealed {}
}
#[cfg(not(feature = "nightly"))]
pub trait Tuple: private::Sealed {}
#[cfg(not(feature = "nightly"))]
macro_rules! decl_tuple {
() => {};
($head:tt $($tail:tt)*) => {
impl<$($tail),*> private::Sealed for ($($tail,)*) {}
impl<$($tail),*> Tuple for ($($tail,)*) {}
decl_tuple!($($tail)*);
};
}
#[cfg(not(feature = "nightly"))]
decl_tuple!(x T20 T19 T18 T17 T16 T15 T14 T13 T12 T11 T10 T9 T8 T7 T6 T5 T4 T3 T2 T1 T0);
impl<T: Object> Deref for CallWrapper<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
#[doc(hidden)]
pub trait InternalFnOnce<Args>: Object {
type Output;
fn call_object_once(self, args: Args) -> Self::Output;
}
impl_fn! {
impl[Args: Tuple, T: InternalFnOnce<Args>] FnOnce<Args, Output = T::Output> for CallWrapper<T> =
|self, args| {
self.0.call_object_once(args)
}
}
#[doc(hidden)]
pub trait InternalFnMut<Args>: InternalFnOnce<Args> {
fn call_object_mut(&mut self, args: Args) -> Self::Output;
}
impl_fn! {
impl[Args: Tuple, T: InternalFnMut<Args>] FnMut<Args> for CallWrapper<T> = |self, args| {
self.0.call_object_mut(args)
}
}
#[doc(hidden)]
pub trait InternalFn<Args>: InternalFnMut<Args> {
fn call_object(&self, args: Args) -> Self::Output;
}
impl_fn! {
impl[Args: Tuple, T: InternalFn<Args>] Fn<Args> for CallWrapper<T> = |self, args| {
self.0.call_object(args)
}
}
#[cfg(not(feature = "nightly"))]
pub trait FnOnceObject<Args: Tuple>: Object {
type Output;
fn call_object_once(self, args: Args) -> Self::Output;
fn call_object_box(self: Box<Self>, args: Args) -> Self::Output;
}
#[cfg(feature = "nightly")]
pub trait FnOnceObject<Args: Tuple>: Object + std::ops::FnOnce<Args> {
fn call_object_once(self, args: Args) -> Self::Output;
fn call_object_box(self: Box<Self>, args: Args) -> Self::Output;
}
#[cfg(not(feature = "nightly"))]
impl<Args: Tuple, T: FnOnceObject<Args> + ?Sized> FnOnceObject<Args> for Box<T>
where
Box<T>: Object,
{
type Output = T::Output;
fn call_object_once(self, args: Args) -> Self::Output {
self.call_object_box(args)
}
fn call_object_box(self: Box<Self>, args: Args) -> Self::Output {
(*self).call_object_once(args)
}
}
#[cfg(feature = "nightly")]
impl<Args: Tuple, T: Object + std::ops::FnOnce<Args>> FnOnceObject<Args> for T {
fn call_object_once(self, args: Args) -> Self::Output {
self.call_once(args)
}
fn call_object_box(self: Box<Self>, args: Args) -> Self::Output {
self.call_once(args)
}
}
#[cfg(feature = "nightly")]
pub trait FnMutObject<Args: Tuple>: FnOnceObject<Args> + std::ops::FnMut<Args> {
fn call_object_mut(&mut self, args: Args) -> Self::Output;
}
#[cfg(not(feature = "nightly"))]
pub trait FnMutObject<Args: Tuple>: FnOnceObject<Args> {
fn call_object_mut(&mut self, args: Args) -> Self::Output;
}
#[cfg(feature = "nightly")]
impl<Args: Tuple, T: Object + std::ops::FnMut<Args>> FnMutObject<Args> for T {
fn call_object_mut(&mut self, args: Args) -> Self::Output {
self.call_mut(args)
}
}
#[cfg(feature = "nightly")]
pub trait FnObject<Args: Tuple>: FnMutObject<Args> + std::ops::Fn<Args> {
fn call_object(&self, args: Args) -> Self::Output;
}
#[cfg(not(feature = "nightly"))]
pub trait FnObject<Args: Tuple>: FnMutObject<Args> {
fn call_object(&self, args: Args) -> Self::Output;
}
#[cfg(feature = "nightly")]
impl<Args: Tuple, T: Object + std::ops::Fn<Args>> FnObject<Args> for T {
fn call_object(&self, args: Args) -> Self::Output {
self.call(args)
}
}
#[doc(hidden)]
pub trait BindValue<Head: Object, Tail>: Object + Sized {
fn bind_value(self, head: Head) -> BoundValue<Self, Head>;
}
#[doc(hidden)]
pub trait BindMut<Head: Object, Tail>: Object + Sized {
fn bind_mut(self, head: Head) -> BoundMut<Self, Head>;
}
#[doc(hidden)]
pub trait BindRef<Head: Object, Tail>: Object + Sized {
fn bind_ref(self, head: Head) -> BoundRef<Self, Head>;
}
#[allow(missing_debug_implementations)]
#[doc(hidden)]
#[derive(Object)]
pub struct BoundValue<Func: Object, Head: Object> {
pub func: Func,
pub head: Head,
}
#[allow(missing_debug_implementations)]
#[doc(hidden)]
#[derive(Object)]
pub struct BoundMut<Func: Object, Head: Object> {
pub func: Func,
pub head: Head,
}
#[allow(missing_debug_implementations)]
#[doc(hidden)]
#[derive(Object)]
pub struct BoundRef<Func: Object, Head: Object> {
pub func: Func,
pub head: Head,
}
macro_rules! reverse {
([$($acc:tt)*]) => { ($($acc)*) };
([$($acc:tt)*] $single:tt) => { reverse!([$single, $($acc)*]) };
([$($acc:tt)*] $head:tt, $($tail:tt),*) => { reverse!([$head, $($acc)*] $($tail),*) };
}
macro_rules! decl_fn {
() => {};
($head:tt $($tail:tt)*) => {
decl_fn!($($tail)*);
paste! {
impl<[<T $head>]: Object $(, [<T $tail>])*, Func: FnOnceObject<([<T $head>], $([<T $tail>]),*)>> BindValue<[<T $head>], ($([<T $tail>],)*)> for Func {
fn bind_value(self, head: [<T $head>]) -> BoundValue<Self, [<T $head>]> {
BoundValue {
func: self,
head,
}
}
}
impl<'a, [<T $head>]: 'a + Object $(, [<T $tail>])*, Func: FnOnceObject<(&'a mut [<T $head>], $([<T $tail>]),*)>> BindMut<[<T $head>], ($([<T $tail>],)*)> for Func {
fn bind_mut(self, head: [<T $head>]) -> BoundMut<Self, [<T $head>]> {
BoundMut {
func: self,
head,
}
}
}
impl<'a, [<T $head>]: 'a + Object $(, [<T $tail>])*, Func: FnOnceObject<(&'a [<T $head>], $([<T $tail>]),*)>> BindRef<[<T $head>], ($([<T $tail>],)*)> for Func {
fn bind_ref(self, head: [<T $head>]) -> BoundRef<Self, [<T $head>]> {
BoundRef {
func: self,
head,
}
}
}
impl_fn! {
impl[[<T $head>]: Object $(, [<T $tail>])*, Func: FnOnceObject<([<T $head>], $([<T $tail>]),*)>] FnOnce<($([<T $tail>],)*), Output = Func::Output> for BoundValue<Func, [<T $head>]> =
#[allow(unused_variables)]
|self, args| {
self.func.call_object_once(reverse!([] $((args.$tail),)* (self.head)))
}
}
impl_fn! {
impl[[<T $head>]: Copy + Object $(, [<T $tail>])*, Func: FnMutObject<([<T $head>], $([<T $tail>]),*)>] FnMut<($([<T $tail>],)*)> for BoundValue<Func, [<T $head>]> =
#[allow(unused_variables)]
|self, args| {
self.func.call_object_mut(reverse!([] $((args.$tail),)* (self.head)))
}
}
impl_fn! {
impl[[<T $head>]: Copy + Object $(, [<T $tail>])*, Func: FnObject<([<T $head>], $([<T $tail>]),*)>] Fn<($([<T $tail>],)*)> for BoundValue<Func, [<T $head>]> =
#[allow(unused_variables)]
|self, args| {
self.func.call_object(reverse!([] $((args.$tail),)* (self.head)))
}
}
impl_fn! {
impl[[<T $head>]: Object $(, [<T $tail>])*, Output, Func: for<'a> FnOnceObject<(&'a mut [<T $head>], $([<T $tail>]),*), Output = Output>] FnOnce<($([<T $tail>],)*), Output = Output> for BoundMut<Func, [<T $head>]> =
#[allow(unused_variables)]
|self, args| {
self.func.call_object_once(reverse!([] $((args.$tail),)* (&mut self.head)))
}
}
impl_fn! {
impl[[<T $head>]: Object $(, [<T $tail>])*, Output, Func: for<'a> FnMutObject<(&'a mut [<T $head>], $([<T $tail>]),*), Output = Output>] FnMut<($([<T $tail>],)*)> for BoundMut<Func, [<T $head>]> =
#[allow(unused_variables)]
|self, args| {
self.func.call_object_mut(reverse!([] $((args.$tail),)* (&mut self.head)))
}
}
impl_fn! {
impl[[<T $head>]: Object $(, [<T $tail>])*, Output, Func: for<'a> FnOnceObject<(&'a [<T $head>], $([<T $tail>]),*), Output = Output>] FnOnce<($([<T $tail>],)*), Output = Output> for BoundRef<Func, [<T $head>]> =
#[allow(unused_variables)]
|self, args| {
self.func.call_object_once(reverse!([] $((args.$tail),)* (&self.head)))
}
}
impl_fn! {
impl[[<T $head>]: Object $(, [<T $tail>])*, Output, Func: for<'a> FnMutObject<(&'a [<T $head>], $([<T $tail>]),*), Output = Output>] FnMut<($([<T $tail>],)*)> for BoundRef<Func, [<T $head>]> =
#[allow(unused_variables)]
|self, args| {
self.func.call_object_mut(reverse!([] $((args.$tail),)* (&self.head)))
}
}
impl_fn! {
impl[[<T $head>]: Object $(, [<T $tail>])*, Output, Func: for<'a> FnObject<(&'a [<T $head>], $([<T $tail>]),*), Output = Output>] Fn<($([<T $tail>],)*)> for BoundRef<Func, [<T $head>]> =
#[allow(unused_variables)]
|self, args| {
self.func.call_object(reverse!([] $((args.$tail),)* (&self.head)))
}
}
}
}
}
decl_fn!(x 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0);
#[macro_export]
macro_rules! lambda {
(|| $($items:tt)*) => {
$crate::lambda_parse! {
[],
[_unnamed],
| $($items)*
}
};
(|$($items:tt)*) => {
$crate::lambda_parse! {
[],
[_unnamed],
$($items)*
}
};
(move($($moved_vars:tt)*) || $($items:tt)*) => {
$crate::lambda_parse! {
[],
[
$crate::lambda_bind! { [_unnamed], $($moved_vars)* }
],
$($moved_vars)*, | $($items)*
}
};
(move($($moved_vars:tt)*) |$($items:tt)*) => {
$crate::lambda_parse! {
[],
[
$crate::lambda_bind! { [_unnamed], $($moved_vars)* }
],
$($moved_vars)*, $($items)*
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! lambda_parse {
(
[$($args:tt)*],
[$($append:tt)*],
, $($rest:tt)*
) => {
$crate::lambda_parse! { [$($args)*], [$($append)*], $($rest)* }
};
(
[$($args:tt)*],
[$($append:tt)*],
&mut $name:ident: $type:ty, $($rest:tt)*
) => {
$crate::lambda_parse! { [$($args)* $name: $type,], [$($append)*], $($rest)* }
};
(
[$($args:tt)*],
[$($append:tt)*],
$(&)? $name:ident: $type:ty, $($rest:tt)*
) => {
$crate::lambda_parse! { [$($args)* $name: $type,], [$($append)*], $($rest)* }
};
(
[$($args:tt)*],
[$($append:tt)*],
&mut $name:ident: $type:ty| $($rest:tt)*
) => {
$crate::lambda_parse! { [$($args)* $name: $type,], [$($append)*], |$($rest)* }
};
(
[$($args:tt)*],
[$($append:tt)*],
$(&)? $name:ident: $type:ty| $($rest:tt)*
) => {
$crate::lambda_parse! { [$($args)* $name: $type,], [$($append)*], |$($rest)* }
};
(
[$($args:tt)*],
[$($append:tt)*],
| -> $return_type:ty { $($code:tt)* }
) => {
{
#[$crate::func]
fn _unnamed($($args)*) -> $return_type {
$($code)*
}
{
#[allow(unused)]
use $crate::{BindValue, BindMut, BindRef};
::std::boxed::Box::new($($append)*)
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! lambda_bind {
([$($acc:tt)*],) => { $($acc)* };
([$($acc:tt)*], &mut $name:ident: $type:ty, $($rest:tt)*) => {
$crate::lambda_bind! { [$($acc)*.bind_mut($name)], $($rest)* }
};
([$($acc:tt)*], &mut $name:ident: $type:ty) => {
$($acc)*.bind_mut($name)
};
([$($acc:tt)*], &$name:ident: $type:ty, $($rest:tt)*) => {
$crate::lambda_bind! { [$($acc)*.bind_ref($name)], $($rest)* }
};
([$($acc:tt)*], &$name:ident: $type:ty) => {
$($acc)*.bind_ref($name)
};
([$($acc:tt)*], $name:ident: $type:ty, $($rest:tt)*) => {
$crate::lambda_bind! { [$($acc)*.bind_value($name)], $($rest)* }
};
([$($acc:tt)*], $name:ident: $type:ty) => {
$($acc)*.bind_value($name)
};
}
#[cfg(feature = "nightly")]
pub trait FnPtr: std::marker::FnPtr {}
#[cfg(feature = "nightly")]
impl<T: std::marker::FnPtr> FnPtr for T {}
#[cfg(not(feature = "nightly"))]
mod fn_ptr_private {
pub trait Sealed {}
}
#[cfg(not(feature = "nightly"))]
pub trait FnPtr: Copy + Clone + fn_ptr_private::Sealed {
fn addr(self) -> *const ();
}
#[derive(Clone, Copy, Debug, Object)]
pub struct StaticFn<F: FnPtr> {
ptr: RelocatablePtr<()>,
phantom: PhantomData<F>,
}
impl<F: FnPtr> StaticFn<F> {
pub unsafe fn new(f: F) -> Self {
Self {
ptr: RelocatablePtr(f.addr()),
phantom: PhantomData,
}
}
pub fn get_fn(self) -> F {
unsafe { std::mem::transmute_copy::<*const (), F>(&self.ptr.0) }
}
const _F_IS_POINTER_SIZED: () = assert!(
std::mem::size_of::<*const ()>() == std::mem::size_of::<F>(),
"An instance of FnPtr has a size not equal to the size of *const (). This should have \
been impossible."
);
}
macro_rules! impl_fn_pointer {
() => {};
($head:tt $($tail:tt)*) => {
paste! {
#[cfg(not(feature = "nightly"))]
impl<Output, $([<T $tail>]),*> fn_ptr_private::Sealed for fn($([<T $tail>]),*) -> Output {}
#[cfg(not(feature = "nightly"))]
impl<Output, $([<T $tail>]),*> FnPtr for fn($([<T $tail>]),*) -> Output {
fn addr(self) -> *const () {
self as *const ()
}
}
#[cfg(not(feature = "nightly"))]
impl<Output, $([<T $tail>]),*> fn_ptr_private::Sealed for unsafe fn($([<T $tail>]),*) -> Output {}
#[cfg(not(feature = "nightly"))]
impl<Output, $([<T $tail>]),*> FnPtr for unsafe fn($([<T $tail>]),*) -> Output {
fn addr(self) -> *const () {
self as *const ()
}
}
impl_fn! {
impl[T: FnPtr, Output, $([<T $tail>]),*] FnOnce<($([<T $tail>],)*), Output = Output> for StaticFn<T> where[T: FnOnce($([<T $tail>]),*) -> Output] =
|self, args| {
let ($([<a $tail>],)*) = args;
self.get_fn()($([<a $tail>]),*)
}
}
impl_fn! {
impl[T: FnPtr, Output, $([<T $tail>]),*] FnMut<($([<T $tail>],)*)> for StaticFn<T> where[T: FnMut($([<T $tail>]),*) -> Output] =
|self, args| {
let ($([<a $tail>],)*) = args;
self.get_fn()($([<a $tail>]),*)
}
}
impl_fn! {
impl[T: FnPtr, Output, $([<T $tail>]),*] Fn<($([<T $tail>],)*)> for StaticFn<T> where[T: Fn($([<T $tail>]),*) -> Output] =
|self, args| {
let ($([<a $tail>],)*) = args;
self.get_fn()($([<a $tail>]),*)
}
}
}
impl_fn_pointer!($($tail)*);
};
}
impl_fn_pointer!(x 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0);