[][src]Crate serde_closure

Serializable and debuggable closures.

📦  Crates.io  │  📑  GitHub  │  💬  Chat

This library provides macros that wrap closures to make them serializable and debuggable.

let one = 1;
let plus_one = Fn!(|x: i32| x + one);

assert_eq!(2, plus_one(1));
println!("{:#?}", plus_one);

// prints:
// Fn<main::{{closure}} at main.rs:6:15> {
//     one: 1,
//     source: "| x : i32 | x + one",
// }

This library aims to work in as simple and safe a way as possible. It currently requires nightly Rust for the unboxed_closures and fn_traits features (rust issue #29625).

  • There are three macros, FnOnce, FnMut and Fn, corresponding to the three types of Rust closure.
  • Wrap your closure with one of the macros and it will now implement Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize and Debug.
  • There are some minor syntax limitations, which are documented below.
  • This crate has one unavoidable but documented and sound usage of unsafe.

Examples of wrapped closures

Inferred, non-capturing closure:

|a| a+1
FnMut!(|a| a+1)

Annotated, non-capturing closure:

|a: String| -> String { a.to_uppercase() }
FnMut!(|a: String| -> String { a.to_uppercase() })

Inferred closure, capturing num:

let mut num = 0;
|a| num += a
let mut num = 0;
FnMut!(|a| num += a)

move closure, capturing hello and world:

let hello = String::from("hello");
let mut world = String::new();
move |name| {
    world += (hello.to_uppercase() + name).as_str();
}
let hello = String::from("hello");
let mut world = String::new();
FnMut!(move |name| {
    world += (hello.to_uppercase() + name).as_str();
})

Limitations

There are currently some minor limitations:

  • Use of types that start with a lowercase letter need might need to be disambiguated from variables. If you see an error like the following, fix the case of the type, or append it with my_struct::<> to disambiguate.
error[E0308]: mismatched types
   --> tests/test.rs:450:4
    |
449 |       FnOnce!(move || {
    |  _____-
450 | |         my_struct;
    | |         ^^^^^^^^^ expected struct `serde_closure::internal::a_variable`, found struct `my_struct`
451 | |     });
    | |______- in this macro invocation
    |
    = note: expected type `serde_closure::internal::a_variable`
               found type `my_struct`
  • Use of variables that start with an uppercase letter might need to be disambiguated from types. If you see an error like the following, fix the case of the variable, or wrap it with (MyVariable) to disambiguate.
error: imports cannot refer to local variables
   --> tests/test.rs:422:3
    |
417 |       FnOnce!(move || {
    |  _____-
418 | |         MyVariable;
    | |         ^^^^^^^^^^
419 | |     });
    | |______- in this macro invocation
    |
  • Functions and closures called inside the closure might need to be disambiguated. This can be done the same as above with function::<> for functions and (closure) for closures.

Serializing between processes

Closures created by this crate are unnameable – i.e. just like normal closures, there is no Rust syntax available with which to write the type. What this means is that to deserialize a closure, you either need to specify the precise type you're deserializing without naming it (which is possible but not particularly practical), or erase the type by storing it in a trait object.

The serde_traitobject crate enables trait objects to be safely serialized and sent between other processes running the same binary.

For example, if you have multiple forks of a process, or the same binary running on each of a cluster of machines, serde_traitobject would help you to send serializable closures between them. This can be done by upcasting the closure to a Box<dyn serde_traitobject::Fn()>, which is automatically serializable and deserializable with serde.

Modules

structs

Structs representing a serializable closure, created by the FnOnce, FnMut and Fn macros. They implement std::ops::FnOnce, std::ops::FnMut and std::ops::Fn respectively, as well as Debug, Serialize and Deserialize, and various convenience traits.

traits

Supertraits of std::ops::FnOnce, std::ops::FnMut and std::ops::Fn that are usable on stable Rust. They are implemented by closures created by the FnOnce, FnMut and Fn macros.

Macros

Fn

Macro that wraps a closure, evaluating to a Fn struct that implements std::ops::Fn, Debug, Serialize and Deserialize, and various convenience traits.

FnMut

Macro that wraps a closure, evaluating to a FnMut struct that implements std::ops::FnMut, Debug, Serialize and Deserialize, and various convenience traits.

FnOnce

Macro that wraps a closure, evaluating to a FnOnce struct that implements std::ops::FnOnce, Debug, Serialize and Deserialize, and various convenience traits.

Attribute Macros

generalize

Attribute macro that can be applied to items to generalize trait bounds FnOnce(…), FnMut(…) and Fn(…) to traits::FnOnce<(…)>, traits::FnMut<(…)> and traits::Fn<(…)>.