diff --git a/src/libcore/future.rs b/src/libcore/future.rs
index 2d9bfb4c81c3..e176b2544d4e 100644
--- a/src/libcore/future.rs
+++ b/src/libcore/future.rs
@@ -17,6 +17,7 @@
import either::Either;
import pipes::recv;
+import unsafe::copy_lifetime;
export Future;
export extensions;
@@ -31,18 +32,29 @@ export spawn;
export future_pipe;
#[doc = "The future type"]
-enum Future = {
- mut v: Either<@A, fn@() -> A>
-};
+struct Future {
+ /*priv*/ mut state: FutureState;
+}
+
+priv enum FutureState {
+ Pending(fn@() -> A),
+ Evaluating,
+ Forced(A)
+}
/// Methods on the `future` type
-impl Future {
-
+impl Future {
fn get() -> A {
//! Get the value of the future
get(&self)
}
+}
+
+impl Future {
+ fn get_ref(&self) -> &self/A {
+ get_ref(self)
+ }
fn with(blk: fn((&A)) -> B) -> B {
//! Work with the value without copying it
@@ -59,9 +71,7 @@ fn from_value(+val: A) -> Future {
* not block.
*/
- Future({
- mut v: either::Left(@val)
- })
+ Future {state: Forced(val)}
}
fn from_port(+port: future_pipe::client::waiting) -> Future {
@@ -83,7 +93,7 @@ fn from_port(+port: future_pipe::client::waiting) -> Future {
}
}
-fn from_fn(f: fn@() -> A) -> Future {
+fn from_fn(+f: @fn() -> A) -> Future {
/*!
* Create a future from a function.
*
@@ -92,9 +102,7 @@ fn from_fn(f: fn@() -> A) -> Future {
* function. It is not spawned into another task.
*/
- Future({
- mut v: either::Right(f)
- })
+ Future {state: Pending(f)}
}
fn spawn(+blk: fn~() -> A) -> Future {
@@ -110,24 +118,54 @@ fn spawn(+blk: fn~() -> A) -> Future {
}))
}
+fn get_ref(future: &r/Future) -> &r/A {
+ /*!
+ * Executes the future's closure and then returns a borrowed
+ * pointer to the result. The borrowed pointer lasts as long as
+ * the future.
+ */
+
+ // The unsafety here is to hide the aliases from borrowck, which
+ // would otherwise be concerned that someone might reassign
+ // `future.state` and cause the value of the future to be freed.
+ // But *we* know that once `future.state` is `Forced()` it will
+ // never become "unforced"---so we can safely return a pointer
+ // into the interior of the Forced() variant which will last as
+ // long as the future itself.
+
+ match future.state {
+ Forced(ref v) => { // v here has type &A, but with a shorter lifetime.
+ return unsafe{ copy_lifetime(future, v) }; // ...extend it.
+ }
+ Evaluating => {
+ fail ~"Recursive forcing of future!";
+ }
+ Pending(_) => {}
+ }
+
+ let mut state = Evaluating;
+ state <-> future.state;
+ match move state {
+ Forced(_) | Evaluating => {
+ fail ~"Logic error.";
+ }
+ Pending(move f) => {
+ future.state = Forced(f());
+ return get_ref(future);
+ }
+ }
+}
+
fn get(future: &Future) -> A {
//! Get the value of the future
- do with(future) |v| { *v }
+ *get_ref(future)
}
fn with(future: &Future, blk: fn((&A)) -> B) -> B {
//! Work with the value without copying it
- let v = match copy future.v {
- either::Left(v) => v,
- either::Right(f) => {
- let v = @f();
- future.v = either::Left(v);
- v
- }
- };
- blk(v)
+ blk(get_ref(future))
}
proto! future_pipe (
@@ -152,8 +190,7 @@ fn test_from_port() {
#[test]
fn test_from_fn() {
- let f = fn@() -> ~str { ~"brail" };
- let f = from_fn(f);
+ let f = from_fn(|| ~"brail");
assert get(&f) == ~"brail";
}
@@ -169,6 +206,18 @@ fn test_with() {
assert with(&f, |v| *v) == ~"nail";
}
+#[test]
+fn test_get_ref_method() {
+ let f = from_value(22);
+ assert *f.get_ref() == 22;
+}
+
+#[test]
+fn test_get_ref_fn() {
+ let f = from_value(22);
+ assert *get_ref(&f) == 22;
+}
+
#[test]
fn test_interface_with() {
let f = from_value(~"kale");
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 5e3b49da4839..2a99ce3f3d6c 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -1,7 +1,7 @@
//! Unsafe pointer utility functions
export addr_of;
-export assimilate;
+export to_unsafe_ptr;
export mut_addr_of;
export offset;
export const_offset;
@@ -136,9 +136,10 @@ unsafe fn memset(dst: *mut T, c: int, count: uint) {
("assimilate" because it makes the pointer forget its region.)
*/
#[inline(always)]
-fn assimilate(thing: &T) -> *T unsafe {
+fn to_unsafe_ptr(thing: &T) -> *T unsafe {
unsafe::reinterpret_cast(thing)
}
+
/**
Cast a region pointer - &T - to a uint.
This is safe, but is implemented with an unsafe block due to
diff --git a/src/libcore/unsafe.rs b/src/libcore/unsafe.rs
index 5f442dc28733..af3f082ea1b5 100644
--- a/src/libcore/unsafe.rs
+++ b/src/libcore/unsafe.rs
@@ -7,6 +7,7 @@ export SharedMutableState, shared_mutable_state, clone_shared_mutable_state;
export get_shared_mutable_state, get_shared_immutable_state;
export unwrap_shared_mutable_state;
export Exclusive, exclusive, unwrap_exclusive;
+export copy_lifetime;
import task::atomically;
@@ -57,15 +58,24 @@ unsafe fn transmute(-thing: L) -> G {
/// Coerce an immutable reference to be mutable.
unsafe fn transmute_mut(+ptr: &a/T) -> &a/mut T { transmute(ptr) }
+
/// Coerce a mutable reference to be immutable.
unsafe fn transmute_immut(+ptr: &a/mut T) -> &a/T { transmute(ptr) }
+
/// Coerce a borrowed pointer to have an arbitrary associated region.
unsafe fn transmute_region(+ptr: &a/T) -> &b/T { transmute(ptr) }
+
/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
unsafe fn transmute_mut_region(+ptr: &a/mut T) -> &b/mut T {
transmute(ptr)
}
+/// Transforms lifetime of the second pointer to match the first.
+unsafe fn copy_lifetime(_ptr: &a/S, ptr: &T) -> &a/T {
+ transmute_region(ptr)
+}
+
+
/****************************************************************************
* Shared state & exclusive ARC
****************************************************************************/
diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs
index 1e7c2c2c8247..aed7c3167705 100644
--- a/src/libstd/uv_ll.rs
+++ b/src/libstd/uv_ll.rs
@@ -21,8 +21,8 @@
*/
import libc::size_t;
-import ptr::assimilate;
import comm = core::comm;
+import ptr::to_unsafe_ptr;
// libuv struct mappings
type uv_ip4_addr = {
@@ -824,7 +824,7 @@ unsafe fn ip4_name(src: &sockaddr_in) -> ~str {
let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8];
do vec::as_buf(dst) |dst_buf, size| {
- rustrt::rust_uv_ip4_name(assimilate(src),
+ rustrt::rust_uv_ip4_name(to_unsafe_ptr(src),
dst_buf, size as libc::size_t);
// seems that checking the result of uv_ip4_name
// doesn't work too well..
@@ -844,7 +844,7 @@ unsafe fn ip6_name(src: &sockaddr_in6) -> ~str {
0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
0u8,0u8,0u8,0u8,0u8,0u8];
do vec::as_buf(dst) |dst_buf, size| {
- let src_unsafe_ptr = assimilate(src);
+ let src_unsafe_ptr = to_unsafe_ptr(src);
log(debug, fmt!("val of src *sockaddr_in6: %? sockaddr_in6: %?",
src_unsafe_ptr, src));
let result = rustrt::rust_uv_ip6_name(src_unsafe_ptr,