Skip to content

Commit 9871494

Browse files
authored
Merge pull request #2 from alecmocatta/pattern-and-relative
switch to relative crate; allow patterns as args
2 parents edc1ac7 + cce5d2f commit 9871494

File tree

6 files changed

+257
-265
lines changed

6 files changed

+257
-265
lines changed

.appveyor.yml

+4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ environment:
22
matrix:
33
- TARGET: x86_64-pc-windows-msvc
44
platform: x64
5+
- TARGET: x86_64-pc-windows-gnu
6+
platform: x64
57
- TARGET: i686-pc-windows-msvc
68
platform: x86
9+
- TARGET: i686-pc-windows-gnu
10+
platform: x86
711

812
install:
913
- appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ script: |
5050
( set -o errexit;set -o pipefail; set -o xtrace;set -o nounset;
5151
cargo +$FMT_VERSION fmt -- --check
5252
for TARGET in $BUILD $RUN; do (
53-
[ \( "$TRAVIS_OS_NAME" = "osx" -o \( "$TRAVIS_OS_NAME" = "linux" -a "${DIST-}" = "precise" \) \) -a \( "$TARGET" = "x86_64-unknown-linux-musl" -o "$TARGET" = "i686-unknown-linux-musl" \) ] && exit 0 # export RUSTFLAGS=-Zlinker-flavor=ld.lld temporarily disable till this is fixed: https://github.com/rust-lang/rust/issues/52501
53+
[ \( "$TRAVIS_OS_NAME" = "osx" -o \( "$TRAVIS_OS_NAME" = "linux" -a "${DIST-}" = "precise" \) \) -a \( "$TARGET" = "x86_64-unknown-linux-musl" -o "$TARGET" = "i686-unknown-linux-musl" \) ] && exit 0 # export RUSTFLAGS="-C linker=rust-lld -Z linker-flavor=ld.lld"
5454
cargo build --verbose --target "$TARGET" --lib --tests
5555
cargo build --verbose --target "$TARGET" --lib --tests --release
5656
); done
5757
for TARGET in $RUN; do (
58-
[ \( "$TRAVIS_OS_NAME" = "osx" -o \( "$TRAVIS_OS_NAME" = "linux" -a "${DIST-}" = "precise" \) \) -a \( "$TARGET" = "x86_64-unknown-linux-musl" -o "$TARGET" = "i686-unknown-linux-musl" \) ] && exit 0 # export RUSTFLAGS=-Zlinker-flavor=ld.lld temporarily disable till this is fixed: https://github.com/rust-lang/rust/issues/52501
58+
[ \( "$TRAVIS_OS_NAME" = "osx" -o \( "$TRAVIS_OS_NAME" = "linux" -a "${DIST-}" = "precise" \) \) -a \( "$TARGET" = "x86_64-unknown-linux-musl" -o "$TARGET" = "i686-unknown-linux-musl" \) ] && exit 0 # export RUSTFLAGS="-C linker=rust-lld -Z linker-flavor=ld.lld"
5959
RUST_BACKTRACE=full cargo test --target "$TARGET"
6060
RUST_BACKTRACE=full cargo test --target "$TARGET" --release
6161
); done

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ maintenance = { status = "actively-developed" }
2626
[dependencies]
2727
serde_derive = "1.0"
2828
serde = "1.0"
29+
relative = "0.1"
2930

3031
[dev-dependencies]
3132
serde_json = "1.0"

README.md

+43-24
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,36 @@
1010

1111
Serialisable closures.
1212

13-
This library provides macros to wrap closures such that they can serialised and sent between other processes running the same binary.
13+
This library provides macros to wrap closures such that they can serialised and
14+
sent between other processes running the same binary.
1415

1516
```rust
1617
fn sum_of_squares(input: &[i32]) -> i32 {
1718
input.dist_iter()
18-
.map(Fn!(|i:&_| *i * *i))
19+
.map(Fn!(|&i| i * i))
1920
.sum()
2021
}
2122
```
2223

23-
For example, if you have the same binary running on each of a cluster of machines, this library would help you to send closures between them.
24+
For example, if you have the same binary running on each of a cluster of
25+
machines, this library would help you to send closures between them.
2426

25-
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)).
27+
This library aims to work in as simple and un-magical a way as possible. It
28+
currently requires nightly Rust for the `unboxed_closures` and `fn_traits`
29+
features (rust issue [#29625](https://github.com/rust-lang/rust/issues/29625)).
2630

27-
* There are three macros, [FnOnce](https://docs.rs/serde_closure/0.1.0/serde_closure/macro.FnOnce.html), [FnMut](https://docs.rs/serde_closure/0.1.0/serde_closure/macro.FnMut.html) and [Fn](https://docs.rs/serde_closure/0.1.0/serde_closure/macro.Fn.html), corresponding to the three types of Rust closure.
28-
* The *captured variables*, i.e. those variables that are referenced by the closure but are declared outside of it, must be explicitly listed.
29-
* The closure is coerced to a function pointer, which is serialized as an `isize` relative to a known base address.
30-
* It is deserialised by adding this isize to the known base address, and transmuting to a function pointer.
31-
* This is the only necessitation of unsafety, and is reliant upon the function pointer being positioned identically relative to the base in both processes – hence both binaries must be identical.
32-
* To the best of my knowledge this holds in Rust for a given binary. If somehow the known base and the function pointer are in different objects and are loaded at different relative addresses, then this will fail, very likely as a segfault.
33-
* A solution in this case would be to compile a statically linked executable – in Rust this currently means adding `--target x86_64-unknown-linux-musl` or similar to the cargo or rustc command line.
31+
* There are three macros,
32+
[FnOnce](https://docs.rs/serde_closure/0.1.0/serde_closure/macro.FnOnce.html),
33+
[FnMut](https://docs.rs/serde_closure/0.1.0/serde_closure/macro.FnMut.html) and
34+
[Fn](https://docs.rs/serde_closure/0.1.0/serde_closure/macro.Fn.html),
35+
corresponding to the three types of Rust closure.
36+
* The *captured variables*, i.e. those variables that are referenced by the
37+
closure but are declared outside of it, must be explicitly listed.
38+
* There are currently some minor limitations of syntax over normal closure
39+
syntax, which are documented below.
40+
* The closure is coerced to a function pointer, which is wrapped by
41+
[relative::Pointer](https://docs.rs/relative) such that it can safely be sent
42+
between processes.
3443

3544
## Examples of wrapped closures
3645
**Inferred, non-capturing closure:**
@@ -56,7 +65,9 @@ move |a| num += a
5665
let mut num = 0;
5766
FnMut!([num] move |a| *num += a)
5867
```
59-
Note: If any variables are captured then the `move` keyword must be present. As this is a FnMut closure, `num` is a mutable reference, and must be dereferenced to use.
68+
Note: If any variables are captured then the `move` keyword must be present. As
69+
this is a FnMut closure, `num` is a mutable reference, and must be dereferenced
70+
to use.
6071

6172
**Capturing `hello` requiring extra annotation:**
6273
```rust
@@ -79,33 +90,41 @@ Note: `hello` needs its type annotated in the closure.
7990
**Complex closure, capturing `a` and `b`:**
8091
```rust
8192
let (mut a, mut b) = (1usize, String::from("foo"));
82-
move |c,d:&_,e: &mut _,f:String,g:&String,h:&mut String| {
83-
*e += a+c+*d;
93+
move |c, d: &_, e: &mut _, f: String, g: &String, h: &mut String| {
94+
*e += a + c + *d;
8495
a += *e;
85-
*h += ((b.clone()+f.as_str()+g.as_str())).as_str();
96+
*h += (b.clone() + f.as_str() + g.as_str()).as_str();
8697
b += h.as_str();
8798
}
8899
```
89100
```rust
90101
let (mut a, mut b) = (1usize, String::from("foo"));
91-
FnMut!([a,b] move |c:_,d:&_,e:&mut _,f:String,g:&String,h:&mut String| {
102+
FnMut!([a,b] move |c:_, d: &_, e: &mut _, f: String, g: &String, h: &mut String| {
92103
let b: &mut String = b;
93-
*e += *a+c+*d;
104+
*e += *a + c + *d;
94105
*a += *e;
95-
*h += ((b.clone()+f.as_str()+g.as_str())).as_str();
106+
*h += ((b.clone() + f.as_str() + g.as_str())).as_str();
96107
*b += h.as_str();
97108
})
98109
```
99110

100111
## Cosmetic limitations
101-
As visible above, there are currently some limitations that often necessitate extra annotation that you might typically expect to be redundant.
102-
* Type inference doesn't work as well as normal, hence extra type annotations might be needed;
103-
* The captured variables in FnMut and FnRef closures are references, so need to be dereferenced;
112+
As visible above, there are currently some limitations that often necessitate
113+
extra annotation that you might typically expect to be redundant.
114+
* Type inference doesn't work as well as normal, hence extra type annotations
115+
might be needed;
116+
* The captured variables in FnMut and Fn closures are references, so need to be
117+
dereferenced;
104118
* Types cannot be annotated in the list of captured variables;
105-
* Either none or all of the closure arguments must be annotated; though `_` can be used;
119+
* If any of the closure arguments are annotated with types (i.e. `|a:i32|0`)
120+
then all must be (though `_` can be used), and patterns can no longer be used
121+
(i.e. `|&a:&i32|0` will not work).
106122
* The `move` keyword must be present if any variables are captured.
107123

108124
## License
109-
Licensed under Apache License, Version 2.0, ([LICENSE.txt](LICENSE.txt) or http://www.apache.org/licenses/LICENSE-2.0).
125+
Licensed under Apache License, Version 2.0, ([LICENSE.txt](LICENSE.txt) or
126+
http://www.apache.org/licenses/LICENSE-2.0).
110127

111-
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions.
128+
Unless you explicitly state otherwise, any contribution intentionally submitted
129+
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
130+
licensed as above, without any additional terms or conditions.

0 commit comments

Comments
 (0)