<commit_before>// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
/*!
 * Communication between tasks
 *
 * Communication between tasks is facilitated by ports (in the receiving
 * task), and channels (in the sending task). Any number of channels may
 * feed into a single port.  Ports and channels may only transmit values
 * of unique types; that is, values that are statically guaranteed to be
 * accessed by a single 'owner' at a time.  Unique types include scalars,
 * vectors, strings, and records, tags, tuples and unique boxes (`~T`)
 * thereof. Most notably, shared boxes (`@T`) may not be transmitted
 * across channels.
 *
 * # Example
 *
 * ~~~
 * let po = comm::port();
 * let ch = comm::chan(po);
 *
 * do task::spawn {
 *     comm::send(ch, "Hello, World");
 * }
 *
 * io::println(comm::recv(p));
 * ~~~
 */

use either::Either;
use libc::size_t;

export Port;
export Chan;
export send;
export recv;
export peek;
export recv_chan;
export select2;
export methods;
export listen;

/**
 * A communication endpoint that can receive messages
 *
 * Each port has a unique per-task identity and may not be replicated or
 * transmitted. If a port value is copied, both copies refer to the same
 * port.  Ports may be associated with multiple `chan`s.
 */
enum Port<T: Send> {
    Port_(@PortPtr<T>)
}

// It's critical that this only have one variant, so it has a record
// layout, and will work in the rust_task structure in task.rs.
/**
 * A communication endpoint that can send messages
 *
 * Each channel is bound to a port when the channel is constructed, so
 * the destination port for a channel must exist before the channel
 * itself.  Channels are weak: a channel does not keep the port it is
 * bound to alive. If a channel attempts to send data to a dead port that
 * data will be silently dropped.  Channels may be duplicated and
 * themselves transmitted over other channels.
 */
enum Chan<T: Send> {
    Chan_(port_id)
}

/// Constructs a port
fn Port<T: Send>() -> Port<T> {
    Port_(@PortPtr(rustrt::new_port(sys::size_of::<T>() as size_t)))
}

impl<T: Send> Port<T> {

    fn chan() -> Chan<T> { Chan(self) }
    fn send(+v: T) { self.chan().send(move v) }
    fn recv() -> T { recv(self) }
    fn peek() -> bool { peek(self) }

}

impl<T: Send> Chan<T> {

    fn chan() -> Chan<T> { self }
    fn send(+v: T) { send(self, move v) }
    fn recv() -> T { recv_chan(self) }
    fn peek() -> bool { peek_chan(self) }

}

/// Open a new receiving channel for the duration of a function
fn listen<T: Send, U>(f: fn(Chan<T>) -> U) -> U {
    let po = Port();
    f(po.chan())
}

struct PortPtr<T:Send> {
    po: *rust_port,
  drop unsafe {
      do task::unkillable {
        // Once the port is detached it's guaranteed not to receive further
        // messages
        let yield = 0;
        let yieldp = ptr::addr_of(yield);
        rustrt::rust_port_begin_detach(self.po, yieldp);
        if yield != 0 {
            // Need to wait for the port to be detached
            task::yield();
        }
        rustrt::rust_port_end_detach(self.po);

        // Drain the port so that all the still-enqueued items get dropped
        while rustrt::rust_port_size(self.po) > 0 as size_t {
            recv_::<T>(self.po);
        }
        rustrt::del_port(self.po);
    }
  }
}

fn PortPtr<T: Send>(po: *rust_port) -> PortPtr<T> {
    PortPtr {
        po: po
    }
}

/**
 * Internal function for converting from a channel to a port
 *
 * # Failure
 *
 * Fails if the port is detached or dead. Fails if the port
 * is owned by a different task.
 */
fn as_raw_port<T: Send, U>(ch: comm::Chan<T>, f: fn(*rust_port) -> U) -> U {

    struct PortRef {
        p: *rust_port,
       drop {
         if !ptr::is_null(self.p) {
           rustrt::rust_port_drop(self.p);
         }
       }
    }

    fn PortRef(p: *rust_port) -> PortRef {
        PortRef {
            p: p
        }
    }

    let p = PortRef(rustrt::rust_port_take(*ch));

    if ptr::is_null(p.p) {
        fail ~"unable to locate port for channel"
    } else if rustrt::get_task_id() != rustrt::rust_port_task(p.p) {
        fail ~"unable to access unowned port"
    }

    f(p.p)
}

/**
 * Constructs a channel. The channel is bound to the port used to
 * construct it.
 */
fn Chan<T: Send>(p: Port<T>) -> Chan<T> {
    Chan_(rustrt::get_port_id((**p).po))
}

/**
 * Sends data over a channel. The sent data is moved into the channel,
 * whereupon the caller loses access to it.
 */
fn send<T: Send>(ch: Chan<T>, +data: T) {
    let Chan_(p) = ch;
    let data_ptr = ptr::addr_of(data) as *();
    let res = rustrt::rust_port_id_send(p, data_ptr);
    if res != 0 unsafe {
        // Data sent successfully
        unsafe::forget(move data);
    }
    task::yield();
}

/**
 * Receive from a port.  If no data is available on the port then the
 * task will block until data becomes available.
 */
fn recv<T: Send>(p: Port<T>) -> T { recv_((**p).po) }

/// Returns true if there are messages available
fn peek<T: Send>(p: Port<T>) -> bool { peek_((**p).po) }

#[doc(hidden)]
fn recv_chan<T: Send>(ch: comm::Chan<T>) -> T {
    as_raw_port(ch, |x|recv_(x))
}

fn peek_chan<T: Send>(ch: comm::Chan<T>) -> bool {
    as_raw_port(ch, |x|peek_(x))
}

/// Receive on a raw port pointer
fn recv_<T: Send>(p: *rust_port) -> T {
    let yield = 0;
    let yieldp = ptr::addr_of(yield);
    let mut res;
    res = rusti::init::<T>();
    rustrt::port_recv(ptr::addr_of(res) as *uint, p, yieldp);

    if yield != 0 {
        // Data isn't available yet, so res has not been initialized.
        task::yield();
    } else {
        // In the absence of compiler-generated preemption points
        // this is a good place to yield
        task::yield();
    }
    move res
}

fn peek_(p: *rust_port) -> bool {
    // Yield here before we check to see if someone sent us a message
    // FIXME #524, if the compiler generates yields, we don't need this
    task::yield();
    rustrt::rust_port_size(p) != 0 as libc::size_t
}

/// Receive on one of two ports
fn select2<A: Send, B: Send>(p_a: Port<A>, p_b: Port<B>)
    -> Either<A, B> {
    let ports = ~[(**p_a).po, (**p_b).po];
    let yield = 0, yieldp = ptr::addr_of(yield);

    let mut resport: *rust_port;
    resport = rusti::init::<*rust_port>();
    do vec::as_imm_buf(ports) |ports, n_ports| {
        rustrt::rust_port_select(ptr::addr_of(resport), ports,
                                 n_ports as size_t, yieldp);
    }

    if yield != 0 {
        // Wait for data
        task::yield();
    } else {
        // As in recv, this is a good place to yield anyway until
        // the compiler generates yield calls
        task::yield();
    }

    // Now we know the port we're supposed to receive from
    assert resport != ptr::null();

    if resport == (**p_a).po {
        either::Left(recv(p_a))
    } else if resport == (**p_b).po {
        either::Right(recv(p_b))
    } else {
        fail ~"unexpected result from rust_port_select";
    }
}

/* Implementation details */

#[allow(non_camel_case_types)] // runtime type
enum rust_port {}

#[allow(non_camel_case_types)] // runtime type
type port_id = int;

#[abi = "cdecl"]
extern mod rustrt {
    fn rust_port_id_send(target_port: port_id, data: *()) -> libc::uintptr_t;

    fn new_port(unit_sz: libc::size_t) -> *rust_port;
    fn del_port(po: *rust_port);
    fn rust_port_begin_detach(po: *rust_port,
                              yield: *libc::uintptr_t);
    fn rust_port_end_detach(po: *rust_port);
    fn get_port_id(po: *rust_port) -> port_id;
    fn rust_port_size(po: *rust_port) -> libc::size_t;
    fn port_recv(dptr: *uint, po: *rust_port,
                 yield: *libc::uintptr_t);
    fn rust_port_select(dptr: **rust_port, ports: **rust_port,
                        n_ports: libc::size_t,
                        yield: *libc::uintptr_t);
    fn rust_port_take(port_id: port_id) -> *rust_port;
    fn rust_port_drop(p: *rust_port);
    fn rust_port_task(p: *rust_port) -> libc::uintptr_t;
    fn get_task_id() -> libc::uintptr_t;
}

#[abi = "rust-intrinsic"]
extern mod rusti {
    fn init<T>() -> T;
}

/* Tests */

#[test]
fn create_port_and_chan() { let p = Port::<int>(); Chan(p); }

#[test]
fn send_int() {
    let p = Port::<int>();
    let c = Chan(p);
    send(c, 22);
}

#[test]
fn send_recv_fn() {
    let p = Port::<int>();
    let c = Chan::<int>(p);
    send(c, 42);
    assert (recv(p) == 42);
}

#[test]
fn send_recv_fn_infer() {
    let p = Port();
    let c = Chan(p);
    send(c, 42);
    assert (recv(p) == 42);
}

#[test]
fn chan_chan_infer() {
    let p = Port(), p2 = Port::<int>();
    let c = Chan(p);
    send(c, Chan(p2));
    recv(p);
}

#[test]
fn chan_chan() {
    let p = Port::<Chan<int>>(), p2 = Port::<int>();
    let c = Chan(p);
    send(c, Chan(p2));
    recv(p);
}

#[test]
fn test_peek() {
    let po = Port();
    let ch = Chan(po);
    assert !peek(po);
    send(ch, ());
    assert peek(po);
    recv(po);
    assert !peek(po);
}

#[test]
fn test_select2_available() {
    let po_a = Port();
    let po_b = Port();
    let ch_a = Chan(po_a);
    let ch_b = Chan(po_b);

    send(ch_a, ~"a");

    assert select2(po_a, po_b) == either::Left(~"a");

    send(ch_b, ~"b");

    assert select2(po_a, po_b) == either::Right(~"b");
}

