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:
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
import either::Either;
|
import either::Either;
|
||||||
import pipes::recv;
|
import pipes::recv;
|
||||||
|
import unsafe::copy_lifetime;
|
||||||
|
|
||||||
export Future;
|
export Future;
|
||||||
export extensions;
|
export extensions;
|
||||||
@@ -31,18 +32,29 @@ export spawn;
|
|||||||
export future_pipe;
|
export future_pipe;
|
||||||
|
|
||||||
#[doc = "The future type"]
|
#[doc = "The future type"]
|
||||||
enum Future<A> = {
|
struct Future<A> {
|
||||||
mut v: Either<@A, fn@() -> A>
|
/*priv*/ mut state: FutureState<A>;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
priv enum FutureState<A> {
|
||||||
|
Pending(fn@() -> A),
|
||||||
|
Evaluating,
|
||||||
|
Forced(A)
|
||||||
|
}
|
||||||
|
|
||||||
/// Methods on the `future` type
|
/// Methods on the `future` type
|
||||||
impl<A:copy send> Future<A> {
|
impl<A:copy> Future<A> {
|
||||||
|
|
||||||
fn get() -> A {
|
fn get() -> A {
|
||||||
//! Get the value of the future
|
//! Get the value of the future
|
||||||
|
|
||||||
get(&self)
|
get(&self)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Future<A> {
|
||||||
|
fn get_ref(&self) -> &self/A {
|
||||||
|
get_ref(self)
|
||||||
|
}
|
||||||
|
|
||||||
fn with<B>(blk: fn((&A)) -> B) -> B {
|
fn with<B>(blk: fn((&A)) -> B) -> B {
|
||||||
//! Work with the value without copying it
|
//! Work with the value without copying it
|
||||||
@@ -59,9 +71,7 @@ fn from_value<A>(+val: A) -> Future<A> {
|
|||||||
* not block.
|
* not block.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Future({
|
Future {state: Forced(val)}
|
||||||
mut v: either::Left(@val)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_port<A:send>(+port: future_pipe::client::waiting<A>) -> Future<A> {
|
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.
|
* 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.
|
* function. It is not spawned into another task.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Future({
|
Future {state: Pending(f)}
|
||||||
mut v: either::Right(f)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn<A:send>(+blk: fn~() -> A) -> Future<A> {
|
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 {
|
fn get<A:copy>(future: &Future<A>) -> A {
|
||||||
//! Get the value of the future
|
//! 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 {
|
fn with<A,B>(future: &Future<A>, blk: fn((&A)) -> B) -> B {
|
||||||
//! Work with the value without copying it
|
//! Work with the value without copying it
|
||||||
|
|
||||||
let v = match copy future.v {
|
blk(get_ref(future))
|
||||||
either::Left(v) => v,
|
|
||||||
either::Right(f) => {
|
|
||||||
let v = @f();
|
|
||||||
future.v = either::Left(v);
|
|
||||||
v
|
|
||||||
}
|
|
||||||
};
|
|
||||||
blk(v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proto! future_pipe (
|
proto! future_pipe (
|
||||||
@@ -152,8 +190,7 @@ fn test_from_port() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_fn() {
|
fn test_from_fn() {
|
||||||
let f = fn@() -> ~str { ~"brail" };
|
let f = from_fn(|| ~"brail");
|
||||||
let f = from_fn(f);
|
|
||||||
assert get(&f) == ~"brail";
|
assert get(&f) == ~"brail";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,6 +206,18 @@ fn test_with() {
|
|||||||
assert with(&f, |v| *v) == ~"nail";
|
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]
|
#[test]
|
||||||
fn test_interface_with() {
|
fn test_interface_with() {
|
||||||
let f = from_value(~"kale");
|
let f = from_value(~"kale");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! Unsafe pointer utility functions
|
//! Unsafe pointer utility functions
|
||||||
|
|
||||||
export addr_of;
|
export addr_of;
|
||||||
export assimilate;
|
export to_unsafe_ptr;
|
||||||
export mut_addr_of;
|
export mut_addr_of;
|
||||||
export offset;
|
export offset;
|
||||||
export const_offset;
|
export const_offset;
|
||||||
@@ -136,9 +136,10 @@ unsafe fn memset<T>(dst: *mut T, c: int, count: uint) {
|
|||||||
("assimilate" because it makes the pointer forget its region.)
|
("assimilate" because it makes the pointer forget its region.)
|
||||||
*/
|
*/
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn assimilate<T>(thing: &T) -> *T unsafe {
|
fn to_unsafe_ptr<T>(thing: &T) -> *T unsafe {
|
||||||
unsafe::reinterpret_cast(thing)
|
unsafe::reinterpret_cast(thing)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Cast a region pointer - &T - to a uint.
|
Cast a region pointer - &T - to a uint.
|
||||||
This is safe, but is implemented with an unsafe block due to
|
This is safe, but is implemented with an unsafe block due to
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export SharedMutableState, shared_mutable_state, clone_shared_mutable_state;
|
|||||||
export get_shared_mutable_state, get_shared_immutable_state;
|
export get_shared_mutable_state, get_shared_immutable_state;
|
||||||
export unwrap_shared_mutable_state;
|
export unwrap_shared_mutable_state;
|
||||||
export Exclusive, exclusive, unwrap_exclusive;
|
export Exclusive, exclusive, unwrap_exclusive;
|
||||||
|
export copy_lifetime;
|
||||||
|
|
||||||
import task::atomically;
|
import task::atomically;
|
||||||
|
|
||||||
@@ -57,15 +58,24 @@ unsafe fn transmute<L, G>(-thing: L) -> G {
|
|||||||
|
|
||||||
/// Coerce an immutable reference to be mutable.
|
/// Coerce an immutable reference to be mutable.
|
||||||
unsafe fn transmute_mut<T>(+ptr: &a/T) -> &a/mut T { transmute(ptr) }
|
unsafe fn transmute_mut<T>(+ptr: &a/T) -> &a/mut T { transmute(ptr) }
|
||||||
|
|
||||||
/// Coerce a mutable reference to be immutable.
|
/// Coerce a mutable reference to be immutable.
|
||||||
unsafe fn transmute_immut<T>(+ptr: &a/mut T) -> &a/T { transmute(ptr) }
|
unsafe fn transmute_immut<T>(+ptr: &a/mut T) -> &a/T { transmute(ptr) }
|
||||||
|
|
||||||
/// Coerce a borrowed pointer to have an arbitrary associated region.
|
/// Coerce a borrowed pointer to have an arbitrary associated region.
|
||||||
unsafe fn transmute_region<T>(+ptr: &a/T) -> &b/T { transmute(ptr) }
|
unsafe fn transmute_region<T>(+ptr: &a/T) -> &b/T { transmute(ptr) }
|
||||||
|
|
||||||
/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
|
/// Coerce a borrowed mutable pointer to have an arbitrary associated region.
|
||||||
unsafe fn transmute_mut_region<T>(+ptr: &a/mut T) -> &b/mut T {
|
unsafe fn transmute_mut_region<T>(+ptr: &a/mut T) -> &b/mut T {
|
||||||
transmute(ptr)
|
transmute(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transforms lifetime of the second pointer to match the first.
|
||||||
|
unsafe fn copy_lifetime<S,T>(_ptr: &a/S, ptr: &T) -> &a/T {
|
||||||
|
transmute_region(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Shared state & exclusive ARC
|
* Shared state & exclusive ARC
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import libc::size_t;
|
import libc::size_t;
|
||||||
import ptr::assimilate;
|
|
||||||
import comm = core::comm;
|
import comm = core::comm;
|
||||||
|
import ptr::to_unsafe_ptr;
|
||||||
|
|
||||||
// libuv struct mappings
|
// libuv struct mappings
|
||||||
type uv_ip4_addr = {
|
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,
|
let dst: ~[u8] = ~[0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8,
|
||||||
0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8];
|
0u8,0u8,0u8,0u8,0u8,0u8,0u8,0u8];
|
||||||
do vec::as_buf(dst) |dst_buf, size| {
|
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);
|
dst_buf, size as libc::size_t);
|
||||||
// seems that checking the result of uv_ip4_name
|
// seems that checking the result of uv_ip4_name
|
||||||
// doesn't work too well..
|
// 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,0u8,0u8,
|
||||||
0u8,0u8,0u8,0u8,0u8,0u8];
|
0u8,0u8,0u8,0u8,0u8,0u8];
|
||||||
do vec::as_buf(dst) |dst_buf, size| {
|
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: %?",
|
log(debug, fmt!("val of src *sockaddr_in6: %? sockaddr_in6: %?",
|
||||||
src_unsafe_ptr, src));
|
src_unsafe_ptr, src));
|
||||||
let result = rustrt::rust_uv_ip6_name(src_unsafe_ptr,
|
let result = rustrt::rust_uv_ip6_name(src_unsafe_ptr,
|
||||||
|
|||||||
Reference in New Issue
Block a user