Skip to content

Commit 444fa1b

Browse files
committed
auto merge of #19467 : japaric/rust/uc, r=alexcrichton
This PR moves almost all our current uses of closures, both in public API and internal uses, to the new "unboxed" closures system. In most cases, downstream code that *only uses* closures will continue to work as it is. The reason is that the `|| {}` syntax can be inferred either as a boxed or an "unboxed" closure according to the context. For example the following code will continue to work: ``` rust some_option.map(|x| x.transform_with(upvar)) ``` And will get silently upgraded to an "unboxed" closure. In some other cases, it may be necessary to "annotate" which `Fn*` trait the closure implements: ``` // Change this |x| { /* body */} // to either of these |: x| { /* body */} // closure implements the FnOnce trait |&mut : x| { /* body */} // FnMut |&: x| { /* body */} // Fn ``` This mainly occurs when the closure is assigned to a variable first, and then passed to a function/method. ``` rust let closure = |: x| x.transform_with(upvar); some.option.map(closure) ``` (It's very likely that in the future, an improved inference engine will make this annotation unnecessary) Other cases that require annotation are closures that implement some trait via a blanket `impl`, for example: - `std::finally::Finally` - `regex::Replacer` - `std::str::CharEq` ``` rust string.trim_left_chars(|c: char| c.is_whitespace()) //~^ ERROR: the trait `Fn<(char,), bool>` is not implemented for the type `|char| -> bool` string.trim_left_chars(|&: c: char| c.is_whitespace()) // OK ``` Finally, all implementations of traits that contain boxed closures in the arguments of their methods are now broken. And will need to be updated to use unboxed closures. These are the main affected traits: - `serialize::Decoder` - `serialize::DecoderHelpers` - `serialize::Encoder` - `serialize::EncoderHelpers` - `rustrt::ToCStr` For example, change this: ``` rust // libserialize/json.rs impl<'a> Encoder<io::IoError> for Encoder<'a> { fn emit_enum(&mut self, _name: &str, f: |&mut Encoder<'a>| -> EncodeResult) -> EncodeResult { f(self) } } ``` to: ``` rust // libserialize/json.rs impl<'a> Encoder<io::IoError> for Encoder<'a> { fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where F: FnOnce(&mut Encoder<'a>) -> EncodeResult { f(self) } } ``` [breaking-change] --- ### How the `Fn*` bound has been selected I've chosen the bounds to make the functions/structs as "generic as possible", i.e. to let them allow the maximum amount of input. - An `F: FnOnce` bound accepts the three kinds of closures: `|:|`, `|&mut:|` and `|&:|`. - An `F: FnMut` bound only accepts "non-consuming" closures: `|&mut:|` and `|&:|`. - An `F: Fn` bound only accept the "immutable environment" closures: `|&:|`. This means that whenever possible the `FnOnce` bound has been used, if the `FnOnce` bound couldn't be used, then the `FnMut` was used. The `Fn` bound was never used in the whole repository. The `FnMut` bound was the most used, because it resembles the semantics of the current boxed closures: the closure can modify its environment, and the closure may be called several times. The `FnOnce` bound allows new semantics: you can move out the upvars when the closure is called. This can be effectively paired with the `move || {}` syntax to transfer ownership from the environment to the closure caller. In the case of trait methods, is hard to select the "right" bound since we can't control how the trait may be implemented by downstream users. In these cases, I have selected the bound based on how we use these traits in the repository. For this reason the selected bounds may not be ideal, and may require tweaking before stabilization. r? @aturon
2 parents 567b90f + b8e0b81 commit 444fa1b

File tree

194 files changed

+2534
-1761
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

194 files changed

+2534
-1761
lines changed

src/libarena/lib.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
html_root_url = "http://doc.rust-lang.org/nightly/")]
2929

3030
#![feature(unsafe_destructor)]
31+
#![feature(unboxed_closures)]
3132
#![allow(missing_docs)]
3233

3334
extern crate alloc;
@@ -209,7 +210,7 @@ impl Arena {
209210
}
210211

211212
#[inline]
212-
fn alloc_copy<T>(&self, op: || -> T) -> &mut T {
213+
fn alloc_copy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
213214
unsafe {
214215
let ptr = self.alloc_copy_inner(mem::size_of::<T>(),
215216
mem::min_align_of::<T>());
@@ -263,7 +264,7 @@ impl Arena {
263264
}
264265

265266
#[inline]
266-
fn alloc_noncopy<T>(&self, op: || -> T) -> &mut T {
267+
fn alloc_noncopy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
267268
unsafe {
268269
let tydesc = get_tydesc::<T>();
269270
let (ty_ptr, ptr) =
@@ -287,7 +288,7 @@ impl Arena {
287288
/// Allocates a new item in the arena, using `op` to initialize the value,
288289
/// and returns a reference to it.
289290
#[inline]
290-
pub fn alloc<T>(&self, op: || -> T) -> &mut T {
291+
pub fn alloc<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
291292
unsafe {
292293
if intrinsics::needs_drop::<T>() {
293294
self.alloc_noncopy(op)
@@ -339,7 +340,7 @@ fn test_arena_destructors_fail() {
339340
arena.alloc(|| { [0u8, 1u8, 2u8] });
340341
}
341342
// Now, panic while allocating
342-
arena.alloc::<Rc<int>>(|| {
343+
arena.alloc::<Rc<int>, _>(|| {
343344
panic!();
344345
});
345346
}

src/libcollections/bench.rs

+32-12
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@ use std::rand;
1313
use std::rand::Rng;
1414
use test::Bencher;
1515

16-
pub fn insert_rand_n<M>(n: uint, map: &mut M, b: &mut Bencher,
17-
insert: |&mut M, uint|,
18-
remove: |&mut M, uint|) {
16+
pub fn insert_rand_n<M, I, R>(n: uint,
17+
map: &mut M,
18+
b: &mut Bencher,
19+
mut insert: I,
20+
mut remove: R) where
21+
I: FnMut(&mut M, uint),
22+
R: FnMut(&mut M, uint),
23+
{
1924
// setup
2025
let mut rng = rand::weak_rng();
2126

@@ -31,9 +36,14 @@ pub fn insert_rand_n<M>(n: uint, map: &mut M, b: &mut Bencher,
3136
})
3237
}
3338

34-
pub fn insert_seq_n<M>(n: uint, map: &mut M, b: &mut Bencher,
35-
insert: |&mut M, uint|,
36-
remove: |&mut M, uint|) {
39+
pub fn insert_seq_n<M, I, R>(n: uint,
40+
map: &mut M,
41+
b: &mut Bencher,
42+
mut insert: I,
43+
mut remove: R) where
44+
I: FnMut(&mut M, uint),
45+
R: FnMut(&mut M, uint),
46+
{
3747
// setup
3848
for i in range(0u, n) {
3949
insert(map, i * 2);
@@ -48,9 +58,14 @@ pub fn insert_seq_n<M>(n: uint, map: &mut M, b: &mut Bencher,
4858
})
4959
}
5060

51-
pub fn find_rand_n<M, T>(n: uint, map: &mut M, b: &mut Bencher,
52-
insert: |&mut M, uint|,
53-
find: |&M, uint| -> T) {
61+
pub fn find_rand_n<M, T, I, F>(n: uint,
62+
map: &mut M,
63+
b: &mut Bencher,
64+
mut insert: I,
65+
mut find: F) where
66+
I: FnMut(&mut M, uint),
67+
F: FnMut(&M, uint) -> T,
68+
{
5469
// setup
5570
let mut rng = rand::weak_rng();
5671
let mut keys = Vec::from_fn(n, |_| rng.gen::<uint>() % n);
@@ -70,9 +85,14 @@ pub fn find_rand_n<M, T>(n: uint, map: &mut M, b: &mut Bencher,
7085
})
7186
}
7287

73-
pub fn find_seq_n<M, T>(n: uint, map: &mut M, b: &mut Bencher,
74-
insert: |&mut M, uint|,
75-
find: |&M, uint| -> T) {
88+
pub fn find_seq_n<M, T, I, F>(n: uint,
89+
map: &mut M,
90+
b: &mut Bencher,
91+
mut insert: I,
92+
mut find: F) where
93+
I: FnMut(&mut M, uint),
94+
F: FnMut(&M, uint) -> T,
95+
{
7696
// setup
7797
for i in range(0u, n) {
7898
insert(map, i);

src/libcollections/bit.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ impl<'a> Iterator<(uint, u32)> for MaskWords<'a> {
174174

175175
impl Bitv {
176176
#[inline]
177-
fn process(&mut self, other: &Bitv, op: |u32, u32| -> u32) -> bool {
177+
fn process<F>(&mut self, other: &Bitv, mut op: F) -> bool where F: FnMut(u32, u32) -> u32 {
178178
let len = other.storage.len();
179179
assert_eq!(self.storage.len(), len);
180180
let mut changed = false;
@@ -816,7 +816,7 @@ pub fn from_bytes(bytes: &[u8]) -> Bitv {
816816
/// let bv = from_fn(5, |i| { i % 2 == 0 });
817817
/// assert!(bv.eq_vec(&[true, false, true, false, true]));
818818
/// ```
819-
pub fn from_fn(len: uint, f: |index: uint| -> bool) -> Bitv {
819+
pub fn from_fn<F>(len: uint, mut f: F) -> Bitv where F: FnMut(uint) -> bool {
820820
let mut bitv = Bitv::with_capacity(len, false);
821821
for i in range(0u, len) {
822822
bitv.set(i, f(i));
@@ -1182,7 +1182,7 @@ impl BitvSet {
11821182
}
11831183

11841184
#[inline]
1185-
fn other_op(&mut self, other: &BitvSet, f: |u32, u32| -> u32) {
1185+
fn other_op<F>(&mut self, other: &BitvSet, mut f: F) where F: FnMut(u32, u32) -> u32 {
11861186
// Expand the vector if necessary
11871187
self.reserve(other.capacity());
11881188

@@ -1277,10 +1277,12 @@ impl BitvSet {
12771277
#[inline]
12781278
#[unstable = "matches collection reform specification, waiting for dust to settle"]
12791279
pub fn union<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> {
1280+
fn or(w1: u32, w2: u32) -> u32 { w1 | w2 }
1281+
12801282
TwoBitPositions {
12811283
set: self,
12821284
other: other,
1283-
merge: |w1, w2| w1 | w2,
1285+
merge: or,
12841286
current_word: 0u32,
12851287
next_idx: 0u
12861288
}
@@ -1306,11 +1308,13 @@ impl BitvSet {
13061308
#[inline]
13071309
#[unstable = "matches collection reform specification, waiting for dust to settle"]
13081310
pub fn intersection<'a>(&'a self, other: &'a BitvSet) -> Take<TwoBitPositions<'a>> {
1311+
fn bitand(w1: u32, w2: u32) -> u32 { w1 & w2 }
1312+
13091313
let min = cmp::min(self.capacity(), other.capacity());
13101314
TwoBitPositions {
13111315
set: self,
13121316
other: other,
1313-
merge: |w1, w2| w1 & w2,
1317+
merge: bitand,
13141318
current_word: 0u32,
13151319
next_idx: 0
13161320
}.take(min)
@@ -1343,10 +1347,12 @@ impl BitvSet {
13431347
#[inline]
13441348
#[unstable = "matches collection reform specification, waiting for dust to settle"]
13451349
pub fn difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> {
1350+
fn diff(w1: u32, w2: u32) -> u32 { w1 & !w2 }
1351+
13461352
TwoBitPositions {
13471353
set: self,
13481354
other: other,
1349-
merge: |w1, w2| w1 & !w2,
1355+
merge: diff,
13501356
current_word: 0u32,
13511357
next_idx: 0
13521358
}
@@ -1373,10 +1379,12 @@ impl BitvSet {
13731379
#[inline]
13741380
#[unstable = "matches collection reform specification, waiting for dust to settle"]
13751381
pub fn symmetric_difference<'a>(&'a self, other: &'a BitvSet) -> TwoBitPositions<'a> {
1382+
fn bitxor(w1: u32, w2: u32) -> u32 { w1 ^ w2 }
1383+
13761384
TwoBitPositions {
13771385
set: self,
13781386
other: other,
1379-
merge: |w1, w2| w1 ^ w2,
1387+
merge: bitxor,
13801388
current_word: 0u32,
13811389
next_idx: 0
13821390
}
@@ -1614,7 +1622,7 @@ pub struct BitPositions<'a> {
16141622
pub struct TwoBitPositions<'a> {
16151623
set: &'a BitvSet,
16161624
other: &'a BitvSet,
1617-
merge: |u32, u32|: 'a -> u32,
1625+
merge: fn(u32, u32) -> u32,
16181626
current_word: u32,
16191627
next_idx: uint
16201628
}

src/libcollections/btree/map.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,12 @@ pub struct MoveEntries<K, V> {
107107
}
108108

109109
/// An iterator over a BTreeMap's keys.
110-
pub type Keys<'a, K, V> = iter::Map<'static, (&'a K, &'a V), &'a K, Entries<'a, K, V>>;
110+
pub type Keys<'a, K, V> =
111+
iter::Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K>;
111112

112113
/// An iterator over a BTreeMap's values.
113-
pub type Values<'a, K, V> = iter::Map<'static, (&'a K, &'a V), &'a V, Entries<'a, K, V>>;
114+
pub type Values<'a, K, V> =
115+
iter::Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>;
114116

115117
/// A view into a single entry in a map, which may either be vacant or occupied.
116118
pub enum Entry<'a, K:'a, V:'a> {
@@ -1207,7 +1209,9 @@ impl<K, V> BTreeMap<K, V> {
12071209
/// ```
12081210
#[unstable = "matches collection reform specification, waiting for dust to settle"]
12091211
pub fn keys<'a>(&'a self) -> Keys<'a, K, V> {
1210-
self.iter().map(|(k, _)| k)
1212+
fn first<A, B>((a, _): (A, B)) -> A { a }
1213+
1214+
self.iter().map(first)
12111215
}
12121216

12131217
/// Gets an iterator over the values of the map.
@@ -1226,7 +1230,9 @@ impl<K, V> BTreeMap<K, V> {
12261230
/// ```
12271231
#[unstable = "matches collection reform specification, waiting for dust to settle"]
12281232
pub fn values<'a>(&'a self) -> Values<'a, K, V> {
1229-
self.iter().map(|(_, v)| v)
1233+
fn second<A, B>((_, b): (A, B)) -> B { b }
1234+
1235+
self.iter().map(second)
12301236
}
12311237

12321238
/// Return the number of elements in the map.

src/libcollections/btree/set.rs

+23-11
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ pub struct BTreeSet<T>{
3636
pub type Items<'a, T> = Keys<'a, T, ()>;
3737

3838
/// An owning iterator over a BTreeSet's items.
39-
pub type MoveItems<T> = iter::Map<'static, (T, ()), T, MoveEntries<T, ()>>;
39+
pub type MoveItems<T> =
40+
iter::Map<(T, ()), T, MoveEntries<T, ()>, fn((T, ())) -> T>;
4041

4142
/// A lazy iterator producing elements in the set difference (in-order).
4243
pub struct DifferenceItems<'a, T:'a> {
@@ -87,7 +88,9 @@ impl<T> BTreeSet<T> {
8788
/// Gets an iterator for moving out the BtreeSet's contents.
8889
#[unstable = "matches collection reform specification, waiting for dust to settle"]
8990
pub fn into_iter(self) -> MoveItems<T> {
90-
self.map.into_iter().map(|(k, _)| k)
91+
fn first<A, B>((a, _): (A, B)) -> A { a }
92+
93+
self.map.into_iter().map(first)
9194
}
9295
}
9396

@@ -600,22 +603,31 @@ mod test {
600603
assert!(hash::hash(&x) == hash::hash(&y));
601604
}
602605

603-
fn check(a: &[int],
604-
b: &[int],
605-
expected: &[int],
606-
f: |&BTreeSet<int>, &BTreeSet<int>, f: |&int| -> bool| -> bool) {
606+
struct Counter<'a, 'b> {
607+
i: &'a mut uint,
608+
expected: &'b [int],
609+
}
610+
611+
impl<'a, 'b> FnMut(&int) -> bool for Counter<'a, 'b> {
612+
extern "rust-call" fn call_mut(&mut self, (&x,): (&int,)) -> bool {
613+
assert_eq!(x, self.expected[*self.i]);
614+
*self.i += 1;
615+
true
616+
}
617+
}
618+
619+
fn check<F>(a: &[int], b: &[int], expected: &[int], f: F) where
620+
// FIXME Replace Counter with `Box<FnMut(_) -> _>`
621+
F: FnOnce(&BTreeSet<int>, &BTreeSet<int>, Counter) -> bool,
622+
{
607623
let mut set_a = BTreeSet::new();
608624
let mut set_b = BTreeSet::new();
609625

610626
for x in a.iter() { assert!(set_a.insert(*x)) }
611627
for y in b.iter() { assert!(set_b.insert(*y)) }
612628

613629
let mut i = 0;
614-
f(&set_a, &set_b, |x| {
615-
assert_eq!(*x, expected[i]);
616-
i += 1;
617-
true
618-
});
630+
f(&set_a, &set_b, Counter { i: &mut i, expected: expected });
619631
assert_eq!(i, expected.len());
620632
}
621633

src/libcollections/dlist.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -351,18 +351,16 @@ impl<T> DList<T> {
351351
/// println!("{}", e); // prints 2, then 4, then 11, then 7, then 8
352352
/// }
353353
/// ```
354-
pub fn insert_when(&mut self, elt: T, f: |&T, &T| -> bool) {
355-
{
356-
let mut it = self.iter_mut();
357-
loop {
358-
match it.peek_next() {
359-
None => break,
360-
Some(x) => if f(x, &elt) { break }
361-
}
362-
it.next();
354+
pub fn insert_when<F>(&mut self, elt: T, mut f: F) where F: FnMut(&T, &T) -> bool {
355+
let mut it = self.iter_mut();
356+
loop {
357+
match it.peek_next() {
358+
None => break,
359+
Some(x) => if f(x, &elt) { break }
363360
}
364-
it.insert_next(elt);
361+
it.next();
365362
}
363+
it.insert_next(elt);
366364
}
367365

368366
/// Merges `other` into this `DList`, using the function `f`.
@@ -371,7 +369,7 @@ impl<T> DList<T> {
371369
/// put `a` in the result if `f(a, b)` is true, and otherwise `b`.
372370
///
373371
/// This operation should compute in O(max(N, M)) time.
374-
pub fn merge(&mut self, mut other: DList<T>, f: |&T, &T| -> bool) {
372+
pub fn merge<F>(&mut self, mut other: DList<T>, mut f: F) where F: FnMut(&T, &T) -> bool {
375373
{
376374
let mut it = self.iter_mut();
377375
loop {

0 commit comments

Comments
 (0)