#[test]
fn test_select2_rendezvous() {
    let po_a = Port();
    let po_b = Port();
    let ch_a = Chan(po_a);
    let ch_b = Chan(po_b);

    for iter::repeat(10) {
        do task::spawn {
            for iter::repeat(10) { task::yield() }
            send(ch_a, ~"a");
        };

        assert select2(po_a, po_b) == either::Left(~"a");

        do task::spawn {
            for iter::repeat(10) { task::yield() }
            send(ch_b, ~"b");
        };

        assert select2(po_a, po_b) == either::Right(~"b");
    }
}

#[test]
fn test_select2_stress() {
    let po_a = Port();
    let po_b = Port();
    let ch_a = Chan(po_a);
    let ch_b = Chan(po_b);

    let msgs = 100;
    let times = 4u;

    for iter::repeat(times) {
        do task::spawn {
            for iter::repeat(msgs) {
                send(ch_a, ~"a")
            }
        };
        do task::spawn {
            for iter::repeat(msgs) {
                send(ch_b, ~"b")
            }
        };
    }

    let mut as_ = 0;
    let mut bs = 0;
    for iter::repeat(msgs * times * 2u) {
        match select2(po_a, po_b) {
          either::Left(~"a") => as_ += 1,
          either::Right(~"b") => bs += 1,
          _ => fail ~"test_select_2_stress failed"
        }
    }

    assert as_ == 400;
    assert bs == 400;
}

#[test]
fn test_recv_chan() {
    let po = Port();
    let ch = Chan(po);
    send(ch, ~"flower");
    assert recv_chan(ch) == ~"flower";
}

#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn test_recv_chan_dead() {
    let ch = Chan(Port());
    send(ch, ~"flower");
    recv_chan(ch);
}

#[test]
#[ignore(cfg(windows))]
fn test_recv_chan_wrong_task() {
    let po = Port();
    let ch = Chan(po);
    send(ch, ~"flower");
    assert result::is_err(task::try(||
        recv_chan(ch)
    ))
}

#[test]
fn test_port_send() {
    let po = Port();
    po.send(());
    po.recv();
}

#[test]
fn test_chan_peek() {
    let po = Port();
    let ch = po.chan();
    ch.send(());
    assert ch.peek();
}

#[test]
fn test_listen() {
    do listen |parent| {
        do task::spawn {
            parent.send(~"oatmeal-salad");
        }
        assert parent.recv() == ~"oatmeal-salad";
    }
}

#[test]
#[ignore(cfg(windows))]
fn test_port_detach_fail() {
    for iter::repeat(100) {
        do task::spawn_unlinked {
            let po = Port();
            let ch = po.chan();

            do task::spawn {
                fail;
            }

            do task::spawn {
                ch.send(());
            }
        }
    }
}
<commit_msg>Doc fix, close #3419<commit_after>// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];
/*!
 * Communication between tasks
 *
 * Communication between tasks is facilitated by ports (in the receiving
 * task), and channels (in the sending task). Any number of channels may
 * feed into a single port.  Ports and channels may only transmit values
 * of unique types; that is, values that are statically guaranteed to be
 * accessed by a single 'owner' at a time.  Unique types include scalars,
 * vectors, strings, and records, tags, tuples and unique boxes (`~T`)
 * thereof. Most notably, shared boxes (`@T`) may not be transmitted
 * across channels.
 *
 * # Example
 *
 * ~~~
 * let po = comm::Port();
 * let ch = comm::Chan(po);
 *
 * do task::spawn {
 *     comm::send(ch, "Hello, World");
 * }
 *
 * io::println(comm::recv(p));
 * ~~~
 */

use either::Either;
use libc::size_t;

export Port;
export Chan;
export send;
export recv;
export peek;
export recv_chan;
export select2;
export methods;
export listen;

/**
 * A communication endpoint that can receive messages
 *
 * Each port has a unique per-task identity and may not be replicated or
 * transmitted. If a port value is copied, both copies refer to the same
 * port.  Ports may be associated with multiple `chan`s.
 */
enum Port<T: Send> {
    Port_(@PortPtr<T>)
}

// It's critical that this only have one variant, so it has a record
// layout, and will work in the rust_task structure in task.rs.
/**
 * A communication endpoint that can send messages
 *
 * Each channel is bound to a port when the channel is constructed, so
 * the destination port for a channel must exist before the channel
 * itself.  Channels are weak: a channel does not keep the port it is
 * bound to alive. If a channel attempts to send data to a dead port that
 * data will be silently dropped.  Channels may be duplicated and
 * themselves transmitted over other channels.
 */
enum Chan<T: Send> {
    Chan_(port_id)
}

/// Constructs a port
fn Port<T: Send>() -> Port<T> {
    Port_(@PortPtr(rustrt::new_port(sys::size_of::<T>() as size_t)))
}

impl<T: Send> Port<T> {

    fn chan() -> Chan<T> { Chan(self) }
    fn send(+v: T) { self.chan().send(move v) }
    fn recv() -> T { recv(self) }
    fn peek() -> bool { peek(self) }

}

impl<T: Send> Chan<T> {

    fn chan() -> Chan<T> { self }
    fn send(+v: T) { send(self, move v) }
    fn recv() -> T { recv_chan(self) }
    fn peek() -> bool { peek_chan(self) }

}

/// Open a new receiving channel for the duration of a function
fn listen<T: Send, U>(f: fn(Chan<T>) -> U) -> U {
    let po = Port();
    f(po.chan())
}

struct PortPtr<T:Send> {
    po: *rust_port,
  drop unsafe {
      do task::unkillable {
        // Once the port is detached it's guaranteed not to receive further
        // messages
        let yield = 0;
        let yieldp = ptr::addr_of(yield);
        rustrt::rust_port_begin_detach(self.po, yieldp);
        if yield != 0 {
            // Need to wait for the port to be detached
            task::yield();
        }
        rustrt::rust_port_end_detach(self.po);

        // Drain the port so that all the still-enqueued items get dropped
        while rustrt::rust_port_size(self.po) > 0 as size_t {
            recv_::<T>(self.po);
        }
        rustrt::del_port(self.po);
    }
  }
}

fn PortPtr<T: Send>(po: *rust_port) -> PortPtr<T> {
    PortPtr {
        po: po
    }
}

/**
 * Internal function for converting from a channel to a port
 *
 * # Failure
 *
 * Fails if the port is detached or dead. Fails if the port
 * is owned by a different task.
 */
fn as_raw_port<T: Send, U>(ch: comm::Chan<T>, f: fn(*rust_port) -> U) -> U {

    struct PortRef {
        p: *rust_port,
       drop {
         if !ptr::is_null(self.p) {
           rustrt::rust_port_drop(self.p);
         }
       }
    }

    fn PortRef(p: *rust_port) -> PortRef {
        PortRef {
            p: p
        }
    }

    let p = PortRef(rustrt::rust_port_take(*ch));

    if ptr::is_null(p.p) {
        fail ~"unable to locate port for channel"
    } else if rustrt::get_task_id() != rustrt::rust_port_task(p.p) {
        fail ~"unable to access unowned port"
    }

    f(p.p)
}

/**
 * Constructs a channel. The channel is bound to the port used to
 * construct it.
 */
fn Chan<T: Send>(p: Port<T>) -> Chan<T> {
    Chan_(rustrt::get_port_id((**p).po))
}

/**
 * Sends data over a channel. The sent data is moved into the channel,
 * whereupon the caller loses access to it.
 */
fn send<T: Send>(ch: Chan<T>, +data: T) {
    let Chan_(p) = ch;
    let data_ptr = ptr::addr_of(data) as *();
    let res = rustrt::rust_port_id_send(p, data_ptr);
    if res != 0 unsafe {
        // Data sent successfully
        unsafe::forget(move data);
    }
    task::yield();
}

/**
 * Receive from a port.  If no data is available on the port then the
 * task will block until data becomes available.
 */
fn recv<T: Send>(p: Port<T>) -> T { recv_((**p).po) }

/// Returns true if there are messages available
fn peek<T: Send>(p: Port<T>) -> bool { peek_((**p).po) }

#[doc(hidden)]
fn recv_chan<T: Send>(ch: comm::Chan<T>) -> T {
    as_raw_port(ch, |x|recv_(x))
}

fn peek_chan<T: Send>(ch: comm::Chan<T>) -> bool {
    as_raw_port(ch, |x|peek_(x))
}

/// Receive on a raw port pointer
fn recv_<T: Send>(p: *rust_port) -> T {
    let yield = 0;
    let yieldp = ptr::addr_of(yield);
    let mut res;
    res = rusti::init::<T>();
    rustrt::port_recv(ptr::addr_of(res) as *uint, p, yieldp);

    if yield != 0 {
        // Data isn't available yet, so res has not been initialized.
        task::yield();
    } else {
        // In the absence of compiler-generated preemption points
        // this is a good place to yield
        task::yield();
    }
    move res
}

fn peek_(p: *rust_port) -> bool {
    // Yield here before we check to see if someone sent us a message
    // FIXME #524, if the compiler generates yields, we don't need this
    task::yield();
    rustrt::rust_port_size(p) != 0 as libc::size_t
}

/// Receive on one of two ports
fn select2<A: Send, B: Send>(p_a: Port<A>, p_b: Port<B>)
    -> Either<A, B> {
    let ports = ~[(**p_a).po, (**p_b).po];
    let yield = 0, yieldp = ptr::addr_of(yield);

    let mut resport: *rust_port;
    resport = rusti::init::<*rust_port>();
    do vec::as_imm_buf(ports) |ports, n_ports| {
        rustrt::rust_port_select(ptr::addr_of(resport), ports,
                                 n_ports as size_t, yieldp);
    }

    if yield != 0 {
        // Wait for data
        task::yield();
    } else {
        // As in recv, this is a good place to yield anyway until
        // the compiler generates yield calls
        task::yield();
    }

    // Now we know the port we're supposed to receive from
    assert resport != ptr::null();

    if resport == (**p_a).po {
        either::Left(recv(p_a))
    } else if resport == (**p_b).po {
        either::Right(recv(p_b))
    } else {
        fail ~"unexpected result from rust_port_select";
    }
}

/* Implementation details */

#[allow(non_camel_case_types)] // runtime type
enum rust_port {}

#[allow(non_camel_case_types)] // runtime type
type port_id = int;

#[abi = "cdecl"]
extern mod rustrt {
    fn rust_port_id_send(target_port: port_id, data: *()) -> libc::uintptr_t;

    fn new_port(unit_sz: libc::size_t) -> *rust_port;
    fn del_port(po: *rust_port);
    fn rust_port_begin_detach(po: *rust_port,
                              yield: *libc::uintptr_t);
    fn rust_port_end_detach(po: *rust_port);
    fn get_port_id(po: *rust_port) -> port_id;
    fn rust_port_size(po: *rust_port) -> libc::size_t;
    fn port_recv(dptr: *uint, po: *rust_port,
                 yield: *libc::uintptr_t);
    fn rust_port_select(dptr: **rust_port, ports: **rust_port,
                        n_ports: libc::size_t,
                        yield: *libc::uintptr_t);
    fn rust_port_take(port_id: port_id) -> *rust_port;
    fn rust_port_drop(p: *rust_port);
    fn rust_port_task(p: *rust_port) -> libc::uintptr_t;
    fn get_task_id() -> libc::uintptr_t;
}

#[abi = "rust-intrinsic"]
extern mod rusti {
    fn init<T>() -> T;
}

/* Tests */

#[test]
fn create_port_and_chan() { let p = Port::<int>(); Chan(p); }

#[test]
fn send_int() {
    let p = Port::<int>();
    let c = Chan(p);
    send(c, 22);
}

#[test]
fn send_recv_fn() {
    let p = Port::<int>();
    let c = Chan::<int>(p);
    send(c, 42);
    assert (recv(p) == 42);
}

#[test]
fn send_recv_fn_infer() {
    let p = Port();
    let c = Chan(p);
    send(c, 42);
    assert (recv(p) == 42);
}

#[test]
fn chan_chan_infer() {
    let p = Port(), p2 = Port::<int>();
    let c = Chan(p);
    send(c, Chan(p2));
    recv(p);
}

#[test]
fn chan_chan() {
    let p = Port::<Chan<int>>(), p2 = Port::<int>();
    let c = Chan(p);
    send(c, Chan(p2));
    recv(p);
}

#[test]
fn test_peek() {
    let po = Port();
    let ch = Chan(po);
    assert !peek(po);
    send(ch, ());
    assert peek(po);
    recv(po);
    assert !peek(po);
}

#[test]
fn test_select2_available() {
    let po_a = Port();
    let po_b = Port();
    let ch_a = Chan(po_a);
    let ch_b = Chan(po_b);

    send(ch_a, ~"a");

    assert select2(po_a, po_b) == either::Left(~"a");

    send(ch_b, ~"b");

    assert select2(po_a, po_b) == either::Right(~"b");
}

#[test]
fn test_select2_rendezvous() {
    let po_a = Port();
    let po_b = Port();
    let ch_a = Chan(po_a);
    let ch_b = Chan(po_b);

    for iter::repeat(10) {
        do task::spawn {
            for iter::repeat(10) { task::yield() }
            send(ch_a, ~"a");
        };

        assert select2(po_a, po_b) == either::Left(~"a");

        do task::spawn {
            for iter::repeat(10) { task::yield() }
            send(ch_b, ~"b");
        };

        assert select2(po_a, po_b) == either::Right(~"b");
    }
}

#[test]
fn test_select2_stress() {
    let po_a = Port();
    let po_b = Port();
    let ch_a = Chan(po_a);
    let ch_b = Chan(po_b);

    let msgs = 100;
    let times = 4u;

    for iter::repeat(times) {
        do task::spawn {
            for iter::repeat(msgs) {
                send(ch_a, ~"a")
            }
        };
        do task::spawn {
            for iter::repeat(msgs) {
                send(ch_b, ~"b")
            }
        };
    }

    let mut as_ = 0;
    let mut bs = 0;
    for iter::repeat(msgs * times * 2u) {
        match select2(po_a, po_b) {
          either::Left(~"a") => as_ += 1,
          either::Right(~"b") => bs += 1,
          _ => fail ~"test_select_2_stress failed"
        }
    }

    assert as_ == 400;
    assert bs == 400;
}

#[test]
fn test_recv_chan() {
    let po = Port();
    let ch = Chan(po);
    send(ch, ~"flower");
    assert recv_chan(ch) == ~"flower";
}

#[test]
#[should_fail]
#[ignore(cfg(windows))]
fn test_recv_chan_dead() {
    let ch = Chan(Port());
    send(ch, ~"flower");
    recv_chan(ch);
}

#[test]
#[ignore(cfg(windows))]
fn test_recv_chan_wrong_task() {
    let po = Port();
    let ch = Chan(po);
    send(ch, ~"flower");
    assert result::is_err(task::try(||
        recv_chan(ch)
    ))
}

#[test]
fn test_port_send() {
    let po = Port();
    po.send(());
    po.recv();
}

#[test]
fn test_chan_peek() {
    let po = Port();
    let ch = po.chan();
    ch.send(());
    assert ch.peek();
}

#[test]
fn test_listen() {
    do listen |parent| {
        do task::spawn {
            parent.send(~"oatmeal-salad");
        }
        assert parent.recv() == ~"oatmeal-salad";
    }
}

#[test]
#[ignore(cfg(windows))]
fn test_port_detach_fail() {
    for iter::repeat(100) {
        do task::spawn_unlinked {
            let po = Port();
            let ch = po.chan();

            do task::spawn {
                fail;
            }

            do task::spawn {
                ch.send(());
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Random number generation

export rng, seed, seeded_rng, weighted, extensions;
export xorshift, seeded_xorshift;

enum rctx {}

#[abi = "cdecl"]
extern mod rustrt {
    fn rand_seed() -> ~[u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: ~[u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

/// A random number generator
iface rng {
    /// Return the next random integer
    fn next() -> u32;
}

/// A value with a particular weight compared to other values
type weighted<T> = { weight: uint, item: T };

/// Extension methods for random number generators
impl extensions for rng {

    /// Return a random int
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    /**
     * Return an int randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_int_range(start: int, end: int) -> int {
        assert start < end;
        start + int::abs(self.gen_int() % (end - start))
    }

    /// Return a random i8
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    /// Return a random i16
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    /// Return a random i32
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    /// Return a random i64
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    /// Return a random uint
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    /**
     * Return a uint randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_uint_range(start: uint, end: uint) -> uint {
        assert start < end;
        start + (self.gen_uint() % (end - start))
    }

    /// Return a random u8
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    /// Return a random u16
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    /// Return a random u32
    fn gen_u32() -> u32 {
        self.next()
    }

    /// Return a random u64
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    /// Return a random float
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    /// Return a random f32
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    /// Return a random f64
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        let scale = u32::max_value as f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    /// Return a random char
    fn gen_char() -> char {
        self.next() as char
    }

    /**
     * Return a char randomly chosen from chars, failing if chars is empty
     */
    fn gen_char_from(chars: ~str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    /// Return a random bool
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    /// Return a bool with a 1 in n chance of true
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_range(1u, n + 1u) == 1u
        }
    }

    /**
     * Return a random string of the specified length composed of A-Z,a-z,0-9
     */
    fn gen_str(len: uint) -> ~str {
        let charset = ~"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                       abcdefghijklmnopqrstuvwxyz\
                       0123456789";
        let mut s = ~"";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    /// Return a random byte string of the specified length
    fn gen_bytes(len: uint) -> ~[u8] {
        do vec::from_fn(len) |_i| {
            self.gen_u8()
        }
    }

    /// Choose an item randomly, failing if values is empty
    fn choose<T:copy>(values: ~[T]) -> T {
        self.choose_option(values).get()
    }

    /// Choose some(item) randomly, returning none if values is empty
    fn choose_option<T:copy>(values: ~[T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_range(0u, values.len())])
        }
    }

    /**
     * Choose an item respecting the relative weights, failing if the sum of
     * the weights is 0
     */
    fn choose_weighted<T: copy>(v : ~[weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    /**
     * Choose some(item) respecting the relative weights, returning none if
     * the sum of the weights is 0
     */
    fn choose_weighted_option<T:copy>(v: ~[weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each |item| {
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each |item| {
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    /**
     * Return a vec containing copies of the items, in order, where
     * the weight of the item determines how many copies there are
     */
    fn weighted_vec<T:copy>(v: ~[weighted<T>]) -> ~[T] {
        let mut r = ~[];
        for v.each |item| {
            for uint::range(0u, item.weight) |_i| {
                vec::push(r, item.item);
            }
        }
        r
    }

    /// Shuffle a vec
    fn shuffle<T:copy>(values: ~[T]) -> ~[T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    /// Shuffle a mutable vec in place
    fn shuffle_mut<T>(&&values: ~[mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_range(0u, i + 1u));
        }
    }

}

class rand_res {
    let c: *rctx;
    new(c: *rctx) { self.c = c; }
    drop { rustrt::rand_free(self.c); }
}

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next((*self).c); }
}

/// Create a new random seed for seeded_rng
fn seed() -> ~[u8] {
    rustrt::rand_seed()
}

/// Create a random number generator with a system specified seed
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

/**
 * Create a random number generator using the specified seed. A generator
 * constructed with a given seed will generate the same sequence of values as
 * all other generators constructed with the same seed. The seed may be any
 * length.
 */
fn seeded_rng(seed: ~[u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

type xorshift_state = {
    mut x: u32,
    mut y: u32,
    mut z: u32,
    mut w: u32
};

impl of rng for xorshift_state {
    fn next() -> u32 {
        let x = self.x;
        let mut t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w = self.w;
        self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}

fn xorshift() -> rng {
    // constants taken from http://en.wikipedia.org/wiki/Xorshift
    seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32)
}

fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> rng {
    {mut x: x, mut y: y, mut z: z, mut w: w} as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed2() {
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        // Regression test that isaac is actually using the above vector
        let r = ra.next();
        #error("%?", r);
        assert r == 890007737u32 // on x86_64
            || r == 2935188040u32; // on x86
    }

    #[test]
    fn gen_int_range() {
        let r = rand::rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_range(5, -2);
    }

    #[test]
    fn gen_uint_range() {
        let r = rand::rng();
        let a = r.gen_uint_range(3u, 42u);
        assert a >= 3u && a < 42u;
        assert r.gen_uint_range(0u, 1u) == 0u;
        assert r.gen_uint_range(12u, 13u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_uint_range_fail() {
        rand::rng().gen_uint_range(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose(~[1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option(~[]) == none::<int>;
        assert r.choose_option(~[1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted(~[{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option(~[{weight: 1u, item: 42}]) ==
               some(42);
        assert r.choose_weighted_option(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option(~[]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.weighted_vec(~[]) == empty;
        assert r.weighted_vec(~[
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == ~[2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.shuffle(~[]) == empty;
        assert r.shuffle(~[1, 1, 1]) == ~[1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Prevent random floats from occasionally being greater than 1.<commit_after>//! Random number generation

export rng, seed, seeded_rng, weighted, extensions;
export xorshift, seeded_xorshift;

enum rctx {}

#[abi = "cdecl"]
extern mod rustrt {
    fn rand_seed() -> ~[u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: ~[u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

/// A random number generator
iface rng {
    /// Return the next random integer
    fn next() -> u32;
}

/// A value with a particular weight compared to other values
type weighted<T> = { weight: uint, item: T };

/// Extension methods for random number generators
impl extensions for rng {

    /// Return a random int
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    /**
     * Return an int randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_int_range(start: int, end: int) -> int {
        assert start < end;
        start + int::abs(self.gen_int() % (end - start))
    }

    /// Return a random i8
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    /// Return a random i16
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    /// Return a random i32
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    /// Return a random i64
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    /// Return a random uint
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    /**
     * Return a uint randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_uint_range(start: uint, end: uint) -> uint {
        assert start < end;
        start + (self.gen_uint() % (end - start))
    }

    /// Return a random u8
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    /// Return a random u16
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    /// Return a random u32
    fn gen_u32() -> u32 {
        self.next()
    }

    /// Return a random u64
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    /// Return a random float in the interval [0,1]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    /// Return a random f32 in the interval [0,1]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    /// Return a random f64 in the interval [0,1]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        const scale : f64 = (u32::max_value as f64) + 1.0f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    /// Return a random char
    fn gen_char() -> char {
        self.next() as char
    }

    /**
     * Return a char randomly chosen from chars, failing if chars is empty
     */
    fn gen_char_from(chars: ~str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    /// Return a random bool
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    /// Return a bool with a 1 in n chance of true
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_range(1u, n + 1u) == 1u
        }
    }

    /**
     * Return a random string of the specified length composed of A-Z,a-z,0-9
     */
    fn gen_str(len: uint) -> ~str {
        let charset = ~"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                       abcdefghijklmnopqrstuvwxyz\
                       0123456789";
        let mut s = ~"";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    /// Return a random byte string of the specified length
    fn gen_bytes(len: uint) -> ~[u8] {
        do vec::from_fn(len) |_i| {
            self.gen_u8()
        }
    }

    /// Choose an item randomly, failing if values is empty
    fn choose<T:copy>(values: ~[T]) -> T {
        self.choose_option(values).get()
    }

    /// Choose some(item) randomly, returning none if values is empty
    fn choose_option<T:copy>(values: ~[T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_range(0u, values.len())])
        }
    }

    /**
     * Choose an item respecting the relative weights, failing if the sum of
     * the weights is 0
     */
    fn choose_weighted<T: copy>(v : ~[weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    /**
     * Choose some(item) respecting the relative weights, returning none if
     * the sum of the weights is 0
     */
    fn choose_weighted_option<T:copy>(v: ~[weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each |item| {
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each |item| {
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    /**
     * Return a vec containing copies of the items, in order, where
     * the weight of the item determines how many copies there are
     */
    fn weighted_vec<T:copy>(v: ~[weighted<T>]) -> ~[T] {
        let mut r = ~[];
        for v.each |item| {
            for uint::range(0u, item.weight) |_i| {
                vec::push(r, item.item);
            }
        }
        r
    }

    /// Shuffle a vec
    fn shuffle<T:copy>(values: ~[T]) -> ~[T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    /// Shuffle a mutable vec in place
    fn shuffle_mut<T>(&&values: ~[mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_range(0u, i + 1u));
        }
    }

}

class rand_res {
    let c: *rctx;
    new(c: *rctx) { self.c = c; }
    drop { rustrt::rand_free(self.c); }
}

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next((*self).c); }
}

/// Create a new random seed for seeded_rng
fn seed() -> ~[u8] {
    rustrt::rand_seed()
}

/// Create a random number generator with a system specified seed
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

/**
 * Create a random number generator using the specified seed. A generator
 * constructed with a given seed will generate the same sequence of values as
 * all other generators constructed with the same seed. The seed may be any
 * length.
 */
fn seeded_rng(seed: ~[u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

type xorshift_state = {
    mut x: u32,
    mut y: u32,
    mut z: u32,
    mut w: u32
};

impl of rng for xorshift_state {
    fn next() -> u32 {
        let x = self.x;
        let mut t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w = self.w;
        self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}

fn xorshift() -> rng {
    // constants taken from http://en.wikipedia.org/wiki/Xorshift
    seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32)
}

fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> rng {
    {mut x: x, mut y: y, mut z: z, mut w: w} as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed2() {
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        // Regression test that isaac is actually using the above vector
        let r = ra.next();
        #error("%?", r);
        assert r == 890007737u32 // on x86_64
            || r == 2935188040u32; // on x86
    }

    #[test]
    fn gen_int_range() {
        let r = rand::rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_range(5, -2);
    }

    #[test]
    fn gen_uint_range() {
        let r = rand::rng();
        let a = r.gen_uint_range(3u, 42u);
        assert a >= 3u && a < 42u;
        assert r.gen_uint_range(0u, 1u) == 0u;
        assert r.gen_uint_range(12u, 13u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_uint_range_fail() {
        rand::rng().gen_uint_range(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose(~[1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option(~[]) == none::<int>;
        assert r.choose_option(~[1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted(~[{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option(~[{weight: 1u, item: 42}]) ==
               some(42);
        assert r.choose_weighted_option(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option(~[]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.weighted_vec(~[]) == empty;
        assert r.weighted_vec(~[
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == ~[2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.shuffle(~[]) == empty;
        assert r.shuffle(~[1, 1, 1]) == ~[1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>extern crate libc;
extern crate nix;
extern crate mio;

use bluetooth::{BtError, BtAddr, BtProtocol};
use platform::get_rfcomm_channel;
use std;
use std::io::{Read, Write};
use std::mem;
use std::error::Error;
use std::os::unix::io::AsRawFd;
use mio::{Poll, Ready};
use mio::deprecated::unix::Io; // TODO: mio::Io is deprecated

#[derive(Debug)]
pub struct BtSocket {
    io: Io,
}

impl BtSocket {
    pub fn new(proto: BtProtocol) -> Result<BtSocket, BtError> {
        match proto {
            BtProtocol::RFCOMM => {
                let fd = unsafe { libc::socket(AF_BLUETOOTH, libc::SOCK_STREAM, BtProtocolBlueZ::RFCOMM as i32) };
                if fd < 0 {
                    return Err(From::from(nix::Error::last()));
                } else {
                    Ok(From::from(Io::from_raw_fd(fd)))
                }
            }
        }
    }

    pub fn connect(&mut self, addr: BtAddr) -> Result<(), BtError> {
        let full_address : sockaddr_rc = sockaddr_rc {
            rc_family : AF_BLUETOOTH as u16,
            rc_bdaddr : addr,
            rc_channel : try!(get_rfcomm_channel(addr))
        };

        if unsafe { libc::connect(self.io.as_raw_fd(), mem::transmute(&full_address), mem::size_of::<sockaddr_rc>() as u32) } < 0 {
            Err(From::from(nix::Error::last()))
        } else {
            Ok(())
        }
    }
}

const AF_BLUETOOTH : i32 = 31;

const BTPROTO_L2CAP : isize = 0;
const BTPROTO_HCI : isize = 1;
const BTPROTO_SCO : isize = 2;
const BTPROTO_RFCOMM : isize = 3;
const BTPROTO_BNEP : isize = 4;
const BTPROTO_CMTP : isize = 5;
const BTPROTO_HIDP : isize = 6;
const BTPROTO_AVDTP : isize = 7;

#[allow(dead_code)]
enum BtProtocolBlueZ {
    L2CAP = BTPROTO_L2CAP,
    HCI = BTPROTO_HCI,
    SCO = BTPROTO_SCO,
    RFCOMM = BTPROTO_RFCOMM,
    BNEP = BTPROTO_BNEP,
    CMTP = BTPROTO_CMTP,
    HIDP = BTPROTO_HIDP,
    AVDTP = BTPROTO_AVDTP
}

#[repr(C)]
#[derive(Copy, Debug, Clone)]
struct sockaddr_rc {
    rc_family : libc::sa_family_t,
    rc_bdaddr : BtAddr,
    rc_channel : u8
}

impl From<nix::Error> for BtError {
    fn from(e: nix::Error) -> BtError {
        match e {
            nix::Error::Sys(errno) => BtError::Errno(errno as u32, e.description().to_string()),
            nix::Error::InvalidPath => BtError::Unknown,
        }
    }
}

impl From<Io> for BtSocket {
    fn from(io : Io) -> BtSocket { BtSocket { io : io } }
}

impl mio::Evented for BtSocket {
    fn register(&self, poll: &Poll, token: mio::Token, interest: Ready, opts: mio::PollOpt) -> std::io::Result<()> {
        self.io.register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &Poll, token: mio::Token, interest: Ready, opts: mio::PollOpt) -> std::io::Result<()> {
        self.io.reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> std::io::Result<()> {
        self.io.deregister(poll)
    }
}

impl Read for BtSocket {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.io.read(buf)
    }
}

impl Write for BtSocket {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.io.write(buf)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.io.flush()
    }
}
<commit_msg>Use UnixStream instead of (deprecated) Io<commit_after>extern crate libc;
extern crate nix;
extern crate mio;

use bluetooth::{BtError, BtAddr, BtProtocol};
use platform::get_rfcomm_channel;
use std;
use std::io::{Read, Write};
use std::mem;
use std::error::Error;
use std::os::unix::io::{RawFd, FromRawFd, AsRawFd};
use mio::{Poll, Ready};
use std::os::unix::net::UnixStream;
use mio::unix::EventedFd;

#[derive(Debug)]
pub struct BtSocket {
    stream: UnixStream,
}

impl BtSocket {
    pub fn new(proto: BtProtocol) -> Result<BtSocket, BtError> {
        match proto {
            BtProtocol::RFCOMM => {
                let fd = unsafe { libc::socket(AF_BLUETOOTH, libc::SOCK_STREAM, BtProtocolBlueZ::RFCOMM as i32) };
                if fd < 0 {
                    return Err(From::from(nix::Error::last()));
                } else {
                    Ok(BtSocket::from(fd))
                }
            }
        }
    }

    pub fn connect(&mut self, addr: BtAddr) -> Result<(), BtError> {
        let full_address : sockaddr_rc = sockaddr_rc {
            rc_family : AF_BLUETOOTH as u16,
            rc_bdaddr : addr,
            rc_channel : try!(get_rfcomm_channel(addr))
        };

        if unsafe { libc::connect(self.stream.as_raw_fd(), mem::transmute(&full_address), mem::size_of::<sockaddr_rc>() as u32) } < 0 {
            Err(From::from(nix::Error::last()))
        } else {
            Ok(())
        }
    }
}

const AF_BLUETOOTH : i32 = 31;

const BTPROTO_L2CAP : isize = 0;
const BTPROTO_HCI : isize = 1;
const BTPROTO_SCO : isize = 2;
const BTPROTO_RFCOMM : isize = 3;
const BTPROTO_BNEP : isize = 4;
const BTPROTO_CMTP : isize = 5;
const BTPROTO_HIDP : isize = 6;
const BTPROTO_AVDTP : isize = 7;

#[allow(dead_code)]
enum BtProtocolBlueZ {
    L2CAP = BTPROTO_L2CAP,
    HCI = BTPROTO_HCI,
    SCO = BTPROTO_SCO,
    RFCOMM = BTPROTO_RFCOMM,
    BNEP = BTPROTO_BNEP,
    CMTP = BTPROTO_CMTP,
    HIDP = BTPROTO_HIDP,
    AVDTP = BTPROTO_AVDTP
}

#[repr(C)]
#[derive(Copy, Debug, Clone)]
struct sockaddr_rc {
    rc_family : libc::sa_family_t,
    rc_bdaddr : BtAddr,
    rc_channel : u8
}

impl From<nix::Error> for BtError {
    fn from(e: nix::Error) -> BtError {
        match e {
            nix::Error::Sys(errno) => BtError::Errno(errno as u32, e.description().to_string()),
            nix::Error::InvalidPath => BtError::Unknown,
        }
    }
}

impl From<RawFd> for BtSocket {
    fn from(rawfd: RawFd) -> BtSocket {
        BtSocket { stream: unsafe { UnixStream::from_raw_fd(rawfd) }, }
    }
}

impl mio::Evented for BtSocket {
    fn register(&self, poll: &Poll, token: mio::Token, interest: Ready, opts: mio::PollOpt) -> std::io::Result<()> {
        EventedFd(&self.stream.as_raw_fd()).register(poll, token, interest, opts)
    }

    fn reregister(&self, poll: &Poll, token: mio::Token, interest: Ready, opts: mio::PollOpt) -> std::io::Result<()> {
        EventedFd(&self.stream.as_raw_fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> std::io::Result<()> {
        EventedFd(&self.stream.as_raw_fd()).deregister(poll)
    }
}

impl Read for BtSocket {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.stream.read(buf)
    }
}

impl Write for BtSocket {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.stream.write(buf)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.stream.flush()
    }
}
<|endoftext|>


<commit_before><commit_msg>progress<commit_after><|endoftext|>


<commit_before><commit_msg>Use ``` for escaping, and use details/summary.<commit_after><|endoftext|>


<commit_before><commit_msg>main: print panic messages<commit_after><|endoftext|>


<commit_before><commit_msg>Print error message when deps_for() fails<commit_after><|endoftext|>


<commit_before><commit_msg>Fix formatting of 'rsure list' command<commit_after><|endoftext|>


<commit_before>use futures::channel::oneshot;
use futures::future::{FutureExt, TryFutureExt};
use futures_test::future::FutureTestExt;
use std::sync::mpsc;
use std::thread;

#[test]
fn oneshot_send1() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    let t = thread::spawn(|| tx1.send(1).unwrap());
    rx1.map_ok(move |x| tx2.send(x)).run_in_background();
    assert_eq!(1, rx2.recv().unwrap());
    t.join().unwrap();
}

#[test]
fn oneshot_send2() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    thread::spawn(|| tx1.send(1).unwrap()).join().unwrap();
    rx1.map_ok(move |x| tx2.send(x).unwrap()).run_in_background();
    assert_eq!(1, rx2.recv().unwrap());
}

#[test]
fn oneshot_send3() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    rx1.map_ok(move |x| tx2.send(x).unwrap()).run_in_background();
    thread::spawn(|| tx1.send(1).unwrap()).join().unwrap();
    assert_eq!(1, rx2.recv().unwrap());
}

#[test]
fn oneshot_drop_tx1() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    drop(tx1);
    rx1.map(move |result| tx2.send(result).unwrap()).run_in_background();

    assert_eq!(Err(oneshot::Canceled), rx2.recv().unwrap());
}

#[test]
fn oneshot_drop_tx2() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    let t = thread::spawn(|| drop(tx1));
    rx1.map(move |result| tx2.send(result).unwrap()).run_in_background();
    t.join().unwrap();

    assert_eq!(Err(oneshot::Canceled), rx2.recv().unwrap());
}

#[test]
fn oneshot_drop_rx() {
    let (tx, rx) = oneshot::channel::<i32>();
    drop(rx);
    assert_eq!(Err(2), tx.send(2));
}
<commit_msg>futures: tests/oneshot.rs: Don't break w/o "alloc"<commit_after>#[cfg(feature = "alloc")] // channel
#[test]
fn oneshot_send1() {
    use futures::channel::oneshot;
    use futures::future::TryFutureExt;
    use futures_test::future::FutureTestExt;
    use std::sync::mpsc;
    use std::thread;

    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    let t = thread::spawn(|| tx1.send(1).unwrap());
    rx1.map_ok(move |x| tx2.send(x)).run_in_background();
    assert_eq!(1, rx2.recv().unwrap());
    t.join().unwrap();
}

#[cfg(feature = "alloc")] // channel
#[test]
fn oneshot_send2() {
    use futures::channel::oneshot;
    use futures::future::TryFutureExt;
    use futures_test::future::FutureTestExt;
    use std::sync::mpsc;
    use std::thread;

    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    thread::spawn(|| tx1.send(1).unwrap()).join().unwrap();
    rx1.map_ok(move |x| tx2.send(x).unwrap()).run_in_background();
    assert_eq!(1, rx2.recv().unwrap());
}

#[cfg(feature = "alloc")] // channel
#[test]
fn oneshot_send3() {
    use futures::channel::oneshot;
    use futures::future::TryFutureExt;
    use futures_test::future::FutureTestExt;
    use std::sync::mpsc;
    use std::thread;

    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    rx1.map_ok(move |x| tx2.send(x).unwrap()).run_in_background();
    thread::spawn(|| tx1.send(1).unwrap()).join().unwrap();
    assert_eq!(1, rx2.recv().unwrap());
}

#[cfg(feature = "alloc")] // channel
#[test]
fn oneshot_drop_tx1() {
    use futures::channel::oneshot;
    use futures::future::FutureExt;
    use futures_test::future::FutureTestExt;
    use std::sync::mpsc;

    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    drop(tx1);
    rx1.map(move |result| tx2.send(result).unwrap()).run_in_background();

    assert_eq!(Err(oneshot::Canceled), rx2.recv().unwrap());
}

#[cfg(feature = "alloc")] // channel
#[test]
fn oneshot_drop_tx2() {
    use futures::channel::oneshot;
    use futures::future::FutureExt;
    use futures_test::future::FutureTestExt;
    use std::sync::mpsc;
    use std::thread;

    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = mpsc::channel();

    let t = thread::spawn(|| drop(tx1));
    rx1.map(move |result| tx2.send(result).unwrap()).run_in_background();
    t.join().unwrap();

    assert_eq!(Err(oneshot::Canceled), rx2.recv().unwrap());
}

#[cfg(feature = "alloc")] // channel
#[test]
fn oneshot_drop_rx() {
    use futures::channel::oneshot;

    let (tx, rx) = oneshot::channel::<i32>();
    drop(rx);
    assert_eq!(Err(2), tx.send(2));
}
<|endoftext|>


<commit_before>pub mod control_block;
pub mod log_var;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry::*;
use std::mem;
use std::sync::{Arc};
use std::any::Any;
use std::cell::Cell;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use self::log_var::LogVar;
use self::log_var::LogVar::*;
use self::control_block::ControlBlock;
use super::var::{TVar, VarControlBlock};
use super::result::*;
use super::result::StmError::*;

static GLOBAL_SEQ_LOCK: AtomicUsize = ATOMIC_USIZE_INIT;

pub struct Transaction {
    snapshot: usize,
    writevars: BTreeMap<Arc<VarControlBlock>, LogVar>,
    readvars: BTreeMap<Arc<VarControlBlock>, LogVar>,
}

impl Transaction {
    fn new(ss: usize) -> Transaction {
        Transaction {
            snapshot: ss,
            writevars: BTreeMap::new(),
            readvars: BTreeMap::new()
        }
    }

    pub fn with<T, F>(f: F) -> T
    where F: Fn(&mut Transaction) -> StmResult<T>,
    {
        let mut ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        while (ss & 1) != 0 {
            ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        }
        let mut transaction = Transaction::new(ss);

        loop {
            match f(&mut transaction) {
                Ok(t) => {
                    if transaction.commit() {
                        return t;
                    }
                }
                Err(_) => { }
                // Err(Retry) => {
                //     transaction.wait_for_change();
                // }
            }
            transaction.clear();
        }
    }

    /// Perform a downcast on a var.
    fn downcast<T: Any + Clone>(var: Arc<Any>) -> T {
        var.downcast_ref::<T>()
           .expect("Vars with different types and same address")
           .clone()
    }

    pub fn read<T: Send + Sync + Any + Clone>(&mut self, var: &TVar<T>) -> StmResult<T> {
        let ctrl = var.control_block().clone();
        // Check if the same var was written before.
        match self.writevars.entry(ctrl) {

            Occupied(mut entry) => {let value = entry.get_mut().read();
                                    return Ok(Transaction::downcast(value));}

            Vacant(entry) => { }
        }
        while self.snapshot != GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
            match self.validate() {
                None => { return Err(Retry); }
                Some(ss) => {
                    self.snapshot = ss;
                }
            }
        }
        let value = var.read_ref_atomic();
        let ctrl = var.control_block().clone();
        self.readvars.insert(ctrl, LogVar::Read(value.clone()));
        Ok(Transaction::downcast(value))
    }

    /// Write a variable.
    ///
    /// `write` does not immediately change the value, but atomically
    /// commits all writes at the end of the computation.
    pub fn write<T: Any + Send + Sync + Clone>(&mut self, var: &TVar<T>, value: T) -> StmResult<()> {
        let boxed = Arc::new(value);
        let ctrl = var.control_block().clone();
        match self.writevars.entry(ctrl) {
            Occupied(mut entry)     => entry.get_mut().write(boxed),
            Vacant(entry)       => { entry.insert(LogVar::Write(boxed)); }
        }
        Ok(())
    }

    fn clear(&mut self) {
        self.writevars.clear();
        self.readvars.clear();
        let mut ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        while (ss & 1) != 0 {
            ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        }
        self.snapshot = ss;
    }

    fn validate(&mut self) -> Option<usize> {
        loop {
            let time = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
            if time & 1 != 0 {
                continue;
            }
            let vars = mem::replace(&mut self.readvars, BTreeMap::new());
            let mut read_vec = Vec::new();
            for (var, value) in &vars {
                match value {
                    &Write(ref w) | &ReadObsoleteWrite(_,ref w) => { }
                    &ReadWrite(ref original,ref w) => { }
                    &ReadObsolete(_) => { }
                    &Read(ref original) => {
                        let lock = var.value.read().unwrap();
                        if !same_address(&lock, original) {
                            mem::drop(read_vec);
                            return None;
                        }
                        read_vec.push(lock);
                    }
                }
            }
            mem::drop(read_vec);
            if time == GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
                return Some(time);
            }
        }
    }

    fn commit(&mut self) -> bool {
        if self.writevars.is_empty() {
            return true;
        }
        while GLOBAL_SEQ_LOCK.compare_and_swap(self.snapshot, self.snapshot+1, Ordering::SeqCst) != self.snapshot {
            match self.validate() {
                None => { return false; }
                Some(ss) => { self.snapshot = ss; }
            }
        }
        let vars = mem::replace(&mut self.writevars, BTreeMap::new());
        let mut read_vec = Vec::new();
        let mut write_vec = Vec::new();

        for (var, value) in &vars {
            // lock the variable and read the value

            match value {
                // We need to take a write lock.
                &Write(ref w) | &ReadObsoleteWrite(_,ref w)=> {
                    // take write lock
                    let lock = var.value.write().unwrap();
                    // add all data to the vector
                    write_vec.push((var, w, lock));
                }

                // We need to check for consistency and
                // take a write lock.
                &ReadWrite(ref original,ref w) => {
                    // take write lock
                    let lock = var.value.write().unwrap();

                    if !same_address(&lock, original) {
                        return false;
                    }
                    // add all data to the vector
                    write_vec.push((var, w, lock));
                }
                // Nothing to do. ReadObsolete is only needed for blocking, not
                // for consistency checks.
                &ReadObsolete(_) => { }
                // Take read lock and check for consistency.
                &Read(ref original) => {
                    // take a read lock
                    let lock = var.value.read().unwrap();

                    if !same_address(&lock, original) {
                        return false;
                    }

                    read_vec.push(lock);
                }
            }
        }

        // Second phase: write back and release

        // Release the reads first.
        mem::drop(read_vec);

        for (var, value, mut lock) in write_vec {
            // commit value
            *lock = value.clone();
        }
        GLOBAL_SEQ_LOCK.store(self.snapshot + 2, Ordering::SeqCst);
        // commit succeded
        true
    }
}

fn arc_to_address<T: ?Sized>(arc: &Arc<T>) -> usize {
    &**arc as *const T as *const u32 as usize
}

fn same_address<T: ?Sized>(a: &Arc<T>, b: &Arc<T>) -> bool {
    arc_to_address(a) == arc_to_address(b)
}

/// Test same_address on a cloned Arc
#[test]
fn test_same_address_equal() {
    let t1 = Arc::new(42);
    let t2 = t1.clone();

    assert!(same_address(&t1, &t2));
}

/// Test same_address on differenc Arcs with same value
#[test]
fn test_same_address_different() {
    let t1 = Arc::new(42);
    let t2 = Arc::new(42);

    assert!(!same_address(&t1, &t2));
}

// #[test]
// fn test_read() {
//     let mut log = Transaction::new();
//     let var = TVar::new(vec![1, 2, 3, 4]);

//     // the variable can be read
//     assert_eq!(&*log.read(&var).unwrap(), &[1, 2, 3, 4]);
// }

// #[test]
// fn test_write_read() {
//     let mut log = Transaction::new();
//     let var = TVar::new(vec![1, 2]);

//     log.write(&var, vec![1, 2, 3, 4]).unwrap();

//     // consecutive reads get the updated version
//     assert_eq!(log.read(&var).unwrap(), [1, 2, 3, 4]);

//     // the original value is still preserved
//     assert_eq!(var.read_atomic(), [1, 2]);
// }

#[test]
fn test_transaction_simple() {
    let x = Transaction::with(|_| Ok(42));
    assert_eq!(x, 42);
}

#[test]
fn test_transaction_read() {
    let read = TVar::new(42);

    let x = Transaction::with(|trans| {
        read.read(trans)
    });

    assert_eq!(x, 42);
}

#[test]
fn test_transaction_write() {
    let write = TVar::new(42);

    Transaction::with(|trans| {
        write.write(trans, 0)
    });

    assert_eq!(write.read_atomic(), 0);
}

#[test]
fn test_transaction_copy() {
    let read = TVar::new(42);
    let write = TVar::new(0);

    Transaction::with(|trans| {
        let r = try!(read.read(trans));
        write.write(trans, r)
    });

    assert_eq!(write.read_atomic(), 42);
}

<commit_msg>without logs<commit_after>pub mod log_var;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry::*;
use std::mem;
use std::sync::{Arc};
use std::any::Any;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};

use self::log_var::LogVar;
use self::log_var::LogVar::*;
use super::var::{TVar, VarControlBlock};
use super::result::*;
use super::result::StmError::*;

type ArcAny = Arc<Any + Send + Sync>;

static GLOBAL_SEQ_LOCK: AtomicUsize = ATOMIC_USIZE_INIT;
pub struct Transaction {
    snapshot: usize,
    writevars: BTreeMap<Arc<VarControlBlock>, ArcAny>,
    readvars: BTreeMap<Arc<VarControlBlock>, ArcAny>,
}

impl Transaction {
    fn new(ss: usize) -> Transaction {
        Transaction {
            snapshot: ss,
            writevars: BTreeMap::new(),
            readvars: BTreeMap::new()
        }
    }

    pub fn with<T, F>(f: F) -> T
    where F: Fn(&mut Transaction) -> StmResult<T>,
    {
        let mut ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        while (ss & 1) != 0 {
            ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        }
        let mut transaction = Transaction::new(ss);

        loop {
            match f(&mut transaction) {
                Ok(t) => {
                    if transaction.commit() {
                        return t;
                    }
                }
                Err(_) => { }
            }
            transaction.clear();
        }
    }

    fn downcast<T: Any + Clone>(var: Arc<Any>) -> T {
        var.downcast_ref::<T>()
           .expect("Vars with different types and same address")
           .clone()
    }

    pub fn read<T: Send + Sync + Any + Clone>(&mut self, var: &TVar<T>) -> StmResult<T> {
        let ctrl = var.control_block().clone();
        match self.writevars.get(&ctrl) {

            Some(mut entry) => {let value = entry.clone();
                                    return Ok(Transaction::downcast(value));}
            None => { }
        }
        while self.snapshot != GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
            match self.validate() {
                None => { return Err(Retry); }
                Some(ss) => {
                    self.snapshot = ss;
                }
            }
        }
        let value = var.read_ref_atomic();
        let ctrl = var.control_block().clone();
        self.readvars.insert(ctrl, value.clone());
        //self.readvars.insert(ctrl, LogVar::Read(value.clone()));
        Ok(Transaction::downcast(value))
    }

    pub fn write<T: Any + Send + Sync + Clone>(&mut self, var: &TVar<T>, value: T) -> StmResult<()> {
        let boxed = Arc::new(value);
        let ctrl = var.control_block().clone();
        self.writevars.insert(ctrl, boxed);
        Ok(())
    }

    fn clear(&mut self) {
        self.writevars.clear();
        self.readvars.clear();
        let mut ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        while (ss & 1) != 0 {
            ss = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
        }
        self.snapshot = ss;
    }

    fn validate(&mut self) -> Option<usize> {
        loop {
            let time = GLOBAL_SEQ_LOCK.load(Ordering::SeqCst);
            if time & 1 != 0 {
                continue;
            }
            let vars = mem::replace(&mut self.readvars, BTreeMap::new());
            let mut read_vec = Vec::new();
            for (var, value) in &vars {
                match value {
                    // &Write(ref w) | &ReadObsoleteWrite(_,ref w) => { }
                    // &ReadWrite(ref original,ref w) => { }
                    // &ReadObsolete(_) => { }
                    //&Read(ref original)
                        ref original => {
                        let lock = var.value.read().unwrap();
                        if !same_address(&lock, original) {
                            mem::drop(read_vec);
                            return None;
                        }
                        read_vec.push(lock);
                    }
                }
            }
            mem::drop(read_vec);
            if time == GLOBAL_SEQ_LOCK.load(Ordering::SeqCst) {
                return Some(time);
            }
        }
    }

    fn commit(&mut self) -> bool {
        if self.writevars.is_empty() {
            return true;
        }
        while GLOBAL_SEQ_LOCK.compare_and_swap(self.snapshot, self.snapshot+1, Ordering::SeqCst) != self.snapshot {
            match self.validate() {
                None => { return false; }
                Some(ss) => { self.snapshot = ss; }
            }
        }
        let vars = mem::replace(&mut self.writevars, BTreeMap::new());
        //let mut read_vec = Vec::new();
        let mut write_vec = Vec::new();

        for (var, value) in &vars {
            match value {
                ref val => {
                    let lock = var.value.write().unwrap();
                    write_vec.push((var, val.clone(), lock));
                }
                // // We need to take a write lock.
                // &Write(ref w) | &ReadObsoleteWrite(_,ref w)=> {
                //     // take write lock
                //     let lock = var.value.write().unwrap();
                //     // add all data to the vector
                //     write_vec.push((var, w, lock));
                // }

                // // We need to check for consistency and
                // // take a write lock.
                // &ReadWrite(ref original,ref w) => {
                //     // take write lock
                //     let lock = var.value.write().unwrap();

                //     if !same_address(&lock, original) {
                //         return false;
                //     }
                //     // add all data to the vector
                //     write_vec.push((var, w, lock));
                // }
                // // Nothing to do. ReadObsolete is only needed for blocking, not
                // // for consistency checks.
                // &ReadObsolete(_) => { }
                // // Take read lock and check for consistency.
                // &Read(ref original) => {
                //     // take a read lock
                //     let lock = var.value.read().unwrap();

                //     if !same_address(&lock, original) {
                //         return false;
                //     }

                //     read_vec.push(lock);
                // }
            }
        }

        // Second phase: write back and release

        // Release the reads first.
        //mem::drop(read_vec);

        for (var, value, mut lock) in write_vec {
            // commit value
            *lock = value.clone();
        }
        GLOBAL_SEQ_LOCK.store(self.snapshot + 2, Ordering::SeqCst);
        // commit succeded
        true
    }
}

fn arc_to_address<T: ?Sized>(arc: &Arc<T>) -> usize {
    &**arc as *const T as *const u32 as usize
}

fn same_address<T: ?Sized>(a: &Arc<T>, b: &Arc<T>) -> bool {
    arc_to_address(a) == arc_to_address(b)
}

/// Test same_address on a cloned Arc
#[test]
fn test_same_address_equal() {
    let t1 = Arc::new(42);
    let t2 = t1.clone();

    assert!(same_address(&t1, &t2));
}

/// Test same_address on differenc Arcs with same value
#[test]
fn test_same_address_different() {
    let t1 = Arc::new(42);
    let t2 = Arc::new(42);

    assert!(!same_address(&t1, &t2));
}

// #[test]
// fn test_read() {
//     let mut log = Transaction::new();
//     let var = TVar::new(vec![1, 2, 3, 4]);

//     // the variable can be read
//     assert_eq!(&*log.read(&var).unwrap(), &[1, 2, 3, 4]);
// }

// #[test]
// fn test_write_read() {
//     let mut log = Transaction::new();
//     let var = TVar::new(vec![1, 2]);

//     log.write(&var, vec![1, 2, 3, 4]).unwrap();

//     // consecutive reads get the updated version
//     assert_eq!(log.read(&var).unwrap(), [1, 2, 3, 4]);

//     // the original value is still preserved
//     assert_eq!(var.read_atomic(), [1, 2]);
// }

#[test]
fn test_transaction_simple() {
    let x = Transaction::with(|_| Ok(42));
    assert_eq!(x, 42);
}

#[test]
fn test_transaction_read() {
    let read = TVar::new(42);

    let x = Transaction::with(|trans| {
        read.read(trans)
    });

    assert_eq!(x, 42);
}

#[test]
fn test_transaction_write() {
    let write = TVar::new(42);

    Transaction::with(|trans| {
        write.write(trans, 0)
    });

    assert_eq!(write.read_atomic(), 0);
}

#[test]
fn test_transaction_copy() {
    let read = TVar::new(42);
    let write = TVar::new(0);

    Transaction::with(|trans| {
        let r = try!(read.read(trans));
        write.write(trans, r)
    });

    assert_eq!(write.read_atomic(), 42);
}

<|endoftext|>


<commit_before>/* CONFIGURATION */

// add other android system headers to this list as necessary
static INCLUDE_SYS_H: [&str; 1] = ["jni.h"];

static RUST_SRC_DIR: &str = "src";
static ANDROID_BASE_DIR: &str = "app";
static ANDROID_PACKAGE_ID: &str = "net.akaame.myapplication";

// =========================================================
// This script is portable; copy and paste it into your own
// build files at will.

extern crate bindgen;
extern crate rust_swig;
extern crate syntex;
extern crate walkdir;

use std::process::{Command, Stdio};
use std::{env, fmt};
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

use bindgen::RustTarget;
use rust_swig::{JavaConfig, LanguageConfig};
use walkdir::WalkDir;

fn main() {
    // don't simplify this to if the target contains the substring "android" --
    // these lines also serve as a guard so only true android triples receive
    // JNI generation.
    let target = env::var("TARGET").unwrap();
    if ["aarch64-linux-android",
        "arm-linux-androideabi",
        "i686-linux-android",
        "x86_64-linux-android"]
        .contains(&target.as_str()) {
            gen_for_android();
        }
}

fn gen_for_android() {
    let target = env::var("TARGET").unwrap();

    let include_dirs =
        get_gcc_system_include_dirs(&target).expect("Can't get NDK's system include dirs");

    let include_headers: Vec<_> = INCLUDE_SYS_H.into_iter()
        .map(|h| search_file_in_directory(&include_dirs, h)
             .expect(format!("Could not find header {}", h).as_ref()))
        .collect();

    let src_dir = Path::new(RUST_SRC_DIR);
    let out_dir = env::var("OUT_DIR").unwrap();

    gen_binding(
        &target,
        &include_dirs,
        &include_headers,
        &Path::new(&out_dir).join("android_c_headers.rs"),
    ).unwrap();

    // Find files ending in .rs.in and expand them with SWIG
    for _entry in WalkDir::new(RUST_SRC_DIR) {
        let entry = _entry.expect("Error walking sources.");
        if entry.path().is_dir() || !entry.path().to_string_lossy().ends_with(".rs.in") {
            continue;
        }

        println!("Found SWIG specification: {}", entry.path().display());
        let swigf = entry.path().strip_prefix("src").unwrap();

        rust_swig_expand(
            &src_dir,
            &swigf,
            Path::new(&out_dir),
        ).unwrap();

        write_include_file(&src_dir, swigf).expect("Failed to write include file.");
    }

    // Hook up cargo reruns
    println!("cargo:rerun-if-changed={}", RUST_SRC_DIR);
    for dir in &include_dirs {println!("cargo:rerun-if-changed={}", dir.display());}
    //if the generated files were deleted (e.g by gradle -q clean), regenerate them
    println!("cargo:rerun-if-changed={}", out_dir);
}

fn get_gcc_system_include_dirs(target: &str) -> Result<Vec<PathBuf>, String> {
    let gcc_cmd = match env::var("RUSTC_LINKER") {
        Ok(path) => path,
        Err(_) => target.to_owned() + "-gcc"
    };

    println!("Trying Android gcc from '{}'", gcc_cmd);

    let gcc_process = match Command::new(&gcc_cmd)
        .args(&["-v", "-x", "c", "-E", "-"])
        .stderr(Stdio::piped())
        .stdin(Stdio::piped())
        .stdout(Stdio::inherit())
        .spawn() { // there are more elegant ways to write this, but this works
            Err(e) => if std::io::ErrorKind::NotFound == e.kind() {
                panic!("Could not find a suitable NDK gcc (tried {})
    You can fix this either by adding the toolchain's bin/ to your $PATH, or by
    merging PR#5394 form github.com/rust-lang/cargo into your version of Cargo.", &gcc_cmd);
            } else {
                panic!("Failed to spawn NDK gcc: {}", e);
            },
            Ok(p) => p,
        };

    gcc_process
        .stdin
        .ok_or(format!("Cannot get stdin of {}", gcc_cmd).as_str())?
        .write_all("\n".as_bytes())
        .map_err(|err| err.to_string())?;

    let mut gcc_output = String::new();
    gcc_process
        .stderr
        .ok_or(format!("Cannot get stderr of {}", gcc_cmd).as_str())?
        .read_to_string(&mut gcc_output)
        .map_err(|err| err.to_string())?;

    const BEGIN_PAT: &'static str = "\n#include <...> search starts here:\n";
    const END_PAT: &'static str = "\nEnd of search list.\n";
    let start_includes = gcc_output
        .find(BEGIN_PAT)
        .ok_or(format!("No '{}' in output from {}", BEGIN_PAT, gcc_cmd).as_str())?
        + BEGIN_PAT.len();
    let end_includes = (&gcc_output[start_includes..])
        .find(END_PAT)
        .ok_or(format!("No '{}' in output from {}", END_PAT, gcc_cmd).as_str())?
        + start_includes;

    Ok((&gcc_output[start_includes..end_includes])
       .split('\n')
       .map(|s| PathBuf::from(s.trim().to_string()))
       .collect())
}

fn search_file_in_directory<P>(dirs: &[P], file: &str) -> Result<PathBuf, ()>
where
    P: AsRef<Path>,
{
    for dir in dirs {
        let file_path = dir.as_ref().join(file);
        if file_path.exists() && file_path.is_file() {
            return Ok(file_path);
        }
    }
    Err(())
}

fn gen_binding<P1, P2>(
    target: &str,
    include_dirs: &[P1],
    c_headers: &[P2],
    output_rust: &Path,
) -> Result<(), String>
where
    P1: AsRef<Path> + fmt::Debug,
    P2: AsRef<Path> + fmt::Debug,
{
    assert!(!c_headers.is_empty());
    let c_file_path = &c_headers[0];

    let mut bindings: bindgen::Builder =
        bindgen::builder().header(c_file_path.as_ref().to_str().unwrap());
    bindings = include_dirs.iter().fold(bindings, |acc, x| {
        acc.clang_arg("-I".to_string() + x.as_ref().to_str().unwrap())
    });
    println!("Generate binding for {:?}", c_headers);
    bindings = bindings
        .rust_target(RustTarget::Stable_1_19)
    //long double not supported yet, see https://github.com/servo/rust-bindgen/issues/550
        .blacklist_type("max_align_t");
    bindings = if target.contains("windows") {
        //see https://github.com/servo/rust-bindgen/issues/578
        bindings.trust_clang_mangling(false)
    } else {
        bindings
    };
    bindings = c_headers[1..].iter().fold(
        Ok(bindings),
        |acc: Result<bindgen::Builder, String>, header| {
            let c_file_path = header;
            let c_file_str = c_file_path
                .as_ref()
                .to_str()
                .ok_or_else(|| format!("Invalid unicode in path to {:?}", c_file_path.as_ref()))?;
            Ok(acc.unwrap().clang_arg("-include").clang_arg(c_file_str))
        },
    )?;

    let generated_bindings = bindings
    //        .clang_arg(format!("-target {}", target))
        .generate()
        .map_err(|_| "Failed to generate bindings".to_string())?;
    generated_bindings
        .write_to_file(output_rust)
        .map_err(|err| err.to_string())?;

    Ok(())
}

fn rust_swig_expand(source_dir: &Path, file: &Path, out_dir: &Path) -> Result<(), String> {
    let mut registry = syntex::Registry::new();
    let swig_gen = rust_swig::Generator::new(LanguageConfig::JavaConfig(
        JavaConfig::new(
            Path::new(ANDROID_BASE_DIR)
                .join("src")
                .join("main")
                .join("java")
                .join(ANDROID_PACKAGE_ID.replace(".", "/")),
            ANDROID_PACKAGE_ID.to_string()
        ).use_null_annotation("android.support.annotation.NonNull".into()),
    ));
    swig_gen.register(&mut registry);

    let out_file = out_dir.join(Path::new(file.parent().unwrap_or(Path::new(".")))
                                .join(file.file_stem().expect("Got invalid file (no filename)")));

    registry
        .expand(ANDROID_PACKAGE_ID.as_ref(), source_dir.join(file), out_file)
        .map_err(|err| format!("Rust-SWIG expansion failed: {}", err))
}

fn write_include_file(source_dir: &Path, swig_file: &Path) -> std::io::Result<()> {
    let rs_rel_file = Path::new(swig_file.parent().unwrap_or(Path::new(".")))
        .join(swig_file.file_stem().expect("Got invalid file (no filename)"));
    let rs_path = source_dir.join(&rs_rel_file);

    if rs_path.exists() {
        println!("Not writing {} because it exists", rs_path.display());
        return Ok(());
    }

    let mut rs_file = File::create(rs_path)?;
    rs_file.write_all(format!("include!(concat!(env!(\"OUT_DIR\"), \"/{}\"));",
                              rs_rel_file.to_string_lossy()).as_bytes())?;

    return Ok(());
}
<commit_msg>Added auto-gen notice<commit_after>/* CONFIGURATION */

// add other android system headers to this list as necessary
static INCLUDE_SYS_H: [&str; 1] = ["jni.h"];

static RUST_SRC_DIR: &str = "src";
static ANDROID_BASE_DIR: &str = "app";
static ANDROID_PACKAGE_ID: &str = "net.akaame.myapplication";

// =========================================================
// This script is portable; copy and paste it into your own
// build files at will.

extern crate bindgen;
extern crate rust_swig;
extern crate syntex;
extern crate walkdir;

use std::process::{Command, Stdio};
use std::{env, fmt};
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

use bindgen::RustTarget;
use rust_swig::{JavaConfig, LanguageConfig};
use walkdir::WalkDir;

fn main() {
    // don't simplify this to if the target contains the substring "android" --
    // these lines also serve as a guard so only true android triples receive
    // JNI generation.
    let target = env::var("TARGET").unwrap();
    if ["aarch64-linux-android",
        "arm-linux-androideabi",
        "i686-linux-android",
        "x86_64-linux-android"]
        .contains(&target.as_str()) {
            gen_for_android();
        }
}

fn gen_for_android() {
    let target = env::var("TARGET").unwrap();

    let include_dirs =
        get_gcc_system_include_dirs(&target).expect("Can't get NDK's system include dirs");

    let include_headers: Vec<_> = INCLUDE_SYS_H.into_iter()
        .map(|h| search_file_in_directory(&include_dirs, h)
             .expect(format!("Could not find header {}", h).as_ref()))
        .collect();

    let src_dir = Path::new(RUST_SRC_DIR);
    let out_dir = env::var("OUT_DIR").unwrap();

    gen_binding(
        &target,
        &include_dirs,
        &include_headers,
        &Path::new(&out_dir).join("android_c_headers.rs"),
    ).unwrap();

    // Find files ending in .rs.in and expand them with SWIG
    for _entry in WalkDir::new(RUST_SRC_DIR) {
        let entry = _entry.expect("Error walking sources.");
        if entry.path().is_dir() || !entry.path().to_string_lossy().ends_with(".rs.in") {
            continue;
        }

        println!("Found SWIG specification: {}", entry.path().display());
        let swigf = entry.path().strip_prefix("src").unwrap();

        rust_swig_expand(
            &src_dir,
            &swigf,
            Path::new(&out_dir),
        ).unwrap();

        write_include_file(&src_dir, swigf).expect("Failed to write include file.");
    }

    // Hook up cargo reruns
    println!("cargo:rerun-if-changed={}", RUST_SRC_DIR);
    for dir in &include_dirs {println!("cargo:rerun-if-changed={}", dir.display());}
    //if the generated files were deleted (e.g by gradle -q clean), regenerate them
    println!("cargo:rerun-if-changed={}", out_dir);
}

fn get_gcc_system_include_dirs(target: &str) -> Result<Vec<PathBuf>, String> {
    let gcc_cmd = match env::var("RUSTC_LINKER") {
        Ok(path) => path,
        Err(_) => target.to_owned() + "-gcc"
    };

    println!("Trying Android gcc from '{}'", gcc_cmd);

    let gcc_process = match Command::new(&gcc_cmd)
        .args(&["-v", "-x", "c", "-E", "-"])
        .stderr(Stdio::piped())
        .stdin(Stdio::piped())
        .stdout(Stdio::inherit())
        .spawn() { // there are more elegant ways to write this, but this works
            Err(e) => if std::io::ErrorKind::NotFound == e.kind() {
                panic!("Could not find a suitable NDK gcc (tried {})
    You can fix this either by adding the toolchain's bin/ to your $PATH, or by
    merging PR#5394 form github.com/rust-lang/cargo into your version of Cargo.", &gcc_cmd);
            } else {
                panic!("Failed to spawn NDK gcc: {}", e);
            },
            Ok(p) => p,
        };

    gcc_process
        .stdin
        .ok_or(format!("Cannot get stdin of {}", gcc_cmd).as_str())?
        .write_all("\n".as_bytes())
        .map_err(|err| err.to_string())?;

    let mut gcc_output = String::new();
    gcc_process
        .stderr
        .ok_or(format!("Cannot get stderr of {}", gcc_cmd).as_str())?
        .read_to_string(&mut gcc_output)
        .map_err(|err| err.to_string())?;

    const BEGIN_PAT: &'static str = "\n#include <...> search starts here:\n";
    const END_PAT: &'static str = "\nEnd of search list.\n";
    let start_includes = gcc_output
        .find(BEGIN_PAT)
        .ok_or(format!("No '{}' in output from {}", BEGIN_PAT, gcc_cmd).as_str())?
        + BEGIN_PAT.len();
    let end_includes = (&gcc_output[start_includes..])
        .find(END_PAT)
        .ok_or(format!("No '{}' in output from {}", END_PAT, gcc_cmd).as_str())?
        + start_includes;

    Ok((&gcc_output[start_includes..end_includes])
       .split('\n')
       .map(|s| PathBuf::from(s.trim().to_string()))
       .collect())
}

fn search_file_in_directory<P>(dirs: &[P], file: &str) -> Result<PathBuf, ()>
where
    P: AsRef<Path>,
{
    for dir in dirs {
        let file_path = dir.as_ref().join(file);
        if file_path.exists() && file_path.is_file() {
            return Ok(file_path);
        }
    }
    Err(())
}

fn gen_binding<P1, P2>(
    target: &str,
    include_dirs: &[P1],
    c_headers: &[P2],
    output_rust: &Path,
) -> Result<(), String>
where
    P1: AsRef<Path> + fmt::Debug,
    P2: AsRef<Path> + fmt::Debug,
{
    assert!(!c_headers.is_empty());
    let c_file_path = &c_headers[0];

    let mut bindings: bindgen::Builder =
        bindgen::builder().header(c_file_path.as_ref().to_str().unwrap());
    bindings = include_dirs.iter().fold(bindings, |acc, x| {
        acc.clang_arg("-I".to_string() + x.as_ref().to_str().unwrap())
    });
    println!("Generate binding for {:?}", c_headers);
    bindings = bindings
        .rust_target(RustTarget::Stable_1_19)
    //long double not supported yet, see https://github.com/servo/rust-bindgen/issues/550
        .blacklist_type("max_align_t");
    bindings = if target.contains("windows") {
        //see https://github.com/servo/rust-bindgen/issues/578
        bindings.trust_clang_mangling(false)
    } else {
        bindings
    };
    bindings = c_headers[1..].iter().fold(
        Ok(bindings),
        |acc: Result<bindgen::Builder, String>, header| {
            let c_file_path = header;
            let c_file_str = c_file_path
                .as_ref()
                .to_str()
                .ok_or_else(|| format!("Invalid unicode in path to {:?}", c_file_path.as_ref()))?;
            Ok(acc.unwrap().clang_arg("-include").clang_arg(c_file_str))
        },
    )?;

    let generated_bindings = bindings
    //        .clang_arg(format!("-target {}", target))
        .generate()
        .map_err(|_| "Failed to generate bindings".to_string())?;
    generated_bindings
        .write_to_file(output_rust)
        .map_err(|err| err.to_string())?;

    Ok(())
}

fn rust_swig_expand(source_dir: &Path, file: &Path, out_dir: &Path) -> Result<(), String> {
    let mut registry = syntex::Registry::new();
    let swig_gen = rust_swig::Generator::new(LanguageConfig::JavaConfig(
        JavaConfig::new(
            Path::new(ANDROID_BASE_DIR)
                .join("src")
                .join("main")
                .join("java")
                .join(ANDROID_PACKAGE_ID.replace(".", "/")),
            ANDROID_PACKAGE_ID.to_string()
        ).use_null_annotation("android.support.annotation.NonNull".into()),
    ));
    swig_gen.register(&mut registry);

    let out_file = out_dir.join(Path::new(file.parent().unwrap_or(Path::new(".")))
                                .join(file.file_stem().expect("Got invalid file (no filename)")));

    registry
        .expand(ANDROID_PACKAGE_ID.as_ref(), source_dir.join(file), out_file)
        .map_err(|err| format!("Rust-SWIG expansion failed: {}", err))
}

fn write_include_file(source_dir: &Path, swig_file: &Path) -> std::io::Result<()> {
    let rs_rel_file = Path::new(swig_file.parent().unwrap_or(Path::new(".")))
        .join(swig_file.file_stem().expect("Got invalid file (no filename)"));
    let rs_path = source_dir.join(&rs_rel_file);

    if rs_path.exists() {
        println!("Not writing {} because it exists", rs_path.display());
        return Ok(());
    }

    let mut rs_file = File::create(rs_path)?;
    rs_file.write_all(format!(
        r#"// Automatically generated by Rust-SWIG

include!(concat!(env!("OUT_DIR"), "/{}"));"#,
        rs_rel_file.to_string_lossy()).as_bytes())?;

    return Ok(());
}
<|endoftext|>