Skip to content

Commit

Permalink
Merge pull request #13 from alecmocatta/proc-macro
Browse files Browse the repository at this point in the history
Switch to using a procedural macro
  • Loading branch information
mergify[bot] authored Oct 12, 2019
2 parents 8497fb7 + 69acc6f commit e8aaff2
Show file tree
Hide file tree
Showing 7 changed files with 1,408 additions and 1,052 deletions.
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[workspace]

[package]
name = "serde_closure"
version = "0.1.5"
version = "0.2.0"
license = "MIT OR Apache-2.0"
authors = ["Alec Mocatta <[email protected]>"]
categories = ["development-tools","encoding","rust-patterns","network-programming"]
Expand All @@ -12,7 +14,7 @@ This library provides macros to wrap closures such that they can serialized and
"""
repository = "https://github.com/alecmocatta/serde_closure"
homepage = "https://github.com/alecmocatta/serde_closure"
documentation = "https://docs.rs/serde_closure/0.1.5"
documentation = "https://docs.rs/serde_closure/0.2.0"
readme = "README.md"
edition = "2018"

Expand All @@ -21,9 +23,10 @@ azure-devops = { project = "alecmocatta/serde_closure", pipeline = "tests" }
maintenance = { status = "actively-developed" }

[dependencies]
serde_closure_derive = { version = "=0.2.0", path = "serde_closure_derive" }
serde_derive = "1.0"
serde = { version = "1.0", features = ["derive"] }
relative = "0.1.1"
proc-macro-hack = "0.5"

[dev-dependencies]
serde_json = "1.0"
Expand Down
86 changes: 55 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![MIT / Apache 2.0 licensed](https://img.shields.io/crates/l/serde_closure.svg?maxAge=2592000)](#License)
[![Build Status](https://dev.azure.com/alecmocatta/serde_closure/_apis/build/status/tests?branchName=master)](https://dev.azure.com/alecmocatta/serde_closure/_build/latest?branchName=master)

[Docs](https://docs.rs/serde_closure/0.1.5)
[Docs](https://docs.rs/serde_closure/0.2.0)

Serializable closures.

Expand All @@ -23,22 +23,22 @@ For example, if you have multiple forks of a process, or the same binary running
on each of a cluster of machines, this library would help you to send closures
between them.

This library aims to work in as simple and un-magical a way as possible. It
currently requires nightly Rust for the `unboxed_closures` and `fn_traits`
features (rust issue [#29625](https://github.com/rust-lang/rust/issues/29625)).
This library aims to work in as simple, safe and un-magical a way as possible.
It currently requires nightly Rust for the `unboxed_closures` and `fn_traits`
features (rust issue
[#29625](https://github.com/rust-lang/rust/issues/29625)).

* There are three macros,
[FnOnce](https://docs.rs/serde_closure/0.1.5/serde_closure/macro.FnOnce.html),
[FnMut](https://docs.rs/serde_closure/0.1.5/serde_closure/macro.FnMut.html) and
[Fn](https://docs.rs/serde_closure/0.1.5/serde_closure/macro.Fn.html),
corresponding to the three types of Rust closure.
* The *captured variables*, i.e. those variables that are referenced by the
closure but are declared outside of it, must be explicitly listed.
* There are currently some minor limitations of syntax over normal closure
syntax, which are documented below.
* The closure is coerced to a function pointer, which is wrapped by
[relative::Code](https://docs.rs/relative) such that it can safely be sent
between processes.
[`FnOnce`](https://docs.rs/serde_closure/0.2.0/serde_closure/macro.FnOnce.html),
[`FnMut`](https://docs.rs/serde_closure/0.2.0/serde_closure/macro.FnMut.html)
and [`Fn`](https://docs.rs/serde_closure/0.2.0/serde_closure/macro.Fn.html),
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:**
Expand All @@ -64,40 +64,64 @@ let mut num = 0;
```
```rust
let mut num = 0;
FnMut!([num] |a| *num += a)
FnMut!(|a| num += a)
```
Note: As this is a FnMut closure, `num` is a mutable reference, and must be
dereferenced to use.

**`move` closure, capturing `hello` and `world`:**
```rust
let hello = String::from("hello");
let mut world = String::new();
move |name| {
world += (hello.to_uppercase() + name).as_str();
world += (hello.to_uppercase() + name).as_str();
}
```
```rust
let hello = String::from("hello");
let mut world = String::new();
FnMut!([hello, world] move |name| {
*world += (hello.to_uppercase() + name).as_str();
FnMut!(move |name| {
world += (hello.to_uppercase() + name).as_str();
})
```
Note: `world` must be dereferenced to use.

## Cosmetic limitations
As visible above, there are currently some minor limitations:
* The captured variables in FnMut and Fn closures are references, so need
to be dereferenced;
* Compiler errors are not as helpful as normal:
## Limitations
There are currently some minor limitations:
* Captured variables with an uppercase first letter need to be explicitly
captured. If you see a panic like the following, fix the case of the
variable.
```text
error[E0308]: mismatched types
thread 'main' panicked at 'A variable with an upper case first letter was implicitly captured.
Unfortunately due to current limitations it must be captured explicitly.
Please refer to the README.', tests/test.rs:205:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
```
* Functions called inside the closure might need to be disambiguated. This
also affects enum unit and tuple variants with a lowercase first letter.
If you see an error like either of the following, qualify `my_function`
as `self::my_function` and `my_enum_variant` as
`MyEnum::my_enum_variant`.
```text
error[E0277]: the trait bound `fn(usize) -> std::option::Option<usize> {my_function::<usize>}: fnref::_IMPL_DESERIALIZE_FOR_Fn::_serde::Serialize` is not satisfied
--> tests/test.rs:327:10
|
314 | fn unfold<A, St, F>(initial_state: St, f: F) -> Unfold<St, F>
| ------
315 | where
316 | F: Fn(&mut St) -> Option<A> + Serialize,
| --------- required by this bound in `fnref::unfold`
...
= note: expected type `for<..> fn(&'r mut (..), (..))`
found type `[closure@<FnMut macros>:9:9: 10:44 my_var:_]`
327 | let _ = unfold(0_usize, Fn!(|acc: &mut _| my_function(*acc)));
| ^^^^^^ the trait `fnref::_IMPL_DESERIALIZE_FOR_Fn::_serde::Serialize` is not implemented for `fn(usize) -> std::option::Option<usize> {my_function::<usize>}`
```
```text
error[E0530]: function parameters cannot shadow tuple variants
--> tests/test.rs:173:47
|
173 | FnMut!(|acc: &mut _| my_enum_variant(*acc))
| ---------------------^^^^^^^^^^^^^^^-------
| | |
| | cannot be named the same as a tuple variant
| in this macro invocation
```
means that `my_var` is a captured variable, but was not explicitly listed.

## License
Licensed under either of
Expand Down
4 changes: 2 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
endpoint: alecmocatta
default:
rust_toolchain: nightly
rust_lint_toolchain: nightly-2019-07-19
rust_lint_toolchain: nightly-2019-10-04
rust_flags: ''
rust_features: ''
rust_target_check: ''
Expand All @@ -29,4 +29,4 @@ jobs:
rust_target_run: 'x86_64-apple-darwin i686-apple-darwin'
linux:
imageName: 'ubuntu-16.04'
rust_target_run: 'x86_64-unknown-linux-gnu i686-unknown-linux-gnu x86_64-unknown-linux-musl i686-unknown-linux-musl'
rust_target_run: 'x86_64-unknown-linux-gnu i686-unknown-linux-gnu' # seems to currently be broken, TODO: x86_64-unknown-linux-musl i686-unknown-linux-musl
34 changes: 34 additions & 0 deletions serde_closure_derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[package]
name = "serde_closure_derive"
version = "0.2.0"
license = "MIT OR Apache-2.0"
authors = ["Alec Mocatta <[email protected]>"]
categories = ["development-tools","encoding","rust-patterns","network-programming"]
keywords = ["closure","serialization","serde","distributed"]
description = """
Serializable closures.
This library provides macros to wrap closures such that they can serialized and sent between other processes running the same binary.
See [`serde_closure`](https://crates.io/crates/serde_closure) for documentation.
"""
repository = "https://github.com/alecmocatta/serde_closure"
homepage = "https://github.com/alecmocatta/serde_closure"
documentation = "https://docs.rs/serde_closure/0.2.0"
edition = "2018"

[badges]
azure-devops = { project = "alecmocatta/serde_closure", pipeline = "tests" }
maintenance = { status = "actively-developed" }

[lib]
proc-macro = true

[dependencies]
proc-macro2 = { version = "1.0.1", default-features = false }
proc-macro-hack = "0.5"
quote = { version = "1.0.2", default-features = false }
syn = { version = "1.0.5", default-features = false, features = ["clone-impls", "full", "parsing", "printing", "proc-macro"] }

[features]
assert-hack = []
Loading

0 comments on commit e8aaff2

Please sign in to comment.