Expand description
Utilities for passing function callbacks between processes.
It is common to use callbacks to specialize function behavior. Capturing lambdas play an
especially big role in this. They are, however, of complex opaque types that cannot be
inspected. Therefore, passing lambdas is not just complicated because they would have to be of
type dyn Object + Fn() -> ()
, which Rust does not support at the moment, but downright
impossible in case of captures.
To fix the following code:
use crossmist::{func, main, Object};
#[main]
fn main() {
let x = 7;
println!("{}", go.run(5, Box::new(|y| x + y)).unwrap());
}
#[func]
fn go(x: i32, f: Box<dyn Object + Fn(i32) -> i32>) -> i32 {
f(x)
}
…we have to use a macro, and also a different invocation syntax:
use crossmist::{FnObject, func, lambda, main};
#[main]
fn main() {
let x = 7;
println!("{}", go.run(5, lambda! { move(x: i32) |y: i32| -> i32 { x + y } }).unwrap());
}
#[func]
fn go(x: i32, f: Box<dyn FnObject<(i32,), Output = i32>>) -> i32 {
f.call_object((x,))
}
The macro syntax is somewhat similar to that of capturing lambdas. call_object
is similar to
std::ops::Fn::call
. If you’re using nightly Rust, you can directly do f(x)
if you opt in
by enabling the nightly
feature.
Another complication is when the callback should capture a non-copyable value (e.g. Box
) and
then be called multiple times. This cannot be detected automatically, so slightly different
syntax is used:
use crossmist::{FnObject, func, lambda, main};
#[main]
fn main() {
let x = Box::new(7);
println!("{}", go.run(5, lambda! { move(&x: &Box<i32>) |y: i32| -> i32 { **x + y } }).unwrap());
}
#[func]
fn go(x: i32, f: Box<dyn FnObject<(i32,), Output = i32>>) -> i32 {
f.call_object((x,))
}
Similarly, &mut x
can be used if the object is to be modified. Note that this still moves x
into the lambda.
Under the hood, the macro uses currying, replacing |y| x + y
with |x, y| x + y
with a
pre-determined x
variable, and makes |x, y| x + y
a callable Object
by using #[func]
:
use crossmist::{BindValue, FnObject, func, main};
#[main]
fn main() {
#[func]
fn add(x: i32, y: i32) -> i32 {
x + y
}
let x = 7;
println!("{}", go.run(5, Box::new(add.bind_value(x))).unwrap());
}
#[func]
fn go(x: i32, f: Box<dyn FnObject<(i32,), Output = i32>>) -> i32 {
f.call_object((x,))
}
Structs§
- A wrapper for
fn(...) -> ...
implementingFnObject
.
Traits§
- FnMutObject
nightly
A callable object that can be called multiple times and might mutate state. - FnObject
nightly
A callable object that can be called multiple times without mutating state. - FnOnceObject
nightly
A callable object that can be called at least once. - Metaprogramming on
fn(...) -> ...
types. - Tuple
nightly
A tuple.