Skip to content

Commit 0a01d82

Browse files
committed
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
1 parent ff513b1 commit 0a01d82

File tree

4 files changed

+89
-29
lines changed

4 files changed

+89
-29
lines changed

src/libcore/future.rs

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import either::Either;
1919
import pipes::recv;
20+
import unsafe::copy_lifetime;
2021

2122
export Future;
2223
export extensions;
@@ -31,18 +32,29 @@ export spawn;
3132
export future_pipe;
3233

3334
#[doc = "The future type"]
34-
enum Future<A> = {
35-
mut v: Either<@A, fn@() -> A>
36-
};
35+
struct Future<A> {
36+
/*priv*/ mut state: FutureState<A>;
37+
}
3738

38-
/// Methods on the `future` type
39-
impl<A:copy send> Future<A> {
39+
priv enum FutureState<A> {
40+
Pending(fn@() -> A),
41+
Evaluating,
42+
Forced(A)
43+
}
4044

45+
/// Methods on the `future` type
46+
impl<A:copy> Future<A> {
4147
fn get() -> A {
4248
//! Get the value of the future
4349
4450
get(&self)
4551
}
52+
}
53+
54+
impl<A> Future<A> {
55+
fn get_ref(&self) -> &self/A {
56+
get_ref(self)
57+
}
4658

4759
fn with<B>(blk: fn((&A)) -> B) -> B {
4860
//! Work with the value without copying it
@@ -59,9 +71,7 @@ fn from_value<A>(+val: A) -> Future<A> {
5971
* not block.
6072
*/
6173

62-
Future({
63-
mut v: either::Left(@val)
64-
})
74+
Future {state: Forced(val)}
6575
}
6676

6777
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> {
8393
}
8494
}
8595

86-
fn from_fn<A>(f: fn@() -> A) -> Future<A> {
96+
fn from_fn<A>(+f: @fn() -> A) -> Future<A> {
8797
/*!
8898
* Create a future from a function.
8999
*
@@ -92,9 +102,7 @@ fn from_fn<A>(f: fn@() -> A) -> Future<A> {
92102
* function. It is not spawned into another task.
93103
*/
94104

95-
Future({
96-
mut v: either::Right(f)
97-
})
105+
Future {state: Pending(f)}
98106
}
99107

100108
fn spawn<A:send>(+blk: fn~() -> A) -> Future<A> {
@@ -110,24 +118,54 @@ fn spawn<A:send>(+blk: fn~() -> A) -> Future<A> {
110118
}))
111119
}
112120

121+
fn get_ref<A>(future: &r/Future<A>) -> &r/A {
122+
/*!
123+
* Executes the future's closure and then returns a borrowed
124+
* pointer to the result. The borrowed pointer lasts as long as
125+
* the future.
126+
*/
127+
128+
// The unsafety here is to hide the aliases from borrowck, which
129+
// would otherwise be concerned that someone might reassign
130+
// `future.state` and cause the value of the future to be freed.
131+
// But *we* know that once `future.state` is `Forced()` it will
132+
// never become "unforced"---so we can safely return a pointer
133+
// into the interior of the Forced() variant which will last as
134+
// long as the future itself.
135+
136+
match future.state {
137+
Forced(ref v) => { // v here has type &A, but with a shorter lifetime.
138+
return unsafe{ copy_lifetime(future, v) }; // ...extend it.
139+
}
140+
Evaluating => {
141+
fail ~"Recursive forcing of future!";
142+
}
143+
Pending(_) => {}
144+
}
145+
146+
let mut state = Evaluating;
147+
state <-> future.state;
148+
match move state {
149+
Forced(_) | Evaluating => {
150+
fail ~"Logic error.";
151+
}
152+
Pending(move f) => {
153+
future.state = Forced(f());
154+
return get_ref(future);
155+
}
156+
}
157+
}
158+
113159
fn get<A:copy>(future: &Future<A>) -> A {
114160
//! Get the value of the future
115161
116-
do with(future) |v| { *v }
162+
*get_ref(future)
117163
}
118164

119165
fn with<A,B>(future: &Future<A>, blk: fn((&A)) -> B) -> B {
120166
//! Work with the value without copying it
121167
122-
let v = match copy future.v {
123-
either::Left(v) => v,
124-
either::Right(f) => {
125-
let v = @f();
126-
future.v = either::Left(v);
127-
v
128-
}
129-
};
130-
blk(v)
168+
blk(get_ref(future))
131169
}
132170

133171
proto! future_pipe (
@@ -152,8 +190,7 @@ fn test_from_port() {
152190

153191
#[test]
154192
fn test_from_fn() {
155-
let f = fn@() -> ~str { ~"brail" };
156-
let f = from_fn(f);
193+
let f = from_fn(|| ~"brail");
157194
assert get(&f) == ~"brail";
158195
}
159196

@@ -169,6 +206,18 @@ fn test_with() {
169206
assert with(&f, |v| *v) == ~"nail";
170207
}
171208

209+
#[test]
210+
fn test_get_ref_method() {
211+
let f = from_value(22);
212+
assert *f.get_ref() == 22;
213+
}
214+
215+
#[test]
216+
fn test_get_ref_fn() {
217+
let f = from_value(22);
218+
assert *get_ref(&f) == 22;
219+
}
220+
172221
#[test]
173222
fn test_interface_with() {
174223
let f = from_value(~"kale");

src/libcore/ptr.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Unsafe pointer utility functions
22
33
export addr_of;
4-
export assimilate;
4+
export to_unsafe_ptr;
55
export mut_addr_of;
66
export offset;
77
export const_offset;
@@ -136,9 +136,10 @@ unsafe fn memset<T>(dst: *mut T, c: int, count: uint) {
136136
("assimilate" because it makes the pointer forget its region.)
137137
*/
138138
#[inline(always)]
139-
fn assimilate<T>(thing: &T) -> *T unsafe {
139+
fn to_unsafe_ptr<T>(thing: &T) -> *T unsafe {
140140
unsafe::reinterpret_cast(thing)
141141
}
142+
142143
/**
143144
Cast a region pointer - &T - to a uint.
144145
This is safe, but is implemented with an unsafe block due to

src/libcore/unsafe.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export SharedMutableState, shared_mutable_state, clone_shared_mutable_state;
77
export get_shared_mutable_state, get_shared_immutable_state;
88
export unwrap_shared_mutable_state;
99
export Exclusive, exclusive, unwrap_exclusive;
10+
export copy_lifetime;
1011

1112
import task::atomically;
1213

@@ -57,15 +58,24 @@ unsafe fn transmute<L, G>(-thing: L) -> G {
5758

5859
/// Coerce an immutable reference to be mutable.
5960
unsafe fn transmute_mut<T>(+ptr: &a/T) -> &a/mut T { transmute(ptr) }
61+
6062
/// Coerce a mutable reference to be immutable.
6163
unsafe fn transmute_immut<T>(+ptr: &a/mut T) -> &a/T { transmute(ptr) }
64+
6265
/// Coerce a borrowed pointer to have an arbitrary associated region.
6366
unsafe fn transmute_region<T>(+ptr: &a/T) -> &b/T { transmute(ptr) }
67+
6468
/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
6569
unsafe fn transmute_mut_region<T>(+ptr: &a/mut T) -> &b/mut T {
6670
transmute(ptr)
6771
}
6872

73+
/// Transforms lifetime of the second pointer to match the first.
74+
unsafe fn copy_lifetime<S,T>(_ptr: &a/S, ptr: &T) -> &a/T {
75+
transmute_region(ptr)
76+
}
77+
78+
6979
/****************************************************************************
7080
* Shared state & exclusive ARC
7181
****************************************************************************/

src/libstd/uv_ll.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
*/
2222

2323
import libc::size_t;
24-
import ptr::assimilate;
2524
import comm = core::comm;
25+
import ptr::to_unsafe_ptr;
2626

2727
// libuv struct mappings
2828
type uv_ip4_addr = {
@@ -824,7 +824,7 @@ unsafe fn ip4_name(src: &sockaddr_in) -> ~str {
824824
let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
825825
0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8];
826826
do vec::as_buf(dst) |dst_buf, size| {
827-
rustrt::rust_uv_ip4_name(assimilate(src),
827+
rustrt::rust_uv_ip4_name(to_unsafe_ptr(src),
828828
dst_buf, size as libc::size_t);
829829
// seems that checking the result of uv_ip4_name
830830
// doesn't work too well..
@@ -844,7 +844,7 @@ unsafe fn ip6_name(src: &sockaddr_in6) -> ~str {
844844
0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
845845
0u8,0u8,0u8,0u8,0u8,0u8];
846846
do vec::as_buf(dst) |dst_buf, size| {
847-
let src_unsafe_ptr = assimilate(src);
847+
let src_unsafe_ptr = to_unsafe_ptr(src);
848848
log(debug, fmt!("val of src *sockaddr_in6: %? sockaddr_in6: %?",
849849
src_unsafe_ptr, src));
850850
let result = rustrt::rust_uv_ip6_name(src_unsafe_ptr,

0 commit comments

Comments
 (0)