about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-04-01 10:11:46 -0400
committerNiko Matsakis <niko@alum.mit.edu>2015-04-01 14:40:44 -0400
commited63d32651105e56afceb94cbb86f115db235825 (patch)
treed1df549a70af147589428d8ade908d1f0560d62f /src/liballoc
parentd528aa9960cb9b937d8ef6c09905a6a8076d5f3a (diff)
downloadrust-ed63d32651105e56afceb94cbb86f115db235825.tar.gz
rust-ed63d32651105e56afceb94cbb86f115db235825.zip
Add (unstable) FnBox trait as a nicer replacement for `Thunk`. The doc
comment includes a test that also shows how it can be used.
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/boxed.rs75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 550b25ac3a7..8d3a63ceb50 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -355,3 +355,78 @@ impl<'a, 'b> From<&'b str> for Box<Error + Send + 'a> {
         }
     }
 }
+
+/// `FnBox` is a version of the `FnOnce` intended for use with boxed
+/// closure objects. The idea is that where one would normally store a
+/// `Box<FnOnce()>` in a data structure, you should use
+/// `Box<FnBox()>`. The two traits behave essentially the same, except
+/// that a `FnBox` closure can only be called if it is boxed. (Note
+/// that `FnBox` may be deprecated in the future if `Box<FnOnce()>`
+/// closures become directly usable.)
+///
+/// ### Example
+///
+/// Here is a snippet of code which creates a hashmap full of boxed
+/// once closures and then removes them one by one, calling each
+/// closure as it is removed. Note that the type of the closures
+/// stored in the map is `Box<FnBox() -> i32>` and not `Box<FnOnce()
+/// -> i32>`.
+///
+/// ```
+/// #![feature(core)]
+///
+/// use std::boxed::FnBox;
+/// use std::collections::HashMap;
+///
+/// fn make_map() -> HashMap<i32, Box<FnBox() -> i32>> {
+///     let mut map: HashMap<i32, Box<FnBox() -> i32>> = HashMap::new();
+///     map.insert(1, Box::new(|| 22));
+///     map.insert(2, Box::new(|| 44));
+///     map
+/// }
+///
+/// fn main() {
+///     let mut map = make_map();
+///     for i in &[1, 2] {
+///         let f = map.remove(&i).unwrap();
+///         assert_eq!(f(), i * 22);
+///     }
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[rustc_paren_sugar]
+#[unstable(feature = "core", reason = "Newly introduced")]
+pub trait FnBox<A> {
+    type Output;
+
+    extern "rust-call" fn call_box(self: Box<Self>, args: A) -> Self::Output;
+}
+
+#[cfg(not(stage0))]
+impl<A,F> FnBox<A> for F
+    where F: FnOnce<A>
+{
+    type Output = F::Output;
+
+    extern "rust-call" fn call_box(self: Box<F>, args: A) -> F::Output {
+        self.call_once(args)
+    }
+}
+
+#[cfg(not(stage0))]
+impl<A,R> FnOnce<A> for Box<FnBox<A,Output=R>> {
+    type Output = R;
+
+    extern "rust-call" fn call_once(self, args: A) -> R {
+        self.call_box(args)
+    }
+}
+
+#[cfg(not(stage0))]
+impl<A,R> FnOnce<A> for Box<FnBox<A,Output=R>+Send> {
+    type Output = R;
+
+    extern "rust-call" fn call_once(self, args: A) -> R {
+        self.call_box(args)
+    }
+}