fn coerce(A) -> B using shared mutable state. Prints "hello world".
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use either::{Either,Left,Right}; | |
// SharedMutableState is an unsafe internal library used by both the ARC and the RWARC. | |
use private::{SharedMutableState, shared_mutable_state, clone_shared_mutable_state, | |
get_shared_mutable_state, get_shared_immutable_state}; | |
type ARC<T: Send> = SharedMutableState<T>; | |
fn ARC<T: Send>(data: T) -> ARC<T> unsafe { shared_mutable_state(data) } | |
fn clone<T: Send>(x: &ARC<T>) -> ARC<T> unsafe { clone_shared_mutable_state(x) } | |
fn get<T: Send>(x: &a/ARC<T>) -> &a/T unsafe { get_shared_immutable_state(x) } | |
fn get_mut<T: Send>(x: &a/ARC<T>) -> &a/mut T unsafe { get_shared_mutable_state(x) } | |
fn coerce<A: Send, B>(data: A) -> B { | |
let data = ~mut Some(data); | |
let getA = fn~() -> A { option::swap_unwrap(data) }; | |
let getB = fn~() -> B { fail }; | |
// Step 0: Start with an "undefined" lazy value for B. | |
let arc: ARC<Either<fn~() -> A, fn~() -> B>> = ARC(Right(getB)); | |
// We could well clone the ARC and send one handle to another task, but | |
// this way is simpler still. | |
let e1 = get(&arc); | |
let e2 = get_mut(&arc); | |
// Step 1: Alias the B. Ordinarily, the borrow-checker would "freeze" | |
// other mutable references to the same data. But with shared state, | |
// it can't know. | |
match *e1 { | |
Left(_) => fail, | |
Right(ref getB_alias) => { | |
// Step 2 (the "data race"): A pretends to be B. | |
*e2 = Left(getA); | |
// (the device has been modified.) | |
(*getB_alias)() | |
} | |
} | |
} | |
fn main() { | |
let x: ~str = coerce(~[104,101,108,108,111,32,119,111,114,108,100,0]); | |
io::println(x); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
About the use of
option::swap_unwrap
ingetA
: I use this because Rust currently doesn't allow moving out of captured noncopyable variables in closures -- if the closure were to be called more than once, it would duplicate the noncopyable. (swap_unwrap
dynamically enforces that it can't be called more than once.)We've been planning to add a notion of "oneshot closures" to the language, which get consumed when they are called, to support this idiom (which actually turns out to be pretty common). With oneshot closures, the code would look something like
let getA = once fn~(move data) -> A { return data }
.