crossmist/fns.rs
1//! Utilities for passing function callbacks between processes.
2//!
3//! It is common to use callbacks to specialize function behavior. Capturing lambdas play an
4//! especially big role in this. They are, however, of complex opaque types that cannot be
5//! inspected. Therefore, passing lambdas is not just complicated because they would have to be of
6//! type `dyn Object + Fn() -> ()`, which Rust does not support at the moment, but downright
7//! impossible in case of captures.
8//!
9//! To fix the following code:
10//!
11//! ```compile_fail
12//! use crossmist::{func, main, Object};
13//!
14//! #[main]
15//! fn main() {
16//! let x = 7;
17//! println!("{}", go.run(5, Box::new(|y| x + y)).unwrap());
18//! }
19//!
20//! #[func]
21//! fn go(x: i32, f: Box<dyn Object + Fn(i32) -> i32>) -> i32 {
22//! f(x)
23//! }
24//! ```
25//!
26//! ...we have to use a macro, and also a different invocation syntax:
27//!
28//! ```rust
29//! use crossmist::{FnObject, func, lambda, main};
30//!
31//! #[main]
32//! fn main() {
33//! let x = 7;
34//! println!("{}", go.run(5, lambda! { move(x: i32) |y: i32| -> i32 { x + y } }).unwrap());
35//! }
36//!
37//! #[func]
38//! fn go(x: i32, f: Box<dyn FnObject<(i32,), Output = i32>>) -> i32 {
39//! f.call_object((x,))
40//! }
41//! ```
42//!
43//! The macro syntax is somewhat similar to that of capturing lambdas. `call_object` is similar to
44//! [`std::ops::Fn::call`]. If you're using nightly Rust, you can directly do `f(x)` if you opt in
45//! by enabling the `nightly` feature.
46//!
47//! Another complication is when the callback should capture a non-copyable value (e.g. [`Box`]) and
48//! then be called multiple times. This cannot be detected automatically, so slightly different
49//! syntax is used:
50//!
51//! ```rust
52//! use crossmist::{FnObject, func, lambda, main};
53//!
54//! #[main]
55//! fn main() {
56//! let x = Box::new(7);
57//! println!("{}", go.run(5, lambda! { move(&x: &Box<i32>) |y: i32| -> i32 { **x + y } }).unwrap());
58//! }
59//!
60//! #[func]
61//! fn go(x: i32, f: Box<dyn FnObject<(i32,), Output = i32>>) -> i32 {
62//! f.call_object((x,))
63//! }
64//! ```
65//!
66//! Similarly, `&mut x` can be used if the object is to be modified. Note that this still moves `x`
67//! into the lambda.
68//!
69//! Under the hood, the macro uses currying, replacing `|y| x + y` with `|x, y| x + y` with a
70//! pre-determined `x` variable, and makes `|x, y| x + y` a callable [`Object`] by using `#[func]`:
71//!
72//! ```rust
73//! use crossmist::{BindValue, FnObject, func, main};
74//!
75//! #[main]
76//! fn main() {
77//! #[func]
78//! fn add(x: i32, y: i32) -> i32 {
79//! x + y
80//! }
81//!
82//! let x = 7;
83//! println!("{}", go.run(5, Box::new(add.bind_value(x))).unwrap());
84//! }
85//!
86//! #[func]
87//! fn go(x: i32, f: Box<dyn FnObject<(i32,), Output = i32>>) -> i32 {
88//! f.call_object((x,))
89//! }
90//! ```
91
92use crate::{relocation::RelocatablePtr, Object};
93use paste::paste;
94use std::marker::PhantomData;
95use std::ops::Deref;
96
97macro_rules! impl_fn {
98 (
99 impl[$($generic_bounds:tt)*] FnOnce<$args_ty:ty, Output = $output:ty> for $target:ty $(where[$($where:tt)*])? =
100 $(#[$attr:meta])*
101 |$self:tt, $args:tt| {
102 $($body:tt)*
103 }
104 ) => {
105 #[cfg(feature = "nightly")]
106 impl<$($generic_bounds)*> std::ops::FnOnce<$args_ty> for $target $(where $($where)*)? {
107 type Output = $output;
108 $(#[$attr])*
109 #[allow(unused_mut)]
110 extern "rust-call" fn call_once(mut $self, $args: $args_ty) -> Self::Output {
111 $($body)*
112 }
113 }
114 #[cfg(not(feature = "nightly"))]
115 impl<$($generic_bounds)*> FnOnceObject<$args_ty> for $target $(where $($where)*)? {
116 type Output = $output;
117 $(#[$attr])*
118 #[allow(unused_mut)]
119 fn call_object_once(mut $self, $args: $args_ty) -> Self::Output {
120 $($body)*
121 }
122 fn call_object_box(self: Box<Self>, args: $args_ty) -> Self::Output {
123 (*self).call_object_once(args)
124 }
125 }
126 };
127
128 (
129 impl[$($generic_bounds:tt)*] FnMut<$args_ty:ty> for $target:ty $(where[$($where:tt)*])? =
130 $(#[$attr:meta])*
131 |$self:tt, $args:tt| {
132 $($body:tt)*
133 }
134 ) => {
135 #[cfg(feature = "nightly")]
136 impl<$($generic_bounds)*> std::ops::FnMut<$args_ty> for $target $(where $($where)*)? {
137 $(#[$attr])*
138 extern "rust-call" fn call_mut(&mut $self, $args: $args_ty) -> Self::Output {
139 $($body)*
140 }
141 }
142 #[cfg(not(feature = "nightly"))]
143 impl<$($generic_bounds)*> FnMutObject<$args_ty> for $target $(where $($where)*)? {
144 $(#[$attr])*
145 fn call_object_mut(&mut $self, $args: $args_ty) -> Self::Output {
146 $($body)*
147 }
148 }
149 };
150
151 (
152 impl[$($generic_bounds:tt)*] Fn<$args_ty:ty> for $target:ty $(where[$($where:tt)*])?=
153 $(#[$attr:meta])*
154 |$self:tt, $args:tt| {
155 $($body:tt)*
156 }
157 ) => {
158 #[cfg(feature = "nightly")]
159 impl<$($generic_bounds)*> std::ops::Fn<$args_ty> for $target $(where $($where)*)? {
160 $(#[$attr])*
161 extern "rust-call" fn call(&$self, $args: $args_ty) -> Self::Output {
162 $($body)*
163 }
164 }
165 #[cfg(not(feature = "nightly"))]
166 impl<$($generic_bounds)*> FnObject<$args_ty> for $target $(where $($where)*)? {
167 $(#[$attr])*
168 fn call_object(&$self, $args: $args_ty) -> Self::Output {
169 $($body)*
170 }
171 }
172 };
173}
174
175#[allow(missing_debug_implementations)]
176#[doc(hidden)]
177#[derive(Object)]
178pub struct CallWrapper<T: Object>(pub T);
179
180/// A tuple.
181///
182/// Do not rely on the exact definition of this trait, as it may change depending on the enabled
183/// features.
184#[cfg(feature = "nightly")]
185pub trait Tuple: std::marker::Tuple {}
186#[cfg(feature = "nightly")]
187impl<T: std::marker::Tuple> Tuple for T {}
188
189#[cfg(not(feature = "nightly"))]
190mod private {
191 pub trait Sealed {}
192}
193/// A tuple.
194///
195/// Do not rely on the exact definition of this trait, as it may change depending on the enabled
196/// features.
197#[cfg(not(feature = "nightly"))]
198pub trait Tuple: private::Sealed {}
199#[cfg(not(feature = "nightly"))]
200macro_rules! decl_tuple {
201 () => {};
202 ($head:tt $($tail:tt)*) => {
203 impl<$($tail),*> private::Sealed for ($($tail,)*) {}
204 impl<$($tail),*> Tuple for ($($tail,)*) {}
205 decl_tuple!($($tail)*);
206 };
207}
208#[cfg(not(feature = "nightly"))]
209decl_tuple!(x T20 T19 T18 T17 T16 T15 T14 T13 T12 T11 T10 T9 T8 T7 T6 T5 T4 T3 T2 T1 T0);
210
211impl<T: Object> Deref for CallWrapper<T> {
212 type Target = T;
213 fn deref(&self) -> &T {
214 &self.0
215 }
216}
217
218#[doc(hidden)]
219pub trait InternalFnOnce<Args>: Object {
220 type Output;
221 fn call_object_once(self, args: Args) -> Self::Output;
222}
223impl_fn! {
224 impl[Args: Tuple, T: InternalFnOnce<Args>] FnOnce<Args, Output = T::Output> for CallWrapper<T> =
225 |self, args| {
226 self.0.call_object_once(args)
227 }
228}
229
230#[doc(hidden)]
231pub trait InternalFnMut<Args>: InternalFnOnce<Args> {
232 fn call_object_mut(&mut self, args: Args) -> Self::Output;
233}
234impl_fn! {
235 impl[Args: Tuple, T: InternalFnMut<Args>] FnMut<Args> for CallWrapper<T> = |self, args| {
236 self.0.call_object_mut(args)
237 }
238}
239
240#[doc(hidden)]
241pub trait InternalFn<Args>: InternalFnMut<Args> {
242 fn call_object(&self, args: Args) -> Self::Output;
243}
244impl_fn! {
245 impl[Args: Tuple, T: InternalFn<Args>] Fn<Args> for CallWrapper<T> = |self, args| {
246 self.0.call_object(args)
247 }
248}
249
250/// A callable object that can be called at least once.
251///
252/// Do not implement this trait manually: the library gives no guarantees whether that is possible,
253/// portable, or stable.
254#[cfg(not(feature = "nightly"))]
255pub trait FnOnceObject<Args: Tuple>: Object {
256 /// Function return type.
257 type Output;
258 /// Invoke the function with the given argument tuple.
259 ///
260 /// # Example
261 ///
262 /// ```rust
263 /// use crossmist::{FnOnceObject, lambda};
264 ///
265 /// let s = "Hello, world!".to_string();
266 /// let mut increment = lambda! { move(s: String) || -> String { s } };
267 ///
268 /// assert_eq!(increment.call_object_once(()), "Hello, world!");
269 /// ```
270 fn call_object_once(self, args: Args) -> Self::Output;
271 /// Invoke a boxed function with the given argument tuple.
272 ///
273 /// This method is implemented as follows:
274 ///
275 /// ```ignore
276 /// fn call_object_box(self: Box<Self>, args: Args) -> Self::Output {
277 /// (*self).call_object_once(args)
278 /// }
279 /// ```
280 ///
281 /// It enables `FnOnceObject<Args>` to be automatically implemented for
282 /// `Box<dyn FnOnceObject<Args>>`.
283 fn call_object_box(self: Box<Self>, args: Args) -> Self::Output;
284}
285/// A callable object that can be called at least once.
286///
287/// Do not implement this trait manually: the library gives no guarantees whether that is possible,
288/// portable, or stable.
289#[cfg(feature = "nightly")]
290pub trait FnOnceObject<Args: Tuple>: Object + std::ops::FnOnce<Args> {
291 /// Invoke the function with the given argument tuple.
292 ///
293 /// # Example
294 ///
295 /// ```rust
296 /// use crossmist::{FnOnceObject, lambda};
297 ///
298 /// let s = "Hello, world!".to_string();
299 /// let mut increment = lambda! { move(s: String) || -> String { s } };
300 ///
301 /// assert_eq!(increment.call_object_once(()), "Hello, world!");
302 /// ```
303 fn call_object_once(self, args: Args) -> Self::Output;
304 /// Invoke a boxed function with the given argument tuple.
305 ///
306 /// This method is implemented as follows:
307 ///
308 /// ```ignore
309 /// fn call_object_box(self: Box<Self>, args: Args) -> Self::Output {
310 /// (*self).call_object_once(args)
311 /// }
312 /// ```
313 ///
314 /// It enables `FnOnceObject<Args>` to be automatically implemented for
315 /// `Box<dyn FnOnceObject<Args>>`.
316 fn call_object_box(self: Box<Self>, args: Args) -> Self::Output;
317}
318#[cfg(not(feature = "nightly"))]
319impl<Args: Tuple, T: FnOnceObject<Args> + ?Sized> FnOnceObject<Args> for Box<T>
320where
321 Box<T>: Object,
322{
323 type Output = T::Output;
324 fn call_object_once(self, args: Args) -> Self::Output {
325 self.call_object_box(args)
326 }
327 fn call_object_box(self: Box<Self>, args: Args) -> Self::Output {
328 (*self).call_object_once(args)
329 }
330}
331#[cfg(feature = "nightly")]
332impl<Args: Tuple, T: Object + std::ops::FnOnce<Args>> FnOnceObject<Args> for T {
333 fn call_object_once(self, args: Args) -> Self::Output {
334 self.call_once(args)
335 }
336 fn call_object_box(self: Box<Self>, args: Args) -> Self::Output {
337 self.call_once(args)
338 }
339}
340
341/// A callable object that can be called multiple times and might mutate state.
342///
343/// Do not implement this trait manually: the library gives no guarantees whether that is possible,
344/// portable, or stable.
345#[cfg(feature = "nightly")]
346pub trait FnMutObject<Args: Tuple>: FnOnceObject<Args> + std::ops::FnMut<Args> {
347 /// Invoke the function with the given argument tuple.
348 ///
349 /// # Example
350 ///
351 /// ```rust
352 /// use crossmist::{FnMutObject, lambda};
353 ///
354 /// let counter = 0;
355 /// let mut increment = lambda! {
356 /// move(&mut counter: &mut i32) || -> i32 { *counter += 1; *counter }
357 /// };
358 ///
359 /// assert_eq!(increment.call_object_mut(()), 1);
360 /// assert_eq!(increment.call_object_mut(()), 2);
361 /// assert_eq!(increment.call_object_mut(()), 3);
362 /// ```
363 fn call_object_mut(&mut self, args: Args) -> Self::Output;
364}
365/// A callable object that can be called multiple times and might mutate state.
366///
367/// Do not implement this trait manually: the library gives no guarantees whether that is possible,
368/// portable, or stable.
369#[cfg(not(feature = "nightly"))]
370pub trait FnMutObject<Args: Tuple>: FnOnceObject<Args> {
371 /// Invoke the function with the given argument tuple.
372 ///
373 /// # Example
374 ///
375 /// ```rust
376 /// use crossmist::{FnMutObject, lambda};
377 ///
378 /// let counter = 0;
379 /// let mut increment = lambda! {
380 /// move(&mut counter: &mut i32) || -> i32 { *counter += 1; *counter }
381 /// };
382 ///
383 /// assert_eq!(increment.call_object_mut(()), 1);
384 /// assert_eq!(increment.call_object_mut(()), 2);
385 /// assert_eq!(increment.call_object_mut(()), 3);
386 /// ```
387 fn call_object_mut(&mut self, args: Args) -> Self::Output;
388}
389#[cfg(feature = "nightly")]
390impl<Args: Tuple, T: Object + std::ops::FnMut<Args>> FnMutObject<Args> for T {
391 fn call_object_mut(&mut self, args: Args) -> Self::Output {
392 self.call_mut(args)
393 }
394}
395
396/// A callable object that can be called multiple times without mutating state.
397///
398/// Do not implement this trait manually: the library gives no guarantees whether that is possible,
399/// portable, or stable.
400#[cfg(feature = "nightly")]
401pub trait FnObject<Args: Tuple>: FnMutObject<Args> + std::ops::Fn<Args> {
402 /// Invoke the function with the given argument tuple.
403 ///
404 /// # Example
405 ///
406 /// ```rust
407 /// use crossmist::{FnObject, func};
408 ///
409 /// #[func]
410 /// fn add(a: i32, b: i32) -> i32 {
411 /// a + b
412 /// }
413 ///
414 /// assert_eq!(add.call_object((5, 7)), 12);
415 /// ```
416 fn call_object(&self, args: Args) -> Self::Output;
417}
418/// A callable object that can be called multiple times without mutating state.
419///
420/// Do not implement this trait manually: the library gives no guarantees whether that is possible,
421/// portable, or stable.
422#[cfg(not(feature = "nightly"))]
423pub trait FnObject<Args: Tuple>: FnMutObject<Args> {
424 /// Invoke the function with the given argument tuple.
425 ///
426 /// # Example
427 ///
428 /// ```rust
429 /// use crossmist::{FnObject, func};
430 ///
431 /// #[func]
432 /// fn add(a: i32, b: i32) -> i32 {
433 /// a + b
434 /// }
435 ///
436 /// assert_eq!(add.call_object((5, 7)), 12);
437 /// ```
438 fn call_object(&self, args: Args) -> Self::Output;
439}
440#[cfg(feature = "nightly")]
441impl<Args: Tuple, T: Object + std::ops::Fn<Args>> FnObject<Args> for T {
442 fn call_object(&self, args: Args) -> Self::Output {
443 self.call(args)
444 }
445}
446
447#[doc(hidden)]
448pub trait BindValue<Head: Object, Tail>: Object + Sized {
449 fn bind_value(self, head: Head) -> BoundValue<Self, Head>;
450}
451#[doc(hidden)]
452pub trait BindMut<Head: Object, Tail>: Object + Sized {
453 fn bind_mut(self, head: Head) -> BoundMut<Self, Head>;
454}
455#[doc(hidden)]
456pub trait BindRef<Head: Object, Tail>: Object + Sized {
457 fn bind_ref(self, head: Head) -> BoundRef<Self, Head>;
458}
459
460#[allow(missing_debug_implementations)]
461#[doc(hidden)]
462#[derive(Object)]
463pub struct BoundValue<Func: Object, Head: Object> {
464 pub func: Func,
465 pub head: Head,
466}
467#[allow(missing_debug_implementations)]
468#[doc(hidden)]
469#[derive(Object)]
470pub struct BoundMut<Func: Object, Head: Object> {
471 pub func: Func,
472 pub head: Head,
473}
474#[allow(missing_debug_implementations)]
475#[doc(hidden)]
476#[derive(Object)]
477pub struct BoundRef<Func: Object, Head: Object> {
478 pub func: Func,
479 pub head: Head,
480}
481
482macro_rules! reverse {
483 ([$($acc:tt)*]) => { ($($acc)*) };
484 ([$($acc:tt)*] $single:tt) => { reverse!([$single, $($acc)*]) };
485 ([$($acc:tt)*] $head:tt, $($tail:tt),*) => { reverse!([$head, $($acc)*] $($tail),*) };
486}
487
488macro_rules! decl_fn {
489 () => {};
490
491 ($head:tt $($tail:tt)*) => {
492 decl_fn!($($tail)*);
493
494 paste! {
495 impl<[<T $head>]: Object $(, [<T $tail>])*, Func: FnOnceObject<([<T $head>], $([<T $tail>]),*)>> BindValue<[<T $head>], ($([<T $tail>],)*)> for Func {
496 fn bind_value(self, head: [<T $head>]) -> BoundValue<Self, [<T $head>]> {
497 BoundValue {
498 func: self,
499 head,
500 }
501 }
502 }
503 impl<'a, [<T $head>]: 'a + Object $(, [<T $tail>])*, Func: FnOnceObject<(&'a mut [<T $head>], $([<T $tail>]),*)>> BindMut<[<T $head>], ($([<T $tail>],)*)> for Func {
504 fn bind_mut(self, head: [<T $head>]) -> BoundMut<Self, [<T $head>]> {
505 BoundMut {
506 func: self,
507 head,
508 }
509 }
510 }
511 impl<'a, [<T $head>]: 'a + Object $(, [<T $tail>])*, Func: FnOnceObject<(&'a [<T $head>], $([<T $tail>]),*)>> BindRef<[<T $head>], ($([<T $tail>],)*)> for Func {
512 fn bind_ref(self, head: [<T $head>]) -> BoundRef<Self, [<T $head>]> {
513 BoundRef {
514 func: self,
515 head,
516 }
517 }
518 }
519
520 impl_fn! {
521 impl[[<T $head>]: Object $(, [<T $tail>])*, Func: FnOnceObject<([<T $head>], $([<T $tail>]),*)>] FnOnce<($([<T $tail>],)*), Output = Func::Output> for BoundValue<Func, [<T $head>]> =
522 #[allow(unused_variables)]
523 |self, args| {
524 self.func.call_object_once(reverse!([] $((args.$tail),)* (self.head)))
525 }
526 }
527 impl_fn! {
528 impl[[<T $head>]: Copy + Object $(, [<T $tail>])*, Func: FnMutObject<([<T $head>], $([<T $tail>]),*)>] FnMut<($([<T $tail>],)*)> for BoundValue<Func, [<T $head>]> =
529 #[allow(unused_variables)]
530 |self, args| {
531 self.func.call_object_mut(reverse!([] $((args.$tail),)* (self.head)))
532 }
533 }
534 impl_fn! {
535 impl[[<T $head>]: Copy + Object $(, [<T $tail>])*, Func: FnObject<([<T $head>], $([<T $tail>]),*)>] Fn<($([<T $tail>],)*)> for BoundValue<Func, [<T $head>]> =
536 #[allow(unused_variables)]
537 |self, args| {
538 self.func.call_object(reverse!([] $((args.$tail),)* (self.head)))
539 }
540 }
541
542 impl_fn! {
543 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>]> =
544 #[allow(unused_variables)]
545 |self, args| {
546 self.func.call_object_once(reverse!([] $((args.$tail),)* (&mut self.head)))
547 }
548 }
549 impl_fn! {
550 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>]> =
551 #[allow(unused_variables)]
552 |self, args| {
553 self.func.call_object_mut(reverse!([] $((args.$tail),)* (&mut self.head)))
554 }
555 }
556
557 impl_fn! {
558 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>]> =
559 #[allow(unused_variables)]
560 |self, args| {
561 self.func.call_object_once(reverse!([] $((args.$tail),)* (&self.head)))
562 }
563 }
564 impl_fn! {
565 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>]> =
566 #[allow(unused_variables)]
567 |self, args| {
568 self.func.call_object_mut(reverse!([] $((args.$tail),)* (&self.head)))
569 }
570 }
571 impl_fn! {
572 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>]> =
573 #[allow(unused_variables)]
574 |self, args| {
575 self.func.call_object(reverse!([] $((args.$tail),)* (&self.head)))
576 }
577 }
578 }
579 }
580}
581
582decl_fn!(x 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0);
583
584/// A short-cut for turning a (possible capturing) closure into an object function, just like as if
585/// `#[func]` was used.
586///
587/// Syntax is similar to that of closure, except that types of all arguments and the type of the
588/// return value are not inferred. Additionally, all moved values have to be listed manually,
589/// indicating how they are captured.
590///
591/// Simplest example:
592///
593/// ```rust
594/// # use crossmist::{lambda, main};
595/// #[main]
596/// fn main() {
597/// let func = lambda! { |a: i32, b: i32| -> i32 { a + b } };
598/// assert_eq!(func.run(5, 7).unwrap(), 12);
599/// }
600/// ```
601///
602/// With captures:
603///
604/// ```rust
605/// # use crossmist::{FnObject, FnOnceObject, func, lambda, main};
606/// #[main]
607/// fn main() {
608/// let a = 5;
609/// let func = lambda! { move(a: i32) |b: i32| -> i32 { a + b } };
610/// // run/spawn do not work directly, but you may still call/pass the function
611/// assert_eq!(func.call_object((7,)), 12);
612/// assert_eq!(gate.run(func, 7).unwrap(), 12);
613/// }
614///
615/// #[func]
616/// fn gate(f: Box<dyn FnOnceObject<(i32,), Output = i32>>, arg: i32) -> i32 {
617/// f.call_object_once((arg,))
618/// }
619/// ```
620///
621/// `f.call_object_once((arg,))` can be replaced with `f(arg)` if the `nightly` feature is enabled.
622///
623/// Captuing more complex objects (type annotations are provided for completeness and are
624/// unnecessary):
625///
626/// ```rust
627/// # use crossmist::{FnOnceObject, lambda, main};
628/// # #[main]
629/// # fn main() {
630/// let a = "Hello, ".to_string();
631/// // a is accessible by value when the lambda is executed
632/// let prepend_hello: Box<dyn FnOnceObject<(&str,), Output = String>> =
633/// lambda! { move(a: String) |b: &str| -> String { a + b } };
634/// assert_eq!(prepend_hello.call_object_once(("world!",)), "Hello, world!".to_string());
635/// // Can only be called once. The line below fails to compile when uncommented:
636/// // assert_eq!(prepend_hello.call_object_once(("world!",)), "Hello, world!".to_string());
637/// # }
638/// ```
639///
640/// ```rust
641/// # use crossmist::{FnMutObject, lambda, main};
642/// # #[main]
643/// # fn main() {
644/// let cache = vec![0, 1];
645/// // cache is accessible by a mutable reference when the lambda is executed
646/// let mut fibonacci: Box<dyn FnMutObject<(usize,), Output = u32>> = lambda! {
647/// move(&mut cache: &mut Vec<u32>) |n: usize| -> u32 {
648/// while cache.len() <= n {
649/// cache.push(cache[cache.len() - 2..].iter().sum());
650/// }
651/// cache[n]
652/// }
653/// };
654/// assert_eq!(fibonacci.call_object_mut((3,)), 2);
655/// // Can be called multiple types, but has to be mutable
656/// assert_eq!(fibonacci.call_object_mut((6,)), 8);
657/// # }
658/// ```
659///
660/// ```rust
661/// # use crossmist::{FnObject, lambda, main};
662/// # #[main]
663/// # fn main() {
664/// let s = "Hello, world!".to_string();
665/// // s is accessible by an immutable reference when the lambda is executed
666/// let count_occurrences: Box<dyn FnObject<(char,), Output = usize>> =
667/// lambda! { move(&s: &String) |c: char| -> usize { s.matches(c).count() } };
668/// assert_eq!(count_occurrences.call_object(('o',)), 2);
669/// // Can be called multiple times and be immutable
670/// assert_eq!(count_occurrences.call_object(('e',)), 1);
671/// # }
672/// ```
673#[macro_export]
674macro_rules! lambda {
675 // split || into | |
676 (|| $($items:tt)*) => {
677 $crate::lambda_parse! {
678 [],
679 [_unnamed],
680 | $($items)*
681 }
682 };
683 (|$($items:tt)*) => {
684 $crate::lambda_parse! {
685 [],
686 [_unnamed],
687 $($items)*
688 }
689 };
690 // split || into | |
691 (move($($moved_vars:tt)*) || $($items:tt)*) => {
692 $crate::lambda_parse! {
693 [],
694 [
695 $crate::lambda_bind! { [_unnamed], $($moved_vars)* }
696 ],
697 $($moved_vars)*, | $($items)*
698 }
699 };
700 (move($($moved_vars:tt)*) |$($items:tt)*) => {
701 $crate::lambda_parse! {
702 [],
703 [
704 $crate::lambda_bind! { [_unnamed], $($moved_vars)* }
705 ],
706 $($moved_vars)*, $($items)*
707 }
708 };
709}
710
711#[doc(hidden)]
712#[macro_export]
713macro_rules! lambda_parse {
714 (
715 [$($args:tt)*],
716 [$($append:tt)*],
717 , $($rest:tt)*
718 ) => {
719 $crate::lambda_parse! { [$($args)*], [$($append)*], $($rest)* }
720 };
721 (
722 [$($args:tt)*],
723 [$($append:tt)*],
724 &mut $name:ident: $type:ty, $($rest:tt)*
725 ) => {
726 $crate::lambda_parse! { [$($args)* $name: $type,], [$($append)*], $($rest)* }
727 };
728 (
729 [$($args:tt)*],
730 [$($append:tt)*],
731 $(&)? $name:ident: $type:ty, $($rest:tt)*
732 ) => {
733 $crate::lambda_parse! { [$($args)* $name: $type,], [$($append)*], $($rest)* }
734 };
735 (
736 [$($args:tt)*],
737 [$($append:tt)*],
738 &mut $name:ident: $type:ty| $($rest:tt)*
739 ) => {
740 $crate::lambda_parse! { [$($args)* $name: $type,], [$($append)*], |$($rest)* }
741 };
742 (
743 [$($args:tt)*],
744 [$($append:tt)*],
745 $(&)? $name:ident: $type:ty| $($rest:tt)*
746 ) => {
747 $crate::lambda_parse! { [$($args)* $name: $type,], [$($append)*], |$($rest)* }
748 };
749
750 (
751 [$($args:tt)*],
752 [$($append:tt)*],
753 | -> $return_type:ty { $($code:tt)* }
754 ) => {
755 {
756 #[$crate::func]
757 fn _unnamed($($args)*) -> $return_type {
758 $($code)*
759 }
760 {
761 #[allow(unused)]
762 use $crate::{BindValue, BindMut, BindRef};
763 ::std::boxed::Box::new($($append)*)
764 }
765 }
766 };
767}
768
769#[doc(hidden)]
770#[macro_export]
771macro_rules! lambda_bind {
772 ([$($acc:tt)*],) => { $($acc)* };
773
774 ([$($acc:tt)*], &mut $name:ident: $type:ty, $($rest:tt)*) => {
775 $crate::lambda_bind! { [$($acc)*.bind_mut($name)], $($rest)* }
776 };
777 ([$($acc:tt)*], &mut $name:ident: $type:ty) => {
778 $($acc)*.bind_mut($name)
779 };
780 ([$($acc:tt)*], &$name:ident: $type:ty, $($rest:tt)*) => {
781 $crate::lambda_bind! { [$($acc)*.bind_ref($name)], $($rest)* }
782 };
783 ([$($acc:tt)*], &$name:ident: $type:ty) => {
784 $($acc)*.bind_ref($name)
785 };
786 ([$($acc:tt)*], $name:ident: $type:ty, $($rest:tt)*) => {
787 $crate::lambda_bind! { [$($acc)*.bind_value($name)], $($rest)* }
788 };
789 ([$($acc:tt)*], $name:ident: $type:ty) => {
790 $($acc)*.bind_value($name)
791 };
792}
793
794/// Metaprogramming on `fn(...) -> ...` types.
795///
796/// This trait is not part of the stable API provided by crossmist.
797#[cfg(feature = "nightly")]
798pub trait FnPtr: std::marker::FnPtr {}
799#[cfg(feature = "nightly")]
800impl<T: std::marker::FnPtr> FnPtr for T {}
801
802#[cfg(not(feature = "nightly"))]
803mod fn_ptr_private {
804 pub trait Sealed {}
805}
806/// Metaprogramming on `fn(...) -> ...` types.
807///
808/// This trait is not part of the stable API provided by crossmist.
809#[cfg(not(feature = "nightly"))]
810pub trait FnPtr: Copy + Clone + fn_ptr_private::Sealed {
811 /// Convert the function pointer to a type-erased pointer.
812 fn addr(self) -> *const ();
813}
814
815/// A wrapper for `fn(...) -> ...` implementing `Object`.
816///
817/// This type enables you to pass `fn` and `unsafe fn` pointers between processes soundly without
818/// requiring [`lambda`] or [`crossmist::func`].
819///
820/// Creating the wrapper from a function pointer is `unsafe` because functions might not be
821/// available in the child process if they were created in runtime by JIT compilation or alike.
822///
823/// All function pointers are supported on nightly. Only function pointers with up to 20 arguments
824/// with no references of generic lifetimes are supported without the `nightly` feature flag.
825///
826/// # Example
827///
828/// These examples require the `nightly` feature to be enabled. [`FnObject::call_object`] can be
829/// used instead of direct calls on stable.
830///
831/// ```rust
832/// # use crossmist::fns::{FnObject, StaticFn};
833/// fn add(a: i32, b: i32) -> i32 {
834/// a + b
835/// }
836/// let add = unsafe { StaticFn::<fn(i32, i32) -> i32>::new(add) };
837/// let add: Box<dyn FnObject<(i32, i32), Output = i32>> = Box::new(add);
838/// assert_eq!(add(5, 7), 12);
839/// ```
840///
841/// ```rust
842/// # use crossmist::fns::{FnObject, StaticFn};
843/// let add = unsafe { StaticFn::<fn(i32, i32) -> i32>::new(|a, b| a + b) };
844/// let add: Box<dyn FnObject<(i32, i32), Output = i32>> = Box::new(add);
845/// assert_eq!(add(5, 7), 12);
846/// ```
847///
848/// This example works on stable without changes.
849///
850/// ```rust
851/// # use crossmist::fns::{FnObject, StaticFn};
852/// unsafe fn dangerous_read(p: *const i32) -> i32 {
853/// p.read()
854/// }
855/// let dangerous_read = unsafe { StaticFn::<unsafe fn(*const i32) -> i32>::new(dangerous_read) };
856/// let dangerous_read = dangerous_read.get_fn();
857/// unsafe {
858/// assert_eq!(dangerous_read(&123), 123);
859/// }
860/// ```
861///
862/// This example requires `nightly` because of references.
863///
864/// ```rust
865/// # use crossmist::fns::{FnObject, StaticFn};
866/// fn safe_read(p: &i32) -> i32 {
867/// *p
868/// }
869/// let safe_read = unsafe { StaticFn::<fn(&i32) -> i32>::new(safe_read) };
870/// let safe_read: Box<dyn FnObject<(&i32,), Output = i32>> = Box::new(safe_read);
871/// assert_eq!(safe_read(&123), 123);
872/// ```
873#[derive(Clone, Copy, Debug, Object)]
874pub struct StaticFn<F: FnPtr> {
875 ptr: RelocatablePtr<()>,
876 phantom: PhantomData<F>,
877}
878
879impl<F: FnPtr> StaticFn<F> {
880 /// Create a [`StaticFn`] from a function pointer.
881 ///
882 /// # Safety
883 ///
884 /// This is safe to call if the function pointer is obtained from an `fn` item or a closure
885 /// without captures.
886 pub unsafe fn new(f: F) -> Self {
887 Self {
888 ptr: RelocatablePtr(f.addr()),
889 phantom: PhantomData,
890 }
891 }
892
893 /// Extract a function pointer from a [`StaticFn`].
894 pub fn get_fn(self) -> F {
895 unsafe { std::mem::transmute_copy::<*const (), F>(&self.ptr.0) }
896 }
897
898 const _F_IS_POINTER_SIZED: () = assert!(
899 std::mem::size_of::<*const ()>() == std::mem::size_of::<F>(),
900 "An instance of FnPtr has a size not equal to the size of *const (). This should have \
901 been impossible."
902 );
903}
904
905macro_rules! impl_fn_pointer {
906 () => {};
907 ($head:tt $($tail:tt)*) => {
908 paste! {
909 #[cfg(not(feature = "nightly"))]
910 impl<Output, $([<T $tail>]),*> fn_ptr_private::Sealed for fn($([<T $tail>]),*) -> Output {}
911 #[cfg(not(feature = "nightly"))]
912 impl<Output, $([<T $tail>]),*> FnPtr for fn($([<T $tail>]),*) -> Output {
913 fn addr(self) -> *const () {
914 self as *const ()
915 }
916 }
917
918 #[cfg(not(feature = "nightly"))]
919 impl<Output, $([<T $tail>]),*> fn_ptr_private::Sealed for unsafe fn($([<T $tail>]),*) -> Output {}
920 #[cfg(not(feature = "nightly"))]
921 impl<Output, $([<T $tail>]),*> FnPtr for unsafe fn($([<T $tail>]),*) -> Output {
922 fn addr(self) -> *const () {
923 self as *const ()
924 }
925 }
926
927 impl_fn! {
928 impl[T: FnPtr, Output, $([<T $tail>]),*] FnOnce<($([<T $tail>],)*), Output = Output> for StaticFn<T> where[T: FnOnce($([<T $tail>]),*) -> Output] =
929 |self, args| {
930 let ($([<a $tail>],)*) = args;
931 self.get_fn()($([<a $tail>]),*)
932 }
933 }
934 impl_fn! {
935 impl[T: FnPtr, Output, $([<T $tail>]),*] FnMut<($([<T $tail>],)*)> for StaticFn<T> where[T: FnMut($([<T $tail>]),*) -> Output] =
936 |self, args| {
937 let ($([<a $tail>],)*) = args;
938 self.get_fn()($([<a $tail>]),*)
939 }
940 }
941 impl_fn! {
942 impl[T: FnPtr, Output, $([<T $tail>]),*] Fn<($([<T $tail>],)*)> for StaticFn<T> where[T: Fn($([<T $tail>]),*) -> Output] =
943 |self, args| {
944 let ($([<a $tail>],)*) = args;
945 self.get_fn()($([<a $tail>]),*)
946 }
947 }
948 }
949
950 impl_fn_pointer!($($tail)*);
951 };
952}
953impl_fn_pointer!(x 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0);