Skip to content

libstd: refactor future, remove get_ref, remove ~ indirection. #4023

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustdoc/markdown_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ pub fn future_writer_factory(
do task::spawn {
let (writer, future) = future_writer();
comm::send(writer_ch, move writer);
let s = future::get(&future);
let s = future.get();
comm::send(markdown_ch, (page, s));
}
comm::recv(writer_po)
Expand Down
117 changes: 27 additions & 90 deletions src/libstd/future.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
// NB: transitionary, de-mode-ing.
// tjc: allowing deprecated modes due to function issue.
// can re-forbid them after snapshot
#[forbid(deprecated_pattern)];

/*!
* A type representing values that may be computed concurrently and
* operations for working with them.
Expand Down Expand Up @@ -34,27 +29,37 @@ impl<A> Future<A> : Drop {
priv enum FutureState<A> {
Pending(fn~() -> A),
Evaluating,
Forced(~A)
Forced(A)
}

/// Methods on the `future` type
impl<A:Copy> Future<A> {
fn get() -> A {
//! Get the value of the future

get(&self)
self.with(|a| *a)
}
}

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
pure fn with<B>(&self, blk: pure fn(&A) -> B) -> B {
match self.state {
Forced(ref v) => { return blk(v); }
Evaluating => fail ~"Recursive forcing of future!",
Pending(_) => {}
}

with(&self, blk)
// We're lying about purity here, hence unsafe.
let mut state = Evaluating;
unsafe {
self.state <-> state;
match move state {
Forced(_) | Evaluating => fail ~"Logic error.",
Pending(move f) => {
self.state = Forced(move f());
self.with(blk)
}
}
}
}
}

Expand All @@ -66,7 +71,7 @@ pub fn from_value<A>(val: A) -> Future<A> {
* not block.
*/

Future {state: Forced(~(move val))}
Future {state: Forced(move val)}
}

pub fn from_port<A:Send>(port: PortOne<A>) ->
Expand Down Expand Up @@ -120,76 +125,26 @@ pub fn spawn<A:Send>(blk: fn~() -> A) -> Future<A> {
return from_port(move port);
}

pub 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);
}
}
}

pub fn get<A:Copy>(future: &Future<A>) -> A {
//! Get the value of the future

*get_ref(future)
}

pub fn with<A,B>(future: &Future<A>, blk: fn(&A) -> B) -> B {
//! Work with the value without copying it

blk(get_ref(future))
}

#[allow(non_implicitly_copyable_typarams)]
pub mod test {
#[test]
pub fn test_from_value() {
let f = from_value(~"snail");
assert get(&f) == ~"snail";
assert f.get() == ~"snail";
}

#[test]
pub fn test_from_port() {
let (ch, po) = oneshot::init();
send_one(move ch, ~"whale");
let f = from_port(move po);
assert get(&f) == ~"whale";
assert f.get() == ~"whale";
}

#[test]
pub fn test_from_fn() {
let f = from_fn(|| ~"brail");
assert get(&f) == ~"brail";
assert f.get() == ~"brail";
}

#[test]
Expand All @@ -198,24 +153,6 @@ pub mod test {
assert f.get() == ~"fail";
}

#[test]
pub fn test_with() {
let f = from_value(~"nail");
assert with(&f, |v| copy *v) == ~"nail";
}

#[test]
pub fn test_get_ref_method() {
let f = from_value(22);
assert *f.get_ref() == 22;
}

#[test]
pub fn test_get_ref_fn() {
let f = from_value(22);
assert *get_ref(&f) == 22;
}

#[test]
pub fn test_interface_with() {
let f = from_value(~"kale");
Expand All @@ -225,23 +162,23 @@ pub mod test {
#[test]
pub fn test_spawn() {
let f = spawn(|| ~"bale");
assert get(&f) == ~"bale";
assert f.get() == ~"bale";
}

#[test]
#[should_fail]
#[ignore(cfg(target_os = "win32"))]
pub fn test_futurefail() {
let f = spawn(|| fail);
let _x: ~str = get(&f);
let _x: ~str = f.get();
}

#[test]
pub fn test_sendable_future() {
let expected = ~"schlorf";
let f = do spawn |copy expected| { copy expected };
do task::spawn |move f, move expected| {
let actual = get(&f);
let actual = f.get();
assert actual == expected;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/bench/msgsend-ring-mutex-arcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ fn main() {
thread_ring(0, msg_per_task, option::unwrap(move num_chan), move num_port);

// synchronize
for futures.each |f| { future::get(f) };
for futures.each |f| { f.get() };

let stop = time::precise_time_s();

Expand Down
2 changes: 1 addition & 1 deletion src/test/bench/msgsend-ring-pipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ fn main() {
thread_ring(0, msg_per_task, option::unwrap(move num_chan), move num_port);

// synchronize
for futures.each |f| { future::get(f) };
for futures.each |f| { f.get() };

let stop = time::precise_time_s();

Expand Down
2 changes: 1 addition & 1 deletion src/test/bench/msgsend-ring-rw-arcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ fn main() {
thread_ring(0, msg_per_task, option::unwrap(move num_chan), move num_port);

// synchronize
for futures.each |f| { future::get(f) };
for futures.each |f| { f.get() };

let stop = time::precise_time_s();

Expand Down