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,