preliminary work on making future's sendable

also various improvements to the ptr casting fns:
- rename assimilate() to to_unsafe_ptr() (fixes #3110)
- introduce `unsafe::copy_lifetime()` to copy the lifetime from one ptr to another
This commit is contained in:
Niko Matsakis
2012-08-27 16:08:17 -07:00
parent ff513b1bcd
commit 0a01d82f6f
4 changed files with 89 additions and 29 deletions

View File

@@ -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<A> = {
mut v: Either<@A, fn@() -> A>
};
struct Future<A> {
/*priv*/ mut state: FutureState<A>;
}
priv enum FutureState<A> {
Pending(fn@() -> A),
Evaluating,
Forced(A)
}
/// Methods on the `future` type
impl<A:copy send> Future<A> {
impl<A:copy> Future<A> {
fn get() -> A {
//! Get the value of the future
get(&self)
}
}
impl<A> Future<A> {
fn get_ref(&self) -> &self/A {
get_ref(self)
}
fn with<B>(blk: fn((&A)) -> B) -> B {
//! Work with the value without copying it
@@ -59,9 +71,7 @@ fn from_value<A>(+val: A) -> Future<A> {
* not block.
*/
Future({
mut v: either::Left(@val)
})
Future {state: Forced(val)}
}
fn from_port<A:send>(+port: future_pipe::client::waiting<A>) -> Future<A> {
@@ -83,7 +93,7 @@ fn from_port<A:send>(+port: future_pipe::client::waiting<A>) -> Future<A> {
}
}
fn from_fn<A>(f: fn@() -> A) -> Future<A> {
fn from_fn<A>(+f: @fn() -> A) -> Future<A> {
/*!
* Create a future from a function.
*
@@ -92,9 +102,7 @@ fn from_fn<A>(f: fn@() -> A) -> Future<A> {
* function. It is not spawned into another task.
*/
Future({
mut v: either::Right(f)
})
Future {state: Pending(f)}
}
fn spawn<A:send>(+blk: fn~() -> A) -> Future<A> {
@@ -110,24 +118,54 @@ fn spawn<A:send>(+blk: fn~() -> A) -> Future<A> {
}))
}
fn get_ref<A>(future: &r/Future<A>) -> &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<A:copy>(future: &Future<A>) -> A {
//! Get the value of the future
do with(future) |v| { *v }
*get_ref(future)
}
fn with<A,B>(future: &Future<A>, 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");