From 228e83888bf3d0e14d0bc00ddd0040bb71e24a87 Mon Sep 17 00:00:00 2001 From: Benjamin Herr Date: Fri, 1 Mar 2013 21:27:08 +0100 Subject: `std::net::tcp` docs: Use current syntax and types Doesn't touch non-comment lines. This changes various type_names to TypeNames and fixes the example for `tcp::accept` that was still using the old `match` syntax and `{|args| ...}` closures. --- src/libstd/net_tcp.rs | 152 +++++++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 76 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index dcbf7e60d89..4266cab0a05 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -43,7 +43,7 @@ extern mod rustrt { /** * Encapsulates an open TCP/IP connection through libuv * - * `tcp_socket` is non-copyable/sendable and automagically handles closing the + * `TcpSocket` is non-copyable/sendable and automagically handles closing the * underlying libuv data structures when it goes out of scope. This is the * data structure that is used for read/write operations over a TCP stream. */ @@ -66,10 +66,10 @@ pub fn TcpSocket(socket_data: @TcpSocketData) -> TcpSocket { } /** - * A buffered wrapper for `net::tcp::tcp_socket` + * A buffered wrapper for `net::tcp::TcpSocket` * * It is created with a call to `net::tcp::socket_buf()` and has impls that - * satisfy both the `io::reader` and `io::writer` traits. + * satisfy both the `io::Reader` and `io::Writer` traits. */ pub struct TcpSocketBuf { data: @TcpBufferedSocketData, @@ -89,7 +89,7 @@ pub struct TcpErrData { err_msg: ~str, } -/// Details returned as part of a `result::err` result from `tcp::listen` +/// Details returned as part of a `Result::Err` result from `tcp::listen` pub enum TcpListenErrData { /** * Some unplanned-for error. The first and second fields correspond @@ -116,7 +116,7 @@ pub enum TcpListenErrData { */ AccessDenied } -/// Details returned as part of a `result::err` result from `tcp::connect` +/// Details returned as part of a `Result::Err` result from `tcp::connect` pub enum TcpConnectErrData { /** * Some unplanned-for error. The first and second fields correspond @@ -139,9 +139,9 @@ pub enum TcpConnectErrData { * # Returns * * A `result` that, if the operation succeeds, contains a - * `net::net::tcp_socket` that can be used to send and receive data to/from + * `net::net::TcpSocket` that can be used to send and receive data to/from * the remote host. In the event of failure, a - * `net::tcp::tcp_connect_err_data` instance will be returned + * `net::tcp::TcpConnectErrData` instance will be returned */ pub fn connect(input_ip: ip::IpAddr, port: uint, iotask: &IoTask) @@ -288,14 +288,14 @@ pub fn connect(input_ip: ip::IpAddr, port: uint, * * # Arguments * - * * sock - a `tcp_socket` to write to + * * sock - a `TcpSocket` to write to * * raw_write_data - a vector of `~[u8]` that will be written to the stream. * This value must remain valid for the duration of the `write` call * * # Returns * - * A `result` object with a `nil` value as the `ok` variant, or a - * `tcp_err_data` value as the `err` variant + * A `Result` object with a `()` value as the `Ok` variant, or a + * `TcpErrData` value as the `Err` variant */ pub fn write(sock: &TcpSocket, raw_write_data: ~[u8]) -> result::Result<(), TcpErrData> { @@ -306,7 +306,7 @@ pub fn write(sock: &TcpSocket, raw_write_data: ~[u8]) } /** - * Write binary data to tcp stream; Returns a `future::future` value + * Write binary data to tcp stream; Returns a `future::Future` value * immediately * * # Safety @@ -314,27 +314,27 @@ pub fn write(sock: &TcpSocket, raw_write_data: ~[u8]) * This function can produce unsafe results if: * * 1. the call to `write_future` is made - * 2. the `future::future` value returned is never resolved via - * `future::get` - * 3. and then the `tcp_socket` passed in to `write_future` leaves + * 2. the `future::Future` value returned is never resolved via + * `Future::get` + * 3. and then the `TcpSocket` passed in to `write_future` leaves * scope and is destructed before the task that runs the libuv write * operation completes. * * As such: If using `write_future`, always be sure to resolve the returned - * `future` so as to ensure libuv doesn't try to access a released write + * `Future` so as to ensure libuv doesn't try to access a released write * handle. Otherwise, use the blocking `tcp::write` function instead. * * # Arguments * - * * sock - a `tcp_socket` to write to + * * sock - a `TcpSocket` to write to * * raw_write_data - a vector of `~[u8]` that will be written to the stream. * This value must remain valid for the duration of the `write` call * * # Returns * - * A `future` value that, once the `write` operation completes, resolves to a - * `result` object with a `nil` value as the `ok` variant, or a `tcp_err_data` - * value as the `err` variant + * A `Future` value that, once the `write` operation completes, resolves to a + * `Result` object with a `nil` value as the `Ok` variant, or a `TcpErrData` + * value as the `Err` variant */ pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8]) -> future::Future> { @@ -353,14 +353,14 @@ pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8]) * * # Arguments * - * * sock -- a `net::tcp::tcp_socket` for the connection to read from + * * sock -- a `net::tcp::TcpSocket` for the connection to read from * * # Returns * - * * A `result` instance that will either contain a - * `core::comm::port` that the user can read (and - * optionally, loop on) from until `read_stop` is called, or a - * `tcp_err_data` record + * * A `Result` instance that will either contain a + * `core::comm::Port>` that the user can read + * (and * optionally, loop on) from until `read_stop` is called, or a + * `TcpErrData` record */ pub fn read_start(sock: &TcpSocket) -> result::Result<@Port< @@ -376,7 +376,7 @@ pub fn read_start(sock: &TcpSocket) * * # Arguments * - * * `sock` - a `net::tcp::tcp_socket` that you wish to stop reading on + * * `sock` - a `net::tcp::TcpSocket` that you wish to stop reading on */ pub fn read_stop(sock: &TcpSocket) -> result::Result<(), TcpErrData> { @@ -387,17 +387,17 @@ pub fn read_stop(sock: &TcpSocket) -> } /** - * Reads a single chunk of data from `tcp_socket`; block until data/error + * Reads a single chunk of data from `TcpSocket`; block until data/error * recv'd * * Does a blocking read operation for a single chunk of data from a - * `tcp_socket` until a data arrives or an error is received. The provided + * `TcpSocket` until a data arrives or an error is received. The provided * `timeout_msecs` value is used to raise an error if the timeout period * passes without any data received. * * # Arguments * - * * `sock` - a `net::tcp::tcp_socket` that you wish to read from + * * `sock` - a `net::tcp::TcpSocket` that you wish to read from * * `timeout_msecs` - a `uint` value, in msecs, to wait before dropping the * read attempt. Pass `0u` to wait indefinitely */ @@ -408,12 +408,12 @@ pub fn read(sock: &TcpSocket, timeout_msecs: uint) } /** - * Reads a single chunk of data; returns a `future::future<~[u8]>` + * Reads a single chunk of data; returns a `future::Future<~[u8]>` * immediately * * Does a non-blocking read operation for a single chunk of data from a - * `tcp_socket` and immediately returns a `future` value representing the - * result. When resolving the returned `future`, it will block until data + * `TcpSocket` and immediately returns a `Future` value representing the + * result. When resolving the returned `Future`, it will block until data * arrives or an error is received. The provided `timeout_msecs` * value is used to raise an error if the timeout period passes without any * data received. @@ -421,18 +421,18 @@ pub fn read(sock: &TcpSocket, timeout_msecs: uint) * # Safety * * This function can produce unsafe results if the call to `read_future` is - * made, the `future::future` value returned is never resolved via - * `future::get`, and then the `tcp_socket` passed in to `read_future` leaves + * made, the `future::Future` value returned is never resolved via + * `Future::get`, and then the `TcpSocket` passed in to `read_future` leaves * scope and is destructed before the task that runs the libuv read * operation completes. * * As such: If using `read_future`, always be sure to resolve the returned - * `future` so as to ensure libuv doesn't try to access a released read + * `Future` so as to ensure libuv doesn't try to access a released read * handle. Otherwise, use the blocking `tcp::read` function instead. * * # Arguments * - * * `sock` - a `net::tcp::tcp_socket` that you wish to read from + * * `sock` - a `net::tcp::TcpSocket` that you wish to read from * * `timeout_msecs` - a `uint` value, in msecs, to wait before dropping the * read attempt. Pass `0u` to wait indefinitely */ @@ -445,7 +445,7 @@ fn read_future(sock: &TcpSocket, timeout_msecs: uint) } /** - * Bind an incoming client connection to a `net::tcp::tcp_socket` + * Bind an incoming client connection to a `net::tcp::TcpSocket` * * # Notes * @@ -461,7 +461,7 @@ fn read_future(sock: &TcpSocket, timeout_msecs: uint) * * This implies that a port/chan pair must be used to make sure that the * `new_connect_cb` call blocks until an attempt to create a - * `net::tcp::tcp_socket` is completed. + * `net::tcp::TcpSocket` is completed. * * # Example * @@ -469,49 +469,49 @@ fn read_future(sock: &TcpSocket, timeout_msecs: uint) * a task spawned by the `new_connect_cb` passed into `listen` * * ~~~~~~~~~~~ - * net::tcp::listen(remote_ip, remote_port, backlog) + * do net::tcp::listen(remote_ip, remote_port, backlog, iotask, * // this callback is ran once after the connection is successfully * // set up - * {|kill_ch| + * |kill_ch| { * // pass the kill_ch to your main loop or wherever you want * // to be able to externally kill the server from - * } + * }) * // this callback is ran when a new connection arrives - * {|new_conn, kill_ch| - * let cont_po = core::comm::port::>(); - * let cont_ch = core::comm::chan(cont_po); - * task::spawn {|| + * |new_conn, kill_ch| { + * let (cont_po, cont_ch) = comm::stream::>(); + * do task::spawn { * let accept_result = net::tcp::accept(new_conn); - * if accept_result.is_err() { - * core::comm::send(cont_ch, result::get_err(accept_result)); - * // fail? - * } - * else { - * let sock = result::get(accept_result); - * core::comm::send(cont_ch, true); - * // do work here + * match accept_result { + * Err(accept_error) => { + * cont_ch.send(Some(accept_error)); + * // fail? + * }, + * Ok(sock) => { + * cont_ch.send(None); + * // do work here + * } * } * }; - * match core::comm::recv(cont_po) { + * match cont_po.recv() { * // shut down listen() - * Some(err_data) { core::comm::send(kill_chan, Some(err_data)) } + * Some(err_data) => kill_ch.send(Some(err_data)), * // wait for next connection - * None {} + * None => () * } * }; * ~~~~~~~~~~~ * * # Arguments * - * * `new_conn` - an opaque value used to create a new `tcp_socket` + * * `new_conn` - an opaque value used to create a new `TcpSocket` * * # Returns * - * On success, this function will return a `net::tcp::tcp_socket` as the - * `ok` variant of a `result`. The `net::tcp::tcp_socket` is anchored within + * On success, this function will return a `net::tcp::TcpSocket` as the + * `Ok` variant of a `Result`. The `net::tcp::TcpSocket` is anchored within * the task that `accept` was called within for its lifetime. On failure, - * this function will return a `net::tcp::tcp_err_data` record - * as the `err` variant of a `result`. + * this function will return a `net::tcp::TcpErrData` record + * as the `Err` variant of a `Result`. */ pub fn accept(new_conn: TcpNewConnection) -> result::Result { @@ -600,27 +600,27 @@ pub fn accept(new_conn: TcpNewConnection) * * # Arguments * - * * `host_ip` - a `net::ip::ip_addr` representing a unique IP + * * `host_ip` - a `net::ip::IpAddr` representing a unique IP * (versions 4 or 6) * * `port` - a uint representing the port to listen on * * `backlog` - a uint representing the number of incoming connections * to cache in memory - * * `hl_loop` - a `uv::hl::high_level_loop` that the tcp request will run on + * * `hl_loop` - a `uv_iotask::IoTask` that the tcp request will run on * * `on_establish_cb` - a callback that is evaluated if/when the listener * is successfully established. it takes no parameters * * `new_connect_cb` - a callback to be evaluated, on the libuv thread, * whenever a client attempts to conect on the provided ip/port. the * callback's arguments are: * * `new_conn` - an opaque type that can be passed to - * `net::tcp::accept` in order to be converted to a `tcp_socket`. - * * `kill_ch` - channel of type `core::comm::chan>`. + * `net::tcp::accept` in order to be converted to a `TcpSocket`. + * * `kill_ch` - channel of type `core::comm::Chan>`. * this channel can be used to send a message to cause `listen` to begin * closing the underlying libuv data structures. * * # returns * - * a `result` instance containing empty data of type `()` on a - * successful/normal shutdown, and a `tcp_listen_err_data` enum in the event + * a `Result` instance containing empty data of type `()` on a + * successful/normal shutdown, and a `TcpListenErrData` enum in the event * of listen exiting because of an error */ pub fn listen(host_ip: ip::IpAddr, port: uint, backlog: uint, @@ -799,19 +799,19 @@ fn listen_common(host_ip: ip::IpAddr, port: uint, backlog: uint, /** - * Convert a `net::tcp::tcp_socket` to a `net::tcp::tcp_socket_buf`. + * Convert a `net::tcp::TcpSocket` to a `net::tcp::TcpSocketBuf`. * - * This function takes ownership of a `net::tcp::tcp_socket`, returning it - * stored within a buffered wrapper, which can be converted to a `io::reader` - * or `io::writer` + * This function takes ownership of a `net::tcp::TcpSocket`, returning it + * stored within a buffered wrapper, which can be converted to a `io::Reader` + * or `io::Writer` * * # Arguments * - * * `sock` -- a `net::tcp::tcp_socket` that you want to buffer + * * `sock` -- a `net::tcp::TcpSocket` that you want to buffer * * # Returns * - * A buffered wrapper that you can cast as an `io::reader` or `io::writer` + * A buffered wrapper that you can cast as an `io::Reader` or `io::Writer` */ pub fn socket_buf(sock: TcpSocket) -> TcpSocketBuf { TcpSocketBuf(@TcpBufferedSocketData { @@ -819,7 +819,7 @@ pub fn socket_buf(sock: TcpSocket) -> TcpSocketBuf { }) } -/// Convenience methods extending `net::tcp::tcp_socket` +/// Convenience methods extending `net::tcp::TcpSocket` pub impl TcpSocket { pub fn read_start() -> result::Result<@Port< result::Result<~[u8], TcpErrData>>, TcpErrData> { @@ -862,7 +862,7 @@ pub impl TcpSocket { } } -/// Implementation of `io::reader` trait for a buffered `net::tcp::tcp_socket` +/// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket` impl io::Reader for TcpSocketBuf { fn read(&self, buf: &mut [u8], len: uint) -> uint { if len == 0 { return 0 } @@ -962,7 +962,7 @@ impl io::Reader for TcpSocketBuf { } } -/// Implementation of `io::reader` trait for a buffered `net::tcp::tcp_socket` +/// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket` impl io::Writer for TcpSocketBuf { pub fn write(&self, data: &[const u8]) { unsafe { -- cgit 1.4.1-3-g733a5 From bcf626812b88f63932c541f81c7f68360e31a7c1 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 27 Feb 2013 19:53:31 -0800 Subject: Rename core::private to core::unstable. #4743 --- src/libcore/at_vec.rs | 2 +- src/libcore/comm.rs | 6 +- src/libcore/core.rc | 8 +- src/libcore/num/f32.rs | 2 +- src/libcore/num/f64.rs | 2 +- src/libcore/os.rs | 5 +- src/libcore/pipes.rs | 4 +- src/libcore/prelude.rs | 2 +- src/libcore/private.rs | 366 ----------- src/libcore/private/at_exit.rs | 92 --- src/libcore/private/exchange_alloc.rs | 71 --- src/libcore/private/extfmt.rs | 676 --------------------- src/libcore/private/finally.rs | 97 --- src/libcore/private/global.rs | 294 --------- src/libcore/private/intrinsics.rs | 131 ---- src/libcore/private/weak_task.rs | 207 ------- src/libcore/ptr.rs | 2 +- src/libcore/rt.rs | 2 +- src/libcore/task/spawn.rs | 14 +- src/libcore/unstable.rs | 366 +++++++++++ src/libcore/unstable/at_exit.rs | 92 +++ src/libcore/unstable/exchange_alloc.rs | 71 +++ src/libcore/unstable/extfmt.rs | 676 +++++++++++++++++++++ src/libcore/unstable/finally.rs | 97 +++ src/libcore/unstable/global.rs | 294 +++++++++ src/libcore/unstable/intrinsics.rs | 131 ++++ src/libcore/unstable/weak_task.rs | 207 +++++++ src/libcore/vec.rs | 8 +- src/libstd/arc.rs | 6 +- src/libstd/sync.rs | 2 +- src/libstd/uv_global_loop.rs | 4 +- src/libsyntax/ext/fmt.rs | 4 +- src/test/compile-fail/noncopyable-match-pattern.rs | 2 +- src/test/run-pass/alt-ref-binding-in-guard-3256.rs | 2 +- src/test/run-pass/foreign-call-no-runtime.rs | 2 +- src/test/run-pass/type-use-i1-versus-i8.rs | 2 +- 36 files changed, 1976 insertions(+), 1973 deletions(-) delete mode 100644 src/libcore/private.rs delete mode 100644 src/libcore/private/at_exit.rs delete mode 100644 src/libcore/private/exchange_alloc.rs delete mode 100644 src/libcore/private/extfmt.rs delete mode 100644 src/libcore/private/finally.rs delete mode 100644 src/libcore/private/global.rs delete mode 100644 src/libcore/private/intrinsics.rs delete mode 100644 src/libcore/private/weak_task.rs create mode 100644 src/libcore/unstable.rs create mode 100644 src/libcore/unstable/at_exit.rs create mode 100644 src/libcore/unstable/exchange_alloc.rs create mode 100644 src/libcore/unstable/extfmt.rs create mode 100644 src/libcore/unstable/finally.rs create mode 100644 src/libcore/unstable/global.rs create mode 100644 src/libcore/unstable/intrinsics.rs create mode 100644 src/libcore/unstable/weak_task.rs (limited to 'src/libstd') diff --git a/src/libcore/at_vec.rs b/src/libcore/at_vec.rs index ab604d1f0b6..d89481766c0 100644 --- a/src/libcore/at_vec.rs +++ b/src/libcore/at_vec.rs @@ -183,7 +183,7 @@ pub mod raw { use at_vec::{capacity, rustrt}; use cast::transmute; use libc; - use private::intrinsics::{move_val_init}; + use unstable::intrinsics::{move_val_init}; use ptr::addr_of; use ptr; use sys; diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs index 238207f12b6..94272f63e67 100644 --- a/src/libcore/comm.rs +++ b/src/libcore/comm.rs @@ -12,7 +12,7 @@ use either::{Either, Left, Right}; use kinds::Owned; use option; use option::{Option, Some, None, unwrap}; -use private; +use unstable; use vec; use pipes::{recv, try_recv, wait_many, peek, PacketHeader}; @@ -242,7 +242,7 @@ impl Peekable for PortSet { } /// A channel that can be shared between many senders. -pub type SharedChan = private::Exclusive>; +pub type SharedChan = unstable::Exclusive>; impl GenericChan for SharedChan { fn send(x: T) { @@ -268,7 +268,7 @@ impl GenericSmartChan for SharedChan { /// Converts a `chan` into a `shared_chan`. pub fn SharedChan(c: Chan) -> SharedChan { - private::exclusive(c) + unstable::exclusive(c) } /// Receive a message from one of two endpoints. diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 3e514ce249f..525887f8cb3 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -228,8 +228,12 @@ pub const debug : u32 = 4_u32; // The runtime interface used by the compiler #[cfg(notest)] pub mod rt; // Private APIs -pub mod private; - +pub mod unstable; +// NOTE: Remove after snapshot +#[cfg(stage0)] +pub mod private { + pub use super::unstable::extfmt; +} /* For internal use, not exported */ diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index c4f2704ab9f..d4808bd111f 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -18,7 +18,7 @@ use num::strconv; use num; use ops; use option::Option; -use private::intrinsics::floorf32; +use unstable::intrinsics::floorf32; use from_str; use to_str; diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 8f3771312e4..5362a65f7ce 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -19,7 +19,7 @@ use num::strconv; use num; use ops; use option::Option; -use private::intrinsics::floorf64; +use unstable::intrinsics::floorf64; use to_str; use from_str; diff --git a/src/libcore/os.rs b/src/libcore/os.rs index 8b6d27496d9..5ede0c550ff 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -35,7 +35,6 @@ use libc::{mode_t, pid_t, FILE}; use option; use option::{Some, None}; use prelude::*; -use private; use ptr; use str; use task; @@ -145,8 +144,8 @@ This uses a per-runtime lock to serialize access. FIXME #4726: It would probably be appropriate to make this a real global */ fn with_env_lock(f: &fn() -> T) -> T { - use private::global::global_data_clone_create; - use private::{Exclusive, exclusive}; + use unstable::global::global_data_clone_create; + use unstable::{Exclusive, exclusive}; struct SharedValue(()); type ValueMutex = Exclusive; diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 77554656913..58ab2ce78f5 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -91,9 +91,9 @@ use libc; use option; use option::{None, Option, Some, unwrap}; use pipes; -use private::intrinsics; +use unstable::intrinsics; use ptr; -use private; +use unstable; use task; use vec; diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index d0a16f7875b..422d9a6eea0 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -69,7 +69,7 @@ pub use option; pub use os; pub use path; pub use comm; -pub use private; +pub use unstable; pub use ptr; pub use rand; pub use result; diff --git a/src/libcore/private.rs b/src/libcore/private.rs deleted file mode 100644 index d19951e76db..00000000000 --- a/src/libcore/private.rs +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[doc(hidden)]; - -use cast; -use iter; -use libc; -use option; -use comm::{GenericChan, GenericPort}; -use prelude::*; -use ptr; -use result; -use task; -use task::{TaskBuilder, atomically}; -use uint; - -#[path = "private/at_exit.rs"] -pub mod at_exit; -#[path = "private/global.rs"] -pub mod global; -#[path = "private/finally.rs"] -pub mod finally; -#[path = "private/weak_task.rs"] -pub mod weak_task; -#[path = "private/exchange_alloc.rs"] -pub mod exchange_alloc; -#[path = "private/intrinsics.rs"] -pub mod intrinsics; -#[path = "private/extfmt.rs"] -pub mod extfmt; - -extern mod rustrt { - pub unsafe fn rust_create_little_lock() -> rust_little_lock; - pub unsafe fn rust_destroy_little_lock(lock: rust_little_lock); - pub unsafe fn rust_lock_little_lock(lock: rust_little_lock); - pub unsafe fn rust_unlock_little_lock(lock: rust_little_lock); - - pub unsafe fn rust_raw_thread_start(f: &fn()) -> *raw_thread; - pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread); -} - -#[allow(non_camel_case_types)] // runtime type -type raw_thread = libc::c_void; - -/** - -Start a new thread outside of the current runtime context and wait -for it to terminate. - -The executing thread has no access to a task pointer and will be using -a normal large stack. -*/ -pub unsafe fn run_in_bare_thread(f: ~fn()) { - let (port, chan) = comm::stream(); - // FIXME #4525: Unfortunate that this creates an extra scheduler but it's - // necessary since rust_raw_thread_join_delete is blocking - do task::spawn_sched(task::SingleThreaded) { - unsafe { - let closure: &fn() = || { - f() - }; - let thread = rustrt::rust_raw_thread_start(closure); - rustrt::rust_raw_thread_join_delete(thread); - chan.send(()); - } - } - port.recv(); -} - -#[test] -fn test_run_in_bare_thread() { - unsafe { - let i = 100; - do run_in_bare_thread { - assert i == 100; - } - } -} - -#[test] -fn test_run_in_bare_thread_exchange() { - unsafe { - // Does the exchange heap work without the runtime? - let i = ~100; - do run_in_bare_thread { - assert i == ~100; - } - } -} - -fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { - unsafe { - let old = intrinsics::atomic_cxchg(address, oldval, newval); - old == oldval - } -} - -/**************************************************************************** - * Shared state & exclusive ARC - ****************************************************************************/ - -struct ArcData { - mut count: libc::intptr_t, - // FIXME(#3224) should be able to make this non-option to save memory - mut data: Option, -} - -struct ArcDestruct { - mut data: *libc::c_void, -} - -impl Drop for ArcDestruct{ - fn finalize(&self) { - unsafe { - do task::unkillable { - let data: ~ArcData = cast::reinterpret_cast(&self.data); - let new_count = - intrinsics::atomic_xsub(&mut data.count, 1) - 1; - assert new_count >= 0; - if new_count == 0 { - // drop glue takes over. - } else { - cast::forget(data); - } - } - } - } -} - -fn ArcDestruct(data: *libc::c_void) -> ArcDestruct { - ArcDestruct { - data: data - } -} - -/** - * COMPLETELY UNSAFE. Used as a primitive for the safe versions in std::arc. - * - * Data races between tasks can result in crashes and, with sufficient - * cleverness, arbitrary type coercion. - */ -pub type SharedMutableState = ArcDestruct; - -pub unsafe fn shared_mutable_state(data: T) -> - SharedMutableState { - let data = ~ArcData { count: 1, data: Some(data) }; - unsafe { - let ptr = cast::transmute(data); - ArcDestruct(ptr) - } -} - -#[inline(always)] -pub unsafe fn get_shared_mutable_state( - rc: *SharedMutableState) -> *mut T -{ - unsafe { - let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); - assert ptr.count > 0; - let r = cast::transmute(option::get_ref(&ptr.data)); - cast::forget(ptr); - return r; - } -} -#[inline(always)] -pub unsafe fn get_shared_immutable_state( - rc: &a/SharedMutableState) -> &a/T { - unsafe { - let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); - assert ptr.count > 0; - // Cast us back into the correct region - let r = cast::transmute_region(option::get_ref(&ptr.data)); - cast::forget(ptr); - return r; - } -} - -pub unsafe fn clone_shared_mutable_state(rc: &SharedMutableState) - -> SharedMutableState { - unsafe { - let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); - let new_count = intrinsics::atomic_xadd(&mut ptr.count, 1) + 1; - assert new_count >= 2; - cast::forget(ptr); - } - ArcDestruct((*rc).data) -} - -impl Clone for SharedMutableState { - fn clone(&self) -> SharedMutableState { - unsafe { - clone_shared_mutable_state(self) - } - } -} - -/****************************************************************************/ - -#[allow(non_camel_case_types)] // runtime type -type rust_little_lock = *libc::c_void; - -struct LittleLock { - l: rust_little_lock, -} - -impl Drop for LittleLock { - fn finalize(&self) { - unsafe { - rustrt::rust_destroy_little_lock(self.l); - } - } -} - -fn LittleLock() -> LittleLock { - unsafe { - LittleLock { - l: rustrt::rust_create_little_lock() - } - } -} - -pub impl LittleLock { - #[inline(always)] - unsafe fn lock(f: fn() -> T) -> T { - struct Unlock { - l: rust_little_lock, - drop { - unsafe { - rustrt::rust_unlock_little_lock(self.l); - } - } - } - - fn Unlock(l: rust_little_lock) -> Unlock { - Unlock { - l: l - } - } - - do atomically { - rustrt::rust_lock_little_lock(self.l); - let _r = Unlock(self.l); - f() - } - } -} - -struct ExData { lock: LittleLock, mut failed: bool, mut data: T, } -/** - * An arc over mutable data that is protected by a lock. For library use only. - */ -pub struct Exclusive { x: SharedMutableState> } - -pub fn exclusive(user_data: T) -> Exclusive { - let data = ExData { - lock: LittleLock(), mut failed: false, mut data: user_data - }; - Exclusive { x: unsafe { shared_mutable_state(data) } } -} - -impl Clone for Exclusive { - // Duplicate an exclusive ARC, as std::arc::clone. - fn clone(&self) -> Exclusive { - Exclusive { x: unsafe { clone_shared_mutable_state(&self.x) } } - } -} - -pub impl Exclusive { - // Exactly like std::arc::mutex_arc,access(), but with the little_lock - // instead of a proper mutex. Same reason for being unsafe. - // - // Currently, scheduling operations (i.e., yielding, receiving on a pipe, - // accessing the provided condition variable) are prohibited while inside - // the exclusive. Supporting that is a work in progress. - #[inline(always)] - unsafe fn with(f: fn(x: &mut T) -> U) -> U { - unsafe { - let rec = get_shared_mutable_state(&self.x); - do (*rec).lock.lock { - if (*rec).failed { - fail!( - ~"Poisoned exclusive - another task failed inside!"); - } - (*rec).failed = true; - let result = f(&mut (*rec).data); - (*rec).failed = false; - result - } - } - } - - #[inline(always)] - unsafe fn with_imm(f: fn(x: &T) -> U) -> U { - do self.with |x| { - f(cast::transmute_immut(x)) - } - } -} - -#[cfg(test)] -pub mod tests { - use core::option::{None, Some}; - - use cell::Cell; - use comm; - use option; - use private::exclusive; - use result; - use task; - use uint; - - #[test] - pub fn exclusive_arc() { - let mut futures = ~[]; - - let num_tasks = 10; - let count = 10; - - let total = exclusive(~0); - - for uint::range(0, num_tasks) |_i| { - let total = total.clone(); - let (port, chan) = comm::stream(); - futures.push(port); - - do task::spawn || { - for uint::range(0, count) |_i| { - do total.with |count| { - **count += 1; - } - } - chan.send(()); - } - }; - - for futures.each |f| { f.recv() } - - do total.with |total| { - assert **total == num_tasks * count - }; - } - - #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn exclusive_poison() { - // Tests that if one task fails inside of an exclusive, subsequent - // accesses will also fail. - let x = exclusive(1); - let x2 = x.clone(); - do task::try || { - do x2.with |one| { - assert *one == 2; - } - }; - do x.with |one| { - assert *one == 1; - } - } -} diff --git a/src/libcore/private/at_exit.rs b/src/libcore/private/at_exit.rs deleted file mode 100644 index 4785cb622cb..00000000000 --- a/src/libcore/private/at_exit.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use sys; -use cast; -use ptr; -use task; -use uint; -use vec; -use rand; -use libc::{c_void, size_t}; - -/** -Register a function to be run during runtime shutdown. - -After all non-weak tasks have exited, registered exit functions will -execute, in random order, on the primary scheduler. Each function runs -in its own unsupervised task. -*/ -pub fn at_exit(f: ~fn()) { - unsafe { - let runner: &fn(*ExitFunctions) = exit_runner; - let runner_pair: sys::Closure = cast::transmute(runner); - let runner_ptr = runner_pair.code; - let runner_ptr = cast::transmute(runner_ptr); - rustrt::rust_register_exit_function(runner_ptr, ~f); - } -} - -// NB: The double pointer indirection here is because ~fn() is a fat -// pointer and due to FFI problems I am more comfortable making the -// interface use a normal pointer -extern mod rustrt { - fn rust_register_exit_function(runner: *c_void, f: ~~fn()); -} - -struct ExitFunctions { - // The number of exit functions - count: size_t, - // The buffer of exit functions - start: *~~fn() -} - -fn exit_runner(exit_fns: *ExitFunctions) { - let exit_fns = unsafe { &*exit_fns }; - let count = (*exit_fns).count; - let start = (*exit_fns).start; - - // NB: from_buf memcpys from the source, which will - // give us ownership of the array of functions - let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) }; - // Let's not make any promises about execution order - rand::Rng().shuffle_mut(exit_fns_vec); - - debug!("running %u exit functions", exit_fns_vec.len()); - - while !exit_fns_vec.is_empty() { - match exit_fns_vec.pop() { - ~f => { - task::task().supervised().spawn(f); - } - } - } -} - -#[test] -fn test_at_exit() { - let i = 10; - do at_exit { - debug!("at_exit1"); - assert i == 10; - } -} - -#[test] -fn test_at_exit_many() { - let i = 10; - for uint::range(20, 100) |j| { - do at_exit { - debug!("at_exit2"); - assert i == 10; - assert j > i; - } - } -} diff --git a/src/libcore/private/exchange_alloc.rs b/src/libcore/private/exchange_alloc.rs deleted file mode 100644 index b6af9891e11..00000000000 --- a/src/libcore/private/exchange_alloc.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use sys::{TypeDesc, size_of}; -use libc::{c_void, size_t, uintptr_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; -use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use private::intrinsics::{atomic_xadd,atomic_xsub}; -use ptr::null; -use intrinsic::TyDesc; - -pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void { - unsafe { - assert td.is_not_null(); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert p.is_not_null(); - - // FIXME #3475: Converting between our two different tydesc types - let td: *TyDesc = transmute(td); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); - - let exchange_count = &mut *rust_get_exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - - return transmute(box); - } -} - -pub unsafe fn free(ptr: *c_void) { - let exchange_count = &mut *rust_get_exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - - assert ptr.is_not_null(); - c_free(ptr); -} - -fn get_box_size(body_size: uint, body_align: uint) -> uint { - let header_size = size_of::(); - // FIXME (#2699): This alignment calculation is suspicious. Is it right? - let total_size = align_to(header_size, body_align) + body_size; - return total_size; -} - -// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power -// of two. -fn align_to(size: uint, align: uint) -> uint { - assert align != 0; - (size + align - 1) & !(align - 1) -} - -extern { - #[rust_stack] - fn rust_get_exchange_count_ptr() -> *mut int; -} - diff --git a/src/libcore/private/extfmt.rs b/src/libcore/private/extfmt.rs deleted file mode 100644 index 616d37a133a..00000000000 --- a/src/libcore/private/extfmt.rs +++ /dev/null @@ -1,676 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Support for fmt! expressions. -//! -//! The syntax is close to that of Posix format strings: -//! -//! ~~~~~~ -//! Format := '%' Parameter? Flag* Width? Precision? Type -//! Parameter := [0-9]+ '$' -//! Flag := [ 0#+-] -//! Width := Parameter | [0-9]+ -//! Precision := '.' [0-9]+ -//! Type := [bcdfiostuxX?] -//! ~~~~~~ -//! -//! * Parameter is the 1-based argument to apply the format to. Currently not -//! implemented. -//! * Flag 0 causes leading zeros to be used for padding when converting -//! numbers. -//! * Flag # causes the conversion to be done in an *alternative* manner. -//! Currently not implemented. -//! * Flag + causes signed numbers to always be prepended with a sign -//! character. -//! * Flag - left justifies the result -//! * Width specifies the minimum field width of the result. By default -//! leading spaces are added. -//! * Precision specifies the minimum number of digits for integral types -//! and the minimum number -//! of decimal places for float. -//! -//! The types currently supported are: -//! -//! * b - bool -//! * c - char -//! * d - int -//! * f - float -//! * i - int (same as d) -//! * o - uint as octal -//! * t - uint as binary -//! * u - uint -//! * x - uint as lower-case hexadecimal -//! * X - uint as upper-case hexadecimal -//! * s - str (any flavor) -//! * ? - arbitrary type (does not use the to_str trait) - -/* -Syntax Extension: fmt - -Format a string - -The 'fmt' extension is modeled on the posix printf system. - -A posix conversion ostensibly looks like this - -> %~[parameter]~[flags]~[width]~[.precision]~[length]type - -Given the different numeric type bestiary we have, we omit the 'length' -parameter and support slightly different conversions for 'type' - -> %~[parameter]~[flags]~[width]~[.precision]type - -we also only support translating-to-rust a tiny subset of the possible -combinations at the moment. - -Example: - -debug!("hello, %s!", "world"); - -*/ - -use cmp::Eq; -use option::{Some, None}; -use prelude::*; -use str; - -/* - * We have a 'ct' (compile-time) module that parses format strings into a - * sequence of conversions. From those conversions AST fragments are built - * that call into properly-typed functions in the 'rt' (run-time) module. - * Each of those run-time conversion functions accepts another conversion - * description that specifies how to format its output. - * - * The building of the AST is currently done in a module inside the compiler, - * but should migrate over here as the plugin interface is defined. - */ - -// Functions used by the fmt extension at compile time -#[doc(hidden)] -pub mod ct { - use char; - use prelude::*; - use str; - use vec; - - #[deriving_eq] - pub enum Signedness { Signed, Unsigned, } - - #[deriving_eq] - pub enum Caseness { CaseUpper, CaseLower, } - - #[deriving_eq] - pub enum Ty { - TyBool, - TyStr, - TyChar, - TyInt(Signedness), - TyBits, - TyHex(Caseness), - TyOctal, - TyFloat, - TyPoly, - } - - #[deriving_eq] - pub enum Flag { - FlagLeftJustify, - FlagLeftZeroPad, - FlagSpaceForSign, - FlagSignAlways, - FlagAlternate, - } - - #[deriving_eq] - pub enum Count { - CountIs(uint), - CountIsParam(uint), - CountIsNextParam, - CountImplied, - } - - #[deriving_eq] - struct Parsed { - val: T, - next: uint - } - - pub impl Parsed { - static pure fn new(val: T, next: uint) -> Parsed { - Parsed {val: val, next: next} - } - } - - // A formatted conversion from an expression to a string - #[deriving_eq] - pub struct Conv { - param: Option, - flags: ~[Flag], - width: Count, - precision: Count, - ty: Ty - } - - // A fragment of the output sequence - #[deriving_eq] - pub enum Piece { PieceString(~str), PieceConv(Conv), } - - pub type ErrorFn = @fn(&str) -> !; - - pub fn parse_fmt_string(s: &str, err: ErrorFn) -> ~[Piece] { - fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) { - if to > from { - ps.push(PieceString(s.slice(from, to))); - } - } - - let lim = s.len(); - let mut h = 0; - let mut i = 0; - let mut pieces = ~[]; - - while i < lim { - if s[i] == '%' as u8 { - i += 1; - - if i >= lim { - err(~"unterminated conversion at end of string"); - } else if s[i] == '%' as u8 { - push_slice(&mut pieces, s, h, i); - i += 1; - } else { - push_slice(&mut pieces, s, h, i - 1); - let Parsed {val, next} = parse_conversion(s, i, lim, err); - pieces.push(val); - i = next; - } - - h = i; - } else { - i += str::utf8_char_width(s[i]); - } - } - - push_slice(&mut pieces, s, h, i); - pieces - } - - pub fn peek_num(s: &str, i: uint, lim: uint) -> Option> { - let mut i = i; - let mut accum = 0; - let mut found = false; - - while i < lim { - match char::to_digit(s[i] as char, 10) { - Some(x) => { - found = true; - accum *= 10; - accum += x; - i += 1; - } - None => break - } - } - - if found { - Some(Parsed::new(accum, i)) - } else { - None - } - } - - pub fn parse_conversion(s: &str, i: uint, lim: uint, err: ErrorFn) -> - Parsed { - let param = parse_parameter(s, i, lim); - // avoid copying ~[Flag] by destructuring - let Parsed {val: flags_val, next: flags_next} = parse_flags(s, - param.next, lim); - let width = parse_count(s, flags_next, lim); - let prec = parse_precision(s, width.next, lim); - let ty = parse_type(s, prec.next, lim, err); - - Parsed::new(PieceConv(Conv { - param: param.val, - flags: flags_val, - width: width.val, - precision: prec.val, - ty: ty.val}), ty.next) - } - - pub fn parse_parameter(s: &str, i: uint, lim: uint) -> - Parsed> { - if i >= lim { return Parsed::new(None, i); } - - match peek_num(s, i, lim) { - Some(num) if num.next < lim && s[num.next] == '$' as u8 => - Parsed::new(Some(num.val), num.next + 1), - _ => Parsed::new(None, i) - } - } - - pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> { - let mut i = i; - let mut flags = ~[]; - - while i < lim { - let f = match s[i] { - '-' as u8 => FlagLeftJustify, - '0' as u8 => FlagLeftZeroPad, - ' ' as u8 => FlagSpaceForSign, - '+' as u8 => FlagSignAlways, - '#' as u8 => FlagAlternate, - _ => break - }; - - flags.push(f); - i += 1; - } - - Parsed::new(flags, i) - } - - pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed { - if i >= lim { - Parsed::new(CountImplied, i) - } else if s[i] == '*' as u8 { - let param = parse_parameter(s, i + 1, lim); - let j = param.next; - - match param.val { - None => Parsed::new(CountIsNextParam, j), - Some(n) => Parsed::new(CountIsParam(n), j) - } - } else { - match peek_num(s, i, lim) { - None => Parsed::new(CountImplied, i), - Some(num) => Parsed::new(CountIs(num.val), num.next) - } - } - } - - pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed { - if i < lim && s[i] == '.' as u8 { - let count = parse_count(s, i + 1, lim); - - // If there were no digits specified, i.e. the precision - // was ".", then the precision is 0 - match count.val { - CountImplied => Parsed::new(CountIs(0), count.next), - _ => count - } - } else { - Parsed::new(CountImplied, i) - } - } - - pub fn parse_type(s: &str, i: uint, lim: uint, err: ErrorFn) -> - Parsed { - if i >= lim { err(~"missing type in conversion"); } - - // FIXME (#2249): Do we really want two signed types here? - // How important is it to be printf compatible? - let t = match s[i] { - 'b' as u8 => TyBool, - 's' as u8 => TyStr, - 'c' as u8 => TyChar, - 'd' as u8 | 'i' as u8 => TyInt(Signed), - 'u' as u8 => TyInt(Unsigned), - 'x' as u8 => TyHex(CaseLower), - 'X' as u8 => TyHex(CaseUpper), - 't' as u8 => TyBits, - 'o' as u8 => TyOctal, - 'f' as u8 => TyFloat, - '?' as u8 => TyPoly, - _ => err(~"unknown type in conversion: " + s.substr(i, 1)) - }; - - Parsed::new(t, i + 1) - } - - #[cfg(test)] - fn die(s: &str) -> ! { fail!(s.to_owned()) } - - #[test] - fn test_parse_count() { - fn test(s: &str, count: Count, next: uint) -> bool { - parse_count(s, 0, s.len()) == Parsed::new(count, next) - } - - assert test("", CountImplied, 0); - assert test("*", CountIsNextParam, 1); - assert test("*1", CountIsNextParam, 1); - assert test("*1$", CountIsParam(1), 3); - assert test("123", CountIs(123), 3); - } - - #[test] - fn test_parse_flags() { - fn pack(fs: &[Flag]) -> uint { - fs.foldl(0, |&p, &f| p | (1 << f as uint)) - } - - fn test(s: &str, flags: &[Flag], next: uint) { - let f = parse_flags(s, 0, s.len()); - assert pack(f.val) == pack(flags); - assert f.next == next; - } - - test("", [], 0); - test("!#-+ 0", [], 0); - test("#-+", [FlagAlternate, FlagLeftJustify, FlagSignAlways], 3); - test(" 0", [FlagSpaceForSign, FlagLeftZeroPad], 2); - } - - #[test] - fn test_parse_fmt_string() { - assert parse_fmt_string("foo %s bar", die) == ~[ - PieceString(~"foo "), - PieceConv(Conv { - param: None, - flags: ~[], - width: CountImplied, - precision: CountImplied, - ty: TyStr, - }), - PieceString(~" bar")]; - - assert parse_fmt_string("%s", die) == ~[ - PieceConv(Conv { - param: None, - flags: ~[], - width: CountImplied, - precision: CountImplied, - ty: TyStr, - })]; - - assert parse_fmt_string("%%%%", die) == ~[ - PieceString(~"%"), PieceString(~"%")]; - } - - #[test] - fn test_parse_parameter() { - fn test(s: &str, param: Option, next: uint) -> bool { - parse_parameter(s, 0, s.len()) == Parsed::new(param, next) - } - - assert test("", None, 0); - assert test("foo", None, 0); - assert test("123", None, 0); - assert test("123$", Some(123), 4); - } - - #[test] - fn test_parse_precision() { - fn test(s: &str, count: Count, next: uint) -> bool { - parse_precision(s, 0, s.len()) == Parsed::new(count, next) - } - - assert test("", CountImplied, 0); - assert test(".", CountIs(0), 1); - assert test(".*", CountIsNextParam, 2); - assert test(".*1", CountIsNextParam, 2); - assert test(".*1$", CountIsParam(1), 4); - assert test(".123", CountIs(123), 4); - } - - #[test] - fn test_parse_type() { - fn test(s: &str, ty: Ty) -> bool { - parse_type(s, 0, s.len(), die) == Parsed::new(ty, 1) - } - - assert test("b", TyBool); - assert test("c", TyChar); - assert test("d", TyInt(Signed)); - assert test("f", TyFloat); - assert test("i", TyInt(Signed)); - assert test("o", TyOctal); - assert test("s", TyStr); - assert test("t", TyBits); - assert test("x", TyHex(CaseLower)); - assert test("X", TyHex(CaseUpper)); - assert test("?", TyPoly); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_parse_type_missing() { - parse_type("", 0, 0, die); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn test_parse_type_unknown() { - parse_type("!", 0, 1, die); - } - - #[test] - fn test_peek_num() { - let s1 = ""; - assert peek_num(s1, 0, s1.len()).is_none(); - - let s2 = "foo"; - assert peek_num(s2, 0, s2.len()).is_none(); - - let s3 = "123"; - assert peek_num(s3, 0, s3.len()) == Some(Parsed::new(123, 3)); - - let s4 = "123foo"; - assert peek_num(s4, 0, s4.len()) == Some(Parsed::new(123, 3)); - } -} - -// Functions used by the fmt extension at runtime. For now there are a lot of -// decisions made a runtime. If it proves worthwhile then some of these -// conditions can be evaluated at compile-time. For now though it's cleaner to -// implement it this way, I think. -#[doc(hidden)] -pub mod rt { - use float; - use str; - use sys; - use uint; - use vec; - - pub const flag_none : u32 = 0u32; - pub const flag_left_justify : u32 = 0b00000000000001u32; - pub const flag_left_zero_pad : u32 = 0b00000000000010u32; - pub const flag_space_for_sign : u32 = 0b00000000000100u32; - pub const flag_sign_always : u32 = 0b00000000001000u32; - pub const flag_alternate : u32 = 0b00000000010000u32; - - pub enum Count { CountIs(uint), CountImplied, } - - pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, } - - pub struct Conv { - flags: u32, - width: Count, - precision: Count, - ty: Ty, - } - - pub pure fn conv_int(cv: Conv, i: int) -> ~str { - let radix = 10; - let prec = get_int_precision(cv); - let mut s : ~str = int_to_str_prec(i, radix, prec); - if 0 <= i { - if have_flag(cv.flags, flag_sign_always) { - unsafe { str::unshift_char(&mut s, '+') }; - } else if have_flag(cv.flags, flag_space_for_sign) { - unsafe { str::unshift_char(&mut s, ' ') }; - } - } - return unsafe { pad(cv, s, PadSigned) }; - } - pub pure fn conv_uint(cv: Conv, u: uint) -> ~str { - let prec = get_int_precision(cv); - let mut rs = - match cv.ty { - TyDefault => uint_to_str_prec(u, 10, prec), - TyHexLower => uint_to_str_prec(u, 16, prec), - TyHexUpper => str::to_upper(uint_to_str_prec(u, 16, prec)), - TyBits => uint_to_str_prec(u, 2, prec), - TyOctal => uint_to_str_prec(u, 8, prec) - }; - return unsafe { pad(cv, rs, PadUnsigned) }; - } - pub pure fn conv_bool(cv: Conv, b: bool) -> ~str { - let s = if b { ~"true" } else { ~"false" }; - // run the boolean conversion through the string conversion logic, - // giving it the same rules for precision, etc. - return conv_str(cv, s); - } - pub pure fn conv_char(cv: Conv, c: char) -> ~str { - let mut s = str::from_char(c); - return unsafe { pad(cv, s, PadNozero) }; - } - pub pure fn conv_str(cv: Conv, s: &str) -> ~str { - // For strings, precision is the maximum characters - // displayed - let mut unpadded = match cv.precision { - CountImplied => s.to_owned(), - CountIs(max) => if max as uint < str::char_len(s) { - str::substr(s, 0, max as uint) - } else { - s.to_owned() - } - }; - return unsafe { pad(cv, unpadded, PadNozero) }; - } - pub pure fn conv_float(cv: Conv, f: float) -> ~str { - let (to_str, digits) = match cv.precision { - CountIs(c) => (float::to_str_exact, c as uint), - CountImplied => (float::to_str_digits, 6u) - }; - let mut s = unsafe { to_str(f, digits) }; - if 0.0 <= f { - if have_flag(cv.flags, flag_sign_always) { - s = ~"+" + s; - } else if have_flag(cv.flags, flag_space_for_sign) { - s = ~" " + s; - } - } - return unsafe { pad(cv, s, PadFloat) }; - } - pub pure fn conv_poly(cv: Conv, v: &T) -> ~str { - let s = sys::log_str(v); - return conv_str(cv, s); - } - - // Convert an int to string with minimum number of digits. If precision is - // 0 and num is 0 then the result is the empty string. - pub pure fn int_to_str_prec(num: int, radix: uint, prec: uint) -> ~str { - return if num < 0 { - ~"-" + uint_to_str_prec(-num as uint, radix, prec) - } else { uint_to_str_prec(num as uint, radix, prec) }; - } - - // Convert a uint to string with a minimum number of digits. If precision - // is 0 and num is 0 then the result is the empty string. Could move this - // to uint: but it doesn't seem all that useful. - pub pure fn uint_to_str_prec(num: uint, radix: uint, - prec: uint) -> ~str { - return if prec == 0u && num == 0u { - ~"" - } else { - let s = uint::to_str_radix(num, radix); - let len = str::char_len(s); - if len < prec { - let diff = prec - len; - let pad = str::from_chars(vec::from_elem(diff, '0')); - pad + s - } else { s } - }; - } - pub pure fn get_int_precision(cv: Conv) -> uint { - return match cv.precision { - CountIs(c) => c as uint, - CountImplied => 1u - }; - } - - #[deriving_eq] - pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat } - - pub fn pad(cv: Conv, s: ~str, mode: PadMode) -> ~str { - let mut s = s; // sadtimes - let uwidth : uint = match cv.width { - CountImplied => return (s), - CountIs(width) => { width as uint } - }; - let strlen = str::char_len(s); - if uwidth <= strlen { return (s); } - let mut padchar = ' '; - let diff = uwidth - strlen; - if have_flag(cv.flags, flag_left_justify) { - let padstr = str::from_chars(vec::from_elem(diff, padchar)); - return s + padstr; - } - let (might_zero_pad, signed) = match mode { - PadNozero => (false, true), - PadSigned => (true, true), - PadFloat => (true, true), - PadUnsigned => (true, false) - }; - pure fn have_precision(cv: Conv) -> bool { - return match cv.precision { CountImplied => false, _ => true }; - } - let zero_padding = { - if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) && - (!have_precision(cv) || mode == PadFloat) { - padchar = '0'; - true - } else { - false - } - }; - let padstr = str::from_chars(vec::from_elem(diff, padchar)); - // This is completely heinous. If we have a signed value then - // potentially rip apart the intermediate result and insert some - // zeros. It may make sense to convert zero padding to a precision - // instead. - - if signed && zero_padding && s.len() > 0 { - let head = str::shift_char(&mut s); - if head == '+' || head == '-' || head == ' ' { - let headstr = str::from_chars(vec::from_elem(1u, head)); - return headstr + padstr + s; - } - else { - str::unshift_char(&mut s, head); - } - } - return padstr + s; - } - pub pure fn have_flag(flags: u32, f: u32) -> bool { - flags & f != 0 - } -} - -// Bulk of the tests are in src/test/run-pass/syntax-extension-fmt.rs -#[cfg(test)] -mod test { - #[test] - fn fmt_slice() { - let s = "abc"; - let _s = fmt!("%s", s); - } -} - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/private/finally.rs b/src/libcore/private/finally.rs deleted file mode 100644 index ff75963511c..00000000000 --- a/src/libcore/private/finally.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -The Finally trait provides a method, `finally` on -stack closures that emulates Java-style try/finally blocks. - -# Example - -~~~ -do || { - ... -}.finally { - alway_run_this(); -} -~~~ -*/ - -use ops::Drop; -use task::{spawn, failing}; - -pub trait Finally { - fn finally(&self, dtor: &fn()) -> T; -} - -impl Finally for &fn() -> T { - fn finally(&self, dtor: &fn()) -> T { - let _d = Finallyalizer { - dtor: dtor - }; - - (*self)() - } -} - -struct Finallyalizer { - dtor: &fn() -} - -impl Drop for Finallyalizer { - fn finalize(&self) { - (self.dtor)(); - } -} - -#[test] -fn test_success() { - let mut i = 0; - do (|| { - i = 10; - }).finally { - assert !failing(); - assert i == 10; - i = 20; - } - assert i == 20; -} - -#[test] -#[ignore(cfg(windows))] -#[should_fail] -fn test_fail() { - let mut i = 0; - do (|| { - i = 10; - fail!(); - }).finally { - assert failing(); - assert i == 10; - } -} - -#[test] -fn test_retval() { - let i = do (fn&() -> int { - 10 - }).finally { }; - assert i == 10; -} - -#[test] -fn test_compact() { - // FIXME #4727: Should be able to use a fn item instead - // of a closure for do_some_fallible_work, - // but it's a type error. - let do_some_fallible_work: &fn() = || { }; - fn but_always_run_this_function() { } - do_some_fallible_work.finally( - but_always_run_this_function); -} diff --git a/src/libcore/private/global.rs b/src/libcore/private/global.rs deleted file mode 100644 index 77b61347250..00000000000 --- a/src/libcore/private/global.rs +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -Global data - -An interface for creating and retrieving values with global -(per-runtime) scope. - -Global values are stored in a map and protected by a single global -mutex. Operations are provided for accessing and cloning the value -under the mutex. - -Because all globals go through a single mutex, they should be used -sparingly. The interface is intended to be used with clonable, -atomically reference counted synchronization types, like ARCs, in -which case the value should be cached locally whenever possible to -avoid hitting the mutex. -*/ - -use cast::{transmute, reinterpret_cast}; -use clone::Clone; -use kinds::Owned; -use libc::{c_void, uintptr_t}; -use option::{Option, Some, None}; -use ops::Drop; -use pipes; -use private::{Exclusive, exclusive}; -use private::{SharedMutableState, shared_mutable_state}; -use private::{get_shared_immutable_state}; -use private::at_exit::at_exit; -use private::intrinsics::atomic_cxchg; -use hashmap::linear::LinearMap; -use sys::Closure; -use task::spawn; -use uint; - -pub type GlobalDataKey = &fn(v: T); - -pub unsafe fn global_data_clone_create( - key: GlobalDataKey, create: &fn() -> ~T) -> T { - /*! - * Clone a global value or, if it has not been created, - * first construct the value then return a clone. - * - * # Safety note - * - * Both the clone operation and the constructor are - * called while the global lock is held. Recursive - * use of the global interface in either of these - * operations will result in deadlock. - */ - global_data_clone_create_(key_ptr(key), create) -} - -unsafe fn global_data_clone_create_( - key: uint, create: &fn() -> ~T) -> T { - - let mut clone_value: Option = None; - do global_data_modify_(key) |value: Option<~T>| { - match value { - None => { - let value = create(); - clone_value = Some(value.clone()); - Some(value) - } - Some(value) => { - clone_value = Some(value.clone()); - Some(value) - } - } - } - return clone_value.unwrap(); -} - -unsafe fn global_data_modify( - key: GlobalDataKey, op: &fn(Option<~T>) -> Option<~T>) { - - global_data_modify_(key_ptr(key), op) -} - -unsafe fn global_data_modify_( - key: uint, op: &fn(Option<~T>) -> Option<~T>) { - - let mut old_dtor = None; - do get_global_state().with |gs| { - let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) { - Some((ptr, dtor)) => { - let value: ~T = transmute(ptr); - (op(Some(value)), Some(dtor)) - } - None => { - (op(None), None) - } - }; - match maybe_new_value { - Some(value) => { - let data: *c_void = transmute(value); - let dtor: ~fn() = match maybe_dtor { - Some(dtor) => dtor, - None => { - let dtor: ~fn() = || unsafe { - let _destroy_value: ~T = transmute(data); - }; - dtor - } - }; - let value = (data, dtor); - gs.map.insert(key, value); - } - None => { - match maybe_dtor { - Some(dtor) => old_dtor = Some(dtor), - None => () - } - } - } - } -} - -pub unsafe fn global_data_clone( - key: GlobalDataKey) -> Option { - let mut maybe_clone: Option = None; - do global_data_modify(key) |current| { - match ¤t { - &Some(~ref value) => { - maybe_clone = Some(value.clone()); - } - &None => () - } - current - } - return maybe_clone; -} - -// GlobalState is a map from keys to unique pointers and a -// destructor. Keys are pointers derived from the type of the -// global value. There is a single GlobalState instance per runtime. -struct GlobalState { - map: LinearMap -} - -impl Drop for GlobalState { - fn finalize(&self) { - for self.map.each_value |v| { - match v { - &(_, ref dtor) => (*dtor)() - } - } - } -} - -fn get_global_state() -> Exclusive { - - const POISON: int = -1; - - // FIXME #4728: Doing atomic_cxchg to initialize the global state - // lazily, which wouldn't be necessary with a runtime written - // in Rust - let global_ptr = unsafe { rust_get_global_data_ptr() }; - - if unsafe { *global_ptr } == 0 { - // Global state doesn't exist yet, probably - - // The global state object - let state = GlobalState { - map: LinearMap::new() - }; - - // It's under a reference-counted mutex - let state = ~exclusive(state); - - // Convert it to an integer - let state_i: int = unsafe { - let state_ptr: &Exclusive = state; - transmute(state_ptr) - }; - - // Swap our structure into the global pointer - let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) }; - - // Sanity check that we're not trying to reinitialize after shutdown - assert prev_i != POISON; - - if prev_i == 0 { - // Successfully installed the global pointer - - // Take a handle to return - let clone = state.clone(); - - // Install a runtime exit function to destroy the global object - do at_exit { - // Poison the global pointer - let prev_i = unsafe { - atomic_cxchg(&mut *global_ptr, state_i, POISON) - }; - assert prev_i == state_i; - - // Capture the global state object in the at_exit closure - // so that it is destroyed at the right time - let _capture_global_state = &state; - }; - return clone; - } else { - // Somebody else initialized the globals first - let state: &Exclusive = unsafe { transmute(prev_i) }; - return state.clone(); - } - } else { - let state: &Exclusive = unsafe { - transmute(*global_ptr) - }; - return state.clone(); - } -} - -fn key_ptr(key: GlobalDataKey) -> uint { - unsafe { - let closure: Closure = reinterpret_cast(&key); - return transmute(closure.code); - } -} - -extern { - fn rust_get_global_data_ptr() -> *mut int; -} - -#[test] -fn test_clone_rc() { - type MyType = SharedMutableState; - - fn key(_v: SharedMutableState) { } - - for uint::range(0, 100) |_| { - do spawn { - unsafe { - let val = do global_data_clone_create(key) { - ~shared_mutable_state(10) - }; - - assert get_shared_immutable_state(&val) == &10; - } - } - } -} - -#[test] -fn test_modify() { - type MyType = SharedMutableState; - - fn key(_v: SharedMutableState) { } - - unsafe { - do global_data_modify(key) |v| { - match v { - None => { - unsafe { - Some(~shared_mutable_state(10)) - } - } - _ => fail!() - } - } - - do global_data_modify(key) |v| { - match v { - Some(sms) => { - let v = get_shared_immutable_state(sms); - assert *v == 10; - None - }, - _ => fail!() - } - } - - do global_data_modify(key) |v| { - match v { - None => { - unsafe { - Some(~shared_mutable_state(10)) - } - } - _ => fail!() - } - } - } -} diff --git a/src/libcore/private/intrinsics.rs b/src/libcore/private/intrinsics.rs deleted file mode 100644 index 8f0067b7393..00000000000 --- a/src/libcore/private/intrinsics.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -An attempt to move all intrinsic declarations to a single place, -as mentioned in #3369 -The intrinsics are defined in librustc/middle/trans/foreign.rs. -*/ - -#[abi = "rust-intrinsic"] -pub extern { - pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int; - pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int; - pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int; - - pub fn atomic_xchg(dst: &mut int, src: int) -> int; - pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int; - pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int; - - pub fn atomic_xadd(dst: &mut int, src: int) -> int; - pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int; - pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int; - - pub fn atomic_xsub(dst: &mut int, src: int) -> int; - pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int; - pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int; - - pub fn size_of() -> uint; - - pub fn move_val(dst: &mut T, -src: T); - pub fn move_val_init(dst: &mut T, -src: T); - - pub fn min_align_of() -> uint; - pub fn pref_align_of() -> uint; - - pub fn get_tydesc() -> *(); - - pub fn init() -> T; - - pub fn forget(_: T) -> (); - - // XXX: intrinsic uses legacy modes - fn reinterpret_cast(&&src: T) -> U; - // XXX: intrinsic uses legacy modes - fn addr_of(&&scr: T) -> *T; - - pub fn needs_drop() -> bool; - - // XXX: intrinsic uses legacy modes and has reference to TyDesc - // and TyVisitor which are in librustc - //fn visit_tydesc(++td: *TyDesc, &&tv: TyVisitor) -> (); - // XXX: intrinsic uses legacy modes - //fn frame_address(f: &once fn(*u8)); - - pub fn morestack_addr() -> *(); - - pub fn memmove32(dst: *mut u8, src: *u8, size: u32); - pub fn memmove64(dst: *mut u8, src: *u8, size: u64); - - pub fn sqrtf32(x: f32) -> f32; - pub fn sqrtf64(x: f64) -> f64; - - pub fn powif32(a: f32, x: i32) -> f32; - pub fn powif64(a: f64, x: i32) -> f64; - - pub fn sinf32(x: f32) -> f32; - pub fn sinf64(x: f64) -> f64; - - pub fn cosf32(x: f32) -> f32; - pub fn cosf64(x: f64) -> f64; - - pub fn powf32(a: f32, x: f32) -> f32; - pub fn powf64(a: f64, x: f64) -> f64; - - pub fn expf32(x: f32) -> f32; - pub fn expf64(x: f64) -> f64; - - pub fn exp2f32(x: f32) -> f32; - pub fn exp2f64(x: f64) -> f64; - - pub fn logf32(x: f32) -> f32; - pub fn logf64(x: f64) -> f64; - - pub fn log10f32(x: f32) -> f32; - pub fn log10f64(x: f64) -> f64; - - pub fn log2f32(x: f32) -> f32; - pub fn log2f64(x: f64) -> f64; - - pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; - pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; - - pub fn fabsf32(x: f32) -> f32; - pub fn fabsf64(x: f64) -> f64; - - pub fn floorf32(x: f32) -> f32; - pub fn floorf64(x: f64) -> f64; - - pub fn ceilf32(x: f32) -> f32; - pub fn ceilf64(x: f64) -> f64; - - pub fn truncf32(x: f32) -> f32; - pub fn truncf64(x: f64) -> f64; - - pub fn ctpop8(x: i8) -> i8; - pub fn ctpop16(x: i16) -> i16; - pub fn ctpop32(x: i32) -> i32; - pub fn ctpop64(x: i64) -> i64; - - pub fn ctlz8(x: i8) -> i8; - pub fn ctlz16(x: i16) -> i16; - pub fn ctlz32(x: i32) -> i32; - pub fn ctlz64(x: i64) -> i64; - - pub fn cttz8(x: i8) -> i8; - pub fn cttz16(x: i16) -> i16; - pub fn cttz32(x: i32) -> i32; - pub fn cttz64(x: i64) -> i64; - - pub fn bswap16(x: i16) -> i16; - pub fn bswap32(x: i32) -> i32; - pub fn bswap64(x: i64) -> i64; -} - diff --git a/src/libcore/private/weak_task.rs b/src/libcore/private/weak_task.rs deleted file mode 100644 index 8445638850c..00000000000 --- a/src/libcore/private/weak_task.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -Weak tasks - -Weak tasks are a runtime feature for building global services that -do not keep the runtime alive. Normally the runtime exits when all -tasks exits, but if a task is weak then the runtime may exit while -it is running, sending a notification to the task that the runtime -is trying to shut down. -*/ - -use cell::Cell; -use comm::{GenericSmartChan, stream}; -use comm::{Port, Chan, SharedChan, GenericChan, GenericPort}; -use hashmap::linear::LinearMap; -use ops::Drop; -use option::{Some, None, swap_unwrap}; -use private::at_exit::at_exit; -use private::finally::Finally; -use private::global::global_data_clone_create; -use task::rt::{task_id, get_task_id}; -use task::{Task, task, spawn}; - -type ShutdownMsg = (); - -// FIXME #4729: This could be a PortOne but I've experienced bugginess -// with oneshot pipes and try_send -pub unsafe fn weaken_task(f: &fn(Port)) { - let service = global_data_clone_create(global_data_key, - create_global_service); - let (shutdown_port, shutdown_chan) = stream::(); - let shutdown_port = Cell(shutdown_port); - let task = get_task_id(); - // Expect the weak task service to be alive - assert service.try_send(RegisterWeakTask(task, shutdown_chan)); - unsafe { rust_dec_kernel_live_count(); } - do fn&() { - f(shutdown_port.take()) - }.finally || { - unsafe { rust_inc_kernel_live_count(); } - // Service my have already exited - service.send(UnregisterWeakTask(task)); - } -} - -type WeakTaskService = SharedChan; -type TaskHandle = task_id; - -fn global_data_key(_v: WeakTaskService) { } - -enum ServiceMsg { - RegisterWeakTask(TaskHandle, Chan), - UnregisterWeakTask(TaskHandle), - Shutdown -} - -fn create_global_service() -> ~WeakTaskService { - - debug!("creating global weak task service"); - let (port, chan) = stream::(); - let port = Cell(port); - let chan = SharedChan(chan); - let chan_clone = chan.clone(); - - do task().unlinked().spawn { - debug!("running global weak task service"); - let port = Cell(port.take()); - do fn&() { - let port = port.take(); - // The weak task service is itself a weak task - debug!("weakening the weak service task"); - unsafe { rust_dec_kernel_live_count(); } - run_weak_task_service(port); - }.finally { - debug!("unweakening the weak service task"); - unsafe { rust_inc_kernel_live_count(); } - } - } - - do at_exit { - debug!("shutting down weak task service"); - chan.send(Shutdown); - } - - return ~chan_clone; -} - -fn run_weak_task_service(port: Port) { - - let mut shutdown_map = LinearMap::new(); - - loop { - match port.recv() { - RegisterWeakTask(task, shutdown_chan) => { - let previously_unregistered = - shutdown_map.insert(task, shutdown_chan); - assert previously_unregistered; - } - UnregisterWeakTask(task) => { - match shutdown_map.pop(&task) { - Some(shutdown_chan) => { - // Oneshot pipes must send, even though - // nobody will receive this - shutdown_chan.send(()); - } - None => fail!() - } - } - Shutdown => break - } - } - - do shutdown_map.consume |_, shutdown_chan| { - // Weak task may have already exited - shutdown_chan.send(()); - } -} - -extern { - unsafe fn rust_inc_kernel_live_count(); - unsafe fn rust_dec_kernel_live_count(); -} - -#[test] -fn test_simple() { - let (port, chan) = stream(); - do spawn { - unsafe { - do weaken_task |_signal| { - } - } - chan.send(()); - } - port.recv(); -} - -#[test] -fn test_weak_weak() { - let (port, chan) = stream(); - do spawn { - unsafe { - do weaken_task |_signal| { - } - do weaken_task |_signal| { - } - } - chan.send(()); - } - port.recv(); -} - -#[test] -fn test_wait_for_signal() { - do spawn { - unsafe { - do weaken_task |signal| { - signal.recv(); - } - } - } -} - -#[test] -fn test_wait_for_signal_many() { - use uint; - for uint::range(0, 100) |_| { - do spawn { - unsafe { - do weaken_task |signal| { - signal.recv(); - } - } - } - } -} - -#[test] -fn test_select_stream_and_oneshot() { - use comm::select2i; - use either::{Left, Right}; - - let (port, chan) = stream(); - let (waitport, waitchan) = stream(); - do spawn { - unsafe { - do weaken_task |signal| { - match select2i(&port, &signal) { - Left(*) => (), - Right(*) => fail!() - } - } - } - waitchan.send(()); - } - chan.send(()); - waitport.recv(); -} - diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 2266c2511f8..5a7b319e7ff 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -14,7 +14,7 @@ use cast; use cmp::{Eq, Ord}; use libc; use libc::{c_void, size_t}; -use private::intrinsics::{memmove32,memmove64}; +use unstable::intrinsics::{memmove32,memmove64}; use ptr; use str; use sys; diff --git a/src/libcore/rt.rs b/src/libcore/rt.rs index 5d0bad3ceb3..a4f90e37683 100644 --- a/src/libcore/rt.rs +++ b/src/libcore/rt.rs @@ -15,7 +15,7 @@ use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int}; use managed::raw::BoxRepr; use str; use sys; -use private::exchange_alloc; +use unstable::exchange_alloc; use cast::transmute; use gc::{cleanup_stack_for_failure, gc, Word}; diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index bf7209f9fc3..6cc3657a32b 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -79,7 +79,7 @@ use option; use comm::{Chan, GenericChan, GenericPort, Port, stream}; use pipes; use prelude::*; -use private; +use unstable; use ptr; use hashmap::linear::LinearSet; use task::local_data_priv::{local_get, local_set}; @@ -123,7 +123,7 @@ struct TaskGroupData { // tasks in this group. mut descendants: TaskSet, } -type TaskGroupArc = private::Exclusive>; +type TaskGroupArc = unstable::Exclusive>; type TaskGroupInner = &mut Option; @@ -153,7 +153,7 @@ struct AncestorNode { mut ancestors: AncestorList, } -enum AncestorList = Option>; +enum AncestorList = Option>; // Accessors for taskgroup arcs and ancestor arcs that wrap the unsafety. #[inline(always)] @@ -162,7 +162,7 @@ fn access_group(x: &TaskGroupArc, blk: fn(TaskGroupInner) -> U) -> U { } #[inline(always)] -fn access_ancestors(x: &private::Exclusive, +fn access_ancestors(x: &unstable::Exclusive, blk: fn(x: &mut AncestorNode) -> U) -> U { unsafe { x.with(blk) } } @@ -458,7 +458,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) // Main task, doing first spawn ever. Lazily initialise here. let mut members = new_taskset(); taskset_insert(&mut members, spawner); - let tasks = private::exclusive(Some(TaskGroupData { + let tasks = unstable::exclusive(Some(TaskGroupData { members: members, descendants: new_taskset(), })); @@ -482,7 +482,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) (g, a, spawner_group.is_main) } else { // Child is in a separate group from spawner. - let g = private::exclusive(Some(TaskGroupData { + let g = unstable::exclusive(Some(TaskGroupData { members: new_taskset(), descendants: new_taskset(), })); @@ -502,7 +502,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) }; assert new_generation < uint::max_value; // Build a new node in the ancestor list. - AncestorList(Some(private::exclusive(AncestorNode { + AncestorList(Some(unstable::exclusive(AncestorNode { generation: new_generation, parent_group: Some(spawner_group.tasks.clone()), ancestors: old_ancestors, diff --git a/src/libcore/unstable.rs b/src/libcore/unstable.rs new file mode 100644 index 00000000000..b7b4b563425 --- /dev/null +++ b/src/libcore/unstable.rs @@ -0,0 +1,366 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[doc(hidden)]; + +use cast; +use iter; +use libc; +use option; +use comm::{GenericChan, GenericPort}; +use prelude::*; +use ptr; +use result; +use task; +use task::{TaskBuilder, atomically}; +use uint; + +#[path = "unstable/at_exit.rs"] +pub mod at_exit; +#[path = "unstable/global.rs"] +pub mod global; +#[path = "unstable/finally.rs"] +pub mod finally; +#[path = "unstable/weak_task.rs"] +pub mod weak_task; +#[path = "unstable/exchange_alloc.rs"] +pub mod exchange_alloc; +#[path = "unstable/intrinsics.rs"] +pub mod intrinsics; +#[path = "unstable/extfmt.rs"] +pub mod extfmt; + +extern mod rustrt { + pub unsafe fn rust_create_little_lock() -> rust_little_lock; + pub unsafe fn rust_destroy_little_lock(lock: rust_little_lock); + pub unsafe fn rust_lock_little_lock(lock: rust_little_lock); + pub unsafe fn rust_unlock_little_lock(lock: rust_little_lock); + + pub unsafe fn rust_raw_thread_start(f: &fn()) -> *raw_thread; + pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread); +} + +#[allow(non_camel_case_types)] // runtime type +type raw_thread = libc::c_void; + +/** + +Start a new thread outside of the current runtime context and wait +for it to terminate. + +The executing thread has no access to a task pointer and will be using +a normal large stack. +*/ +pub unsafe fn run_in_bare_thread(f: ~fn()) { + let (port, chan) = comm::stream(); + // FIXME #4525: Unfortunate that this creates an extra scheduler but it's + // necessary since rust_raw_thread_join_delete is blocking + do task::spawn_sched(task::SingleThreaded) { + unsafe { + let closure: &fn() = || { + f() + }; + let thread = rustrt::rust_raw_thread_start(closure); + rustrt::rust_raw_thread_join_delete(thread); + chan.send(()); + } + } + port.recv(); +} + +#[test] +fn test_run_in_bare_thread() { + unsafe { + let i = 100; + do run_in_bare_thread { + assert i == 100; + } + } +} + +#[test] +fn test_run_in_bare_thread_exchange() { + unsafe { + // Does the exchange heap work without the runtime? + let i = ~100; + do run_in_bare_thread { + assert i == ~100; + } + } +} + +fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { + unsafe { + let old = intrinsics::atomic_cxchg(address, oldval, newval); + old == oldval + } +} + +/**************************************************************************** + * Shared state & exclusive ARC + ****************************************************************************/ + +struct ArcData { + mut count: libc::intptr_t, + // FIXME(#3224) should be able to make this non-option to save memory + mut data: Option, +} + +struct ArcDestruct { + mut data: *libc::c_void, +} + +impl Drop for ArcDestruct{ + fn finalize(&self) { + unsafe { + do task::unkillable { + let data: ~ArcData = cast::reinterpret_cast(&self.data); + let new_count = + intrinsics::atomic_xsub(&mut data.count, 1) - 1; + assert new_count >= 0; + if new_count == 0 { + // drop glue takes over. + } else { + cast::forget(data); + } + } + } + } +} + +fn ArcDestruct(data: *libc::c_void) -> ArcDestruct { + ArcDestruct { + data: data + } +} + +/** + * COMPLETELY UNSAFE. Used as a primitive for the safe versions in std::arc. + * + * Data races between tasks can result in crashes and, with sufficient + * cleverness, arbitrary type coercion. + */ +pub type SharedMutableState = ArcDestruct; + +pub unsafe fn shared_mutable_state(data: T) -> + SharedMutableState { + let data = ~ArcData { count: 1, data: Some(data) }; + unsafe { + let ptr = cast::transmute(data); + ArcDestruct(ptr) + } +} + +#[inline(always)] +pub unsafe fn get_shared_mutable_state( + rc: *SharedMutableState) -> *mut T +{ + unsafe { + let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); + assert ptr.count > 0; + let r = cast::transmute(option::get_ref(&ptr.data)); + cast::forget(ptr); + return r; + } +} +#[inline(always)] +pub unsafe fn get_shared_immutable_state( + rc: &a/SharedMutableState) -> &a/T { + unsafe { + let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); + assert ptr.count > 0; + // Cast us back into the correct region + let r = cast::transmute_region(option::get_ref(&ptr.data)); + cast::forget(ptr); + return r; + } +} + +pub unsafe fn clone_shared_mutable_state(rc: &SharedMutableState) + -> SharedMutableState { + unsafe { + let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); + let new_count = intrinsics::atomic_xadd(&mut ptr.count, 1) + 1; + assert new_count >= 2; + cast::forget(ptr); + } + ArcDestruct((*rc).data) +} + +impl Clone for SharedMutableState { + fn clone(&self) -> SharedMutableState { + unsafe { + clone_shared_mutable_state(self) + } + } +} + +/****************************************************************************/ + +#[allow(non_camel_case_types)] // runtime type +type rust_little_lock = *libc::c_void; + +struct LittleLock { + l: rust_little_lock, +} + +impl Drop for LittleLock { + fn finalize(&self) { + unsafe { + rustrt::rust_destroy_little_lock(self.l); + } + } +} + +fn LittleLock() -> LittleLock { + unsafe { + LittleLock { + l: rustrt::rust_create_little_lock() + } + } +} + +pub impl LittleLock { + #[inline(always)] + unsafe fn lock(f: fn() -> T) -> T { + struct Unlock { + l: rust_little_lock, + drop { + unsafe { + rustrt::rust_unlock_little_lock(self.l); + } + } + } + + fn Unlock(l: rust_little_lock) -> Unlock { + Unlock { + l: l + } + } + + do atomically { + rustrt::rust_lock_little_lock(self.l); + let _r = Unlock(self.l); + f() + } + } +} + +struct ExData { lock: LittleLock, mut failed: bool, mut data: T, } +/** + * An arc over mutable data that is protected by a lock. For library use only. + */ +pub struct Exclusive { x: SharedMutableState> } + +pub fn exclusive(user_data: T) -> Exclusive { + let data = ExData { + lock: LittleLock(), mut failed: false, mut data: user_data + }; + Exclusive { x: unsafe { shared_mutable_state(data) } } +} + +impl Clone for Exclusive { + // Duplicate an exclusive ARC, as std::arc::clone. + fn clone(&self) -> Exclusive { + Exclusive { x: unsafe { clone_shared_mutable_state(&self.x) } } + } +} + +pub impl Exclusive { + // Exactly like std::arc::mutex_arc,access(), but with the little_lock + // instead of a proper mutex. Same reason for being unsafe. + // + // Currently, scheduling operations (i.e., yielding, receiving on a pipe, + // accessing the provided condition variable) are prohibited while inside + // the exclusive. Supporting that is a work in progress. + #[inline(always)] + unsafe fn with(f: fn(x: &mut T) -> U) -> U { + unsafe { + let rec = get_shared_mutable_state(&self.x); + do (*rec).lock.lock { + if (*rec).failed { + fail!( + ~"Poisoned exclusive - another task failed inside!"); + } + (*rec).failed = true; + let result = f(&mut (*rec).data); + (*rec).failed = false; + result + } + } + } + + #[inline(always)] + unsafe fn with_imm(f: fn(x: &T) -> U) -> U { + do self.with |x| { + f(cast::transmute_immut(x)) + } + } +} + +#[cfg(test)] +pub mod tests { + use core::option::{None, Some}; + + use cell::Cell; + use comm; + use option; + use super::exclusive; + use result; + use task; + use uint; + + #[test] + pub fn exclusive_arc() { + let mut futures = ~[]; + + let num_tasks = 10; + let count = 10; + + let total = exclusive(~0); + + for uint::range(0, num_tasks) |_i| { + let total = total.clone(); + let (port, chan) = comm::stream(); + futures.push(port); + + do task::spawn || { + for uint::range(0, count) |_i| { + do total.with |count| { + **count += 1; + } + } + chan.send(()); + } + }; + + for futures.each |f| { f.recv() } + + do total.with |total| { + assert **total == num_tasks * count + }; + } + + #[test] #[should_fail] #[ignore(cfg(windows))] + pub fn exclusive_poison() { + // Tests that if one task fails inside of an exclusive, subsequent + // accesses will also fail. + let x = exclusive(1); + let x2 = x.clone(); + do task::try || { + do x2.with |one| { + assert *one == 2; + } + }; + do x.with |one| { + assert *one == 1; + } + } +} diff --git a/src/libcore/unstable/at_exit.rs b/src/libcore/unstable/at_exit.rs new file mode 100644 index 00000000000..4785cb622cb --- /dev/null +++ b/src/libcore/unstable/at_exit.rs @@ -0,0 +1,92 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sys; +use cast; +use ptr; +use task; +use uint; +use vec; +use rand; +use libc::{c_void, size_t}; + +/** +Register a function to be run during runtime shutdown. + +After all non-weak tasks have exited, registered exit functions will +execute, in random order, on the primary scheduler. Each function runs +in its own unsupervised task. +*/ +pub fn at_exit(f: ~fn()) { + unsafe { + let runner: &fn(*ExitFunctions) = exit_runner; + let runner_pair: sys::Closure = cast::transmute(runner); + let runner_ptr = runner_pair.code; + let runner_ptr = cast::transmute(runner_ptr); + rustrt::rust_register_exit_function(runner_ptr, ~f); + } +} + +// NB: The double pointer indirection here is because ~fn() is a fat +// pointer and due to FFI problems I am more comfortable making the +// interface use a normal pointer +extern mod rustrt { + fn rust_register_exit_function(runner: *c_void, f: ~~fn()); +} + +struct ExitFunctions { + // The number of exit functions + count: size_t, + // The buffer of exit functions + start: *~~fn() +} + +fn exit_runner(exit_fns: *ExitFunctions) { + let exit_fns = unsafe { &*exit_fns }; + let count = (*exit_fns).count; + let start = (*exit_fns).start; + + // NB: from_buf memcpys from the source, which will + // give us ownership of the array of functions + let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) }; + // Let's not make any promises about execution order + rand::Rng().shuffle_mut(exit_fns_vec); + + debug!("running %u exit functions", exit_fns_vec.len()); + + while !exit_fns_vec.is_empty() { + match exit_fns_vec.pop() { + ~f => { + task::task().supervised().spawn(f); + } + } + } +} + +#[test] +fn test_at_exit() { + let i = 10; + do at_exit { + debug!("at_exit1"); + assert i == 10; + } +} + +#[test] +fn test_at_exit_many() { + let i = 10; + for uint::range(20, 100) |j| { + do at_exit { + debug!("at_exit2"); + assert i == 10; + assert j > i; + } + } +} diff --git a/src/libcore/unstable/exchange_alloc.rs b/src/libcore/unstable/exchange_alloc.rs new file mode 100644 index 00000000000..f59037445eb --- /dev/null +++ b/src/libcore/unstable/exchange_alloc.rs @@ -0,0 +1,71 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sys::{TypeDesc, size_of}; +use libc::{c_void, size_t, uintptr_t}; +use c_malloc = libc::malloc; +use c_free = libc::free; +use managed::raw::{BoxHeaderRepr, BoxRepr}; +use cast::transmute; +use unstable::intrinsics::{atomic_xadd,atomic_xsub}; +use ptr::null; +use intrinsic::TyDesc; + +pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void { + unsafe { + assert td.is_not_null(); + + let total_size = get_box_size(size, (*td).align); + let p = c_malloc(total_size as size_t); + assert p.is_not_null(); + + // FIXME #3475: Converting between our two different tydesc types + let td: *TyDesc = transmute(td); + + let box: &mut BoxRepr = transmute(p); + box.header.ref_count = -1; // Exchange values not ref counted + box.header.type_desc = td; + box.header.prev = null(); + box.header.next = null(); + + let exchange_count = &mut *rust_get_exchange_count_ptr(); + atomic_xadd(exchange_count, 1); + + return transmute(box); + } +} + +pub unsafe fn free(ptr: *c_void) { + let exchange_count = &mut *rust_get_exchange_count_ptr(); + atomic_xsub(exchange_count, 1); + + assert ptr.is_not_null(); + c_free(ptr); +} + +fn get_box_size(body_size: uint, body_align: uint) -> uint { + let header_size = size_of::(); + // FIXME (#2699): This alignment calculation is suspicious. Is it right? + let total_size = align_to(header_size, body_align) + body_size; + return total_size; +} + +// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power +// of two. +fn align_to(size: uint, align: uint) -> uint { + assert align != 0; + (size + align - 1) & !(align - 1) +} + +extern { + #[rust_stack] + fn rust_get_exchange_count_ptr() -> *mut int; +} + diff --git a/src/libcore/unstable/extfmt.rs b/src/libcore/unstable/extfmt.rs new file mode 100644 index 00000000000..616d37a133a --- /dev/null +++ b/src/libcore/unstable/extfmt.rs @@ -0,0 +1,676 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support for fmt! expressions. +//! +//! The syntax is close to that of Posix format strings: +//! +//! ~~~~~~ +//! Format := '%' Parameter? Flag* Width? Precision? Type +//! Parameter := [0-9]+ '$' +//! Flag := [ 0#+-] +//! Width := Parameter | [0-9]+ +//! Precision := '.' [0-9]+ +//! Type := [bcdfiostuxX?] +//! ~~~~~~ +//! +//! * Parameter is the 1-based argument to apply the format to. Currently not +//! implemented. +//! * Flag 0 causes leading zeros to be used for padding when converting +//! numbers. +//! * Flag # causes the conversion to be done in an *alternative* manner. +//! Currently not implemented. +//! * Flag + causes signed numbers to always be prepended with a sign +//! character. +//! * Flag - left justifies the result +//! * Width specifies the minimum field width of the result. By default +//! leading spaces are added. +//! * Precision specifies the minimum number of digits for integral types +//! and the minimum number +//! of decimal places for float. +//! +//! The types currently supported are: +//! +//! * b - bool +//! * c - char +//! * d - int +//! * f - float +//! * i - int (same as d) +//! * o - uint as octal +//! * t - uint as binary +//! * u - uint +//! * x - uint as lower-case hexadecimal +//! * X - uint as upper-case hexadecimal +//! * s - str (any flavor) +//! * ? - arbitrary type (does not use the to_str trait) + +/* +Syntax Extension: fmt + +Format a string + +The 'fmt' extension is modeled on the posix printf system. + +A posix conversion ostensibly looks like this + +> %~[parameter]~[flags]~[width]~[.precision]~[length]type + +Given the different numeric type bestiary we have, we omit the 'length' +parameter and support slightly different conversions for 'type' + +> %~[parameter]~[flags]~[width]~[.precision]type + +we also only support translating-to-rust a tiny subset of the possible +combinations at the moment. + +Example: + +debug!("hello, %s!", "world"); + +*/ + +use cmp::Eq; +use option::{Some, None}; +use prelude::*; +use str; + +/* + * We have a 'ct' (compile-time) module that parses format strings into a + * sequence of conversions. From those conversions AST fragments are built + * that call into properly-typed functions in the 'rt' (run-time) module. + * Each of those run-time conversion functions accepts another conversion + * description that specifies how to format its output. + * + * The building of the AST is currently done in a module inside the compiler, + * but should migrate over here as the plugin interface is defined. + */ + +// Functions used by the fmt extension at compile time +#[doc(hidden)] +pub mod ct { + use char; + use prelude::*; + use str; + use vec; + + #[deriving_eq] + pub enum Signedness { Signed, Unsigned, } + + #[deriving_eq] + pub enum Caseness { CaseUpper, CaseLower, } + + #[deriving_eq] + pub enum Ty { + TyBool, + TyStr, + TyChar, + TyInt(Signedness), + TyBits, + TyHex(Caseness), + TyOctal, + TyFloat, + TyPoly, + } + + #[deriving_eq] + pub enum Flag { + FlagLeftJustify, + FlagLeftZeroPad, + FlagSpaceForSign, + FlagSignAlways, + FlagAlternate, + } + + #[deriving_eq] + pub enum Count { + CountIs(uint), + CountIsParam(uint), + CountIsNextParam, + CountImplied, + } + + #[deriving_eq] + struct Parsed { + val: T, + next: uint + } + + pub impl Parsed { + static pure fn new(val: T, next: uint) -> Parsed { + Parsed {val: val, next: next} + } + } + + // A formatted conversion from an expression to a string + #[deriving_eq] + pub struct Conv { + param: Option, + flags: ~[Flag], + width: Count, + precision: Count, + ty: Ty + } + + // A fragment of the output sequence + #[deriving_eq] + pub enum Piece { PieceString(~str), PieceConv(Conv), } + + pub type ErrorFn = @fn(&str) -> !; + + pub fn parse_fmt_string(s: &str, err: ErrorFn) -> ~[Piece] { + fn push_slice(ps: &mut ~[Piece], s: &str, from: uint, to: uint) { + if to > from { + ps.push(PieceString(s.slice(from, to))); + } + } + + let lim = s.len(); + let mut h = 0; + let mut i = 0; + let mut pieces = ~[]; + + while i < lim { + if s[i] == '%' as u8 { + i += 1; + + if i >= lim { + err(~"unterminated conversion at end of string"); + } else if s[i] == '%' as u8 { + push_slice(&mut pieces, s, h, i); + i += 1; + } else { + push_slice(&mut pieces, s, h, i - 1); + let Parsed {val, next} = parse_conversion(s, i, lim, err); + pieces.push(val); + i = next; + } + + h = i; + } else { + i += str::utf8_char_width(s[i]); + } + } + + push_slice(&mut pieces, s, h, i); + pieces + } + + pub fn peek_num(s: &str, i: uint, lim: uint) -> Option> { + let mut i = i; + let mut accum = 0; + let mut found = false; + + while i < lim { + match char::to_digit(s[i] as char, 10) { + Some(x) => { + found = true; + accum *= 10; + accum += x; + i += 1; + } + None => break + } + } + + if found { + Some(Parsed::new(accum, i)) + } else { + None + } + } + + pub fn parse_conversion(s: &str, i: uint, lim: uint, err: ErrorFn) -> + Parsed { + let param = parse_parameter(s, i, lim); + // avoid copying ~[Flag] by destructuring + let Parsed {val: flags_val, next: flags_next} = parse_flags(s, + param.next, lim); + let width = parse_count(s, flags_next, lim); + let prec = parse_precision(s, width.next, lim); + let ty = parse_type(s, prec.next, lim, err); + + Parsed::new(PieceConv(Conv { + param: param.val, + flags: flags_val, + width: width.val, + precision: prec.val, + ty: ty.val}), ty.next) + } + + pub fn parse_parameter(s: &str, i: uint, lim: uint) -> + Parsed> { + if i >= lim { return Parsed::new(None, i); } + + match peek_num(s, i, lim) { + Some(num) if num.next < lim && s[num.next] == '$' as u8 => + Parsed::new(Some(num.val), num.next + 1), + _ => Parsed::new(None, i) + } + } + + pub fn parse_flags(s: &str, i: uint, lim: uint) -> Parsed<~[Flag]> { + let mut i = i; + let mut flags = ~[]; + + while i < lim { + let f = match s[i] { + '-' as u8 => FlagLeftJustify, + '0' as u8 => FlagLeftZeroPad, + ' ' as u8 => FlagSpaceForSign, + '+' as u8 => FlagSignAlways, + '#' as u8 => FlagAlternate, + _ => break + }; + + flags.push(f); + i += 1; + } + + Parsed::new(flags, i) + } + + pub fn parse_count(s: &str, i: uint, lim: uint) -> Parsed { + if i >= lim { + Parsed::new(CountImplied, i) + } else if s[i] == '*' as u8 { + let param = parse_parameter(s, i + 1, lim); + let j = param.next; + + match param.val { + None => Parsed::new(CountIsNextParam, j), + Some(n) => Parsed::new(CountIsParam(n), j) + } + } else { + match peek_num(s, i, lim) { + None => Parsed::new(CountImplied, i), + Some(num) => Parsed::new(CountIs(num.val), num.next) + } + } + } + + pub fn parse_precision(s: &str, i: uint, lim: uint) -> Parsed { + if i < lim && s[i] == '.' as u8 { + let count = parse_count(s, i + 1, lim); + + // If there were no digits specified, i.e. the precision + // was ".", then the precision is 0 + match count.val { + CountImplied => Parsed::new(CountIs(0), count.next), + _ => count + } + } else { + Parsed::new(CountImplied, i) + } + } + + pub fn parse_type(s: &str, i: uint, lim: uint, err: ErrorFn) -> + Parsed { + if i >= lim { err(~"missing type in conversion"); } + + // FIXME (#2249): Do we really want two signed types here? + // How important is it to be printf compatible? + let t = match s[i] { + 'b' as u8 => TyBool, + 's' as u8 => TyStr, + 'c' as u8 => TyChar, + 'd' as u8 | 'i' as u8 => TyInt(Signed), + 'u' as u8 => TyInt(Unsigned), + 'x' as u8 => TyHex(CaseLower), + 'X' as u8 => TyHex(CaseUpper), + 't' as u8 => TyBits, + 'o' as u8 => TyOctal, + 'f' as u8 => TyFloat, + '?' as u8 => TyPoly, + _ => err(~"unknown type in conversion: " + s.substr(i, 1)) + }; + + Parsed::new(t, i + 1) + } + + #[cfg(test)] + fn die(s: &str) -> ! { fail!(s.to_owned()) } + + #[test] + fn test_parse_count() { + fn test(s: &str, count: Count, next: uint) -> bool { + parse_count(s, 0, s.len()) == Parsed::new(count, next) + } + + assert test("", CountImplied, 0); + assert test("*", CountIsNextParam, 1); + assert test("*1", CountIsNextParam, 1); + assert test("*1$", CountIsParam(1), 3); + assert test("123", CountIs(123), 3); + } + + #[test] + fn test_parse_flags() { + fn pack(fs: &[Flag]) -> uint { + fs.foldl(0, |&p, &f| p | (1 << f as uint)) + } + + fn test(s: &str, flags: &[Flag], next: uint) { + let f = parse_flags(s, 0, s.len()); + assert pack(f.val) == pack(flags); + assert f.next == next; + } + + test("", [], 0); + test("!#-+ 0", [], 0); + test("#-+", [FlagAlternate, FlagLeftJustify, FlagSignAlways], 3); + test(" 0", [FlagSpaceForSign, FlagLeftZeroPad], 2); + } + + #[test] + fn test_parse_fmt_string() { + assert parse_fmt_string("foo %s bar", die) == ~[ + PieceString(~"foo "), + PieceConv(Conv { + param: None, + flags: ~[], + width: CountImplied, + precision: CountImplied, + ty: TyStr, + }), + PieceString(~" bar")]; + + assert parse_fmt_string("%s", die) == ~[ + PieceConv(Conv { + param: None, + flags: ~[], + width: CountImplied, + precision: CountImplied, + ty: TyStr, + })]; + + assert parse_fmt_string("%%%%", die) == ~[ + PieceString(~"%"), PieceString(~"%")]; + } + + #[test] + fn test_parse_parameter() { + fn test(s: &str, param: Option, next: uint) -> bool { + parse_parameter(s, 0, s.len()) == Parsed::new(param, next) + } + + assert test("", None, 0); + assert test("foo", None, 0); + assert test("123", None, 0); + assert test("123$", Some(123), 4); + } + + #[test] + fn test_parse_precision() { + fn test(s: &str, count: Count, next: uint) -> bool { + parse_precision(s, 0, s.len()) == Parsed::new(count, next) + } + + assert test("", CountImplied, 0); + assert test(".", CountIs(0), 1); + assert test(".*", CountIsNextParam, 2); + assert test(".*1", CountIsNextParam, 2); + assert test(".*1$", CountIsParam(1), 4); + assert test(".123", CountIs(123), 4); + } + + #[test] + fn test_parse_type() { + fn test(s: &str, ty: Ty) -> bool { + parse_type(s, 0, s.len(), die) == Parsed::new(ty, 1) + } + + assert test("b", TyBool); + assert test("c", TyChar); + assert test("d", TyInt(Signed)); + assert test("f", TyFloat); + assert test("i", TyInt(Signed)); + assert test("o", TyOctal); + assert test("s", TyStr); + assert test("t", TyBits); + assert test("x", TyHex(CaseLower)); + assert test("X", TyHex(CaseUpper)); + assert test("?", TyPoly); + } + + #[test] + #[should_fail] + #[ignore(cfg(windows))] + fn test_parse_type_missing() { + parse_type("", 0, 0, die); + } + + #[test] + #[should_fail] + #[ignore(cfg(windows))] + fn test_parse_type_unknown() { + parse_type("!", 0, 1, die); + } + + #[test] + fn test_peek_num() { + let s1 = ""; + assert peek_num(s1, 0, s1.len()).is_none(); + + let s2 = "foo"; + assert peek_num(s2, 0, s2.len()).is_none(); + + let s3 = "123"; + assert peek_num(s3, 0, s3.len()) == Some(Parsed::new(123, 3)); + + let s4 = "123foo"; + assert peek_num(s4, 0, s4.len()) == Some(Parsed::new(123, 3)); + } +} + +// Functions used by the fmt extension at runtime. For now there are a lot of +// decisions made a runtime. If it proves worthwhile then some of these +// conditions can be evaluated at compile-time. For now though it's cleaner to +// implement it this way, I think. +#[doc(hidden)] +pub mod rt { + use float; + use str; + use sys; + use uint; + use vec; + + pub const flag_none : u32 = 0u32; + pub const flag_left_justify : u32 = 0b00000000000001u32; + pub const flag_left_zero_pad : u32 = 0b00000000000010u32; + pub const flag_space_for_sign : u32 = 0b00000000000100u32; + pub const flag_sign_always : u32 = 0b00000000001000u32; + pub const flag_alternate : u32 = 0b00000000010000u32; + + pub enum Count { CountIs(uint), CountImplied, } + + pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, } + + pub struct Conv { + flags: u32, + width: Count, + precision: Count, + ty: Ty, + } + + pub pure fn conv_int(cv: Conv, i: int) -> ~str { + let radix = 10; + let prec = get_int_precision(cv); + let mut s : ~str = int_to_str_prec(i, radix, prec); + if 0 <= i { + if have_flag(cv.flags, flag_sign_always) { + unsafe { str::unshift_char(&mut s, '+') }; + } else if have_flag(cv.flags, flag_space_for_sign) { + unsafe { str::unshift_char(&mut s, ' ') }; + } + } + return unsafe { pad(cv, s, PadSigned) }; + } + pub pure fn conv_uint(cv: Conv, u: uint) -> ~str { + let prec = get_int_precision(cv); + let mut rs = + match cv.ty { + TyDefault => uint_to_str_prec(u, 10, prec), + TyHexLower => uint_to_str_prec(u, 16, prec), + TyHexUpper => str::to_upper(uint_to_str_prec(u, 16, prec)), + TyBits => uint_to_str_prec(u, 2, prec), + TyOctal => uint_to_str_prec(u, 8, prec) + }; + return unsafe { pad(cv, rs, PadUnsigned) }; + } + pub pure fn conv_bool(cv: Conv, b: bool) -> ~str { + let s = if b { ~"true" } else { ~"false" }; + // run the boolean conversion through the string conversion logic, + // giving it the same rules for precision, etc. + return conv_str(cv, s); + } + pub pure fn conv_char(cv: Conv, c: char) -> ~str { + let mut s = str::from_char(c); + return unsafe { pad(cv, s, PadNozero) }; + } + pub pure fn conv_str(cv: Conv, s: &str) -> ~str { + // For strings, precision is the maximum characters + // displayed + let mut unpadded = match cv.precision { + CountImplied => s.to_owned(), + CountIs(max) => if max as uint < str::char_len(s) { + str::substr(s, 0, max as uint) + } else { + s.to_owned() + } + }; + return unsafe { pad(cv, unpadded, PadNozero) }; + } + pub pure fn conv_float(cv: Conv, f: float) -> ~str { + let (to_str, digits) = match cv.precision { + CountIs(c) => (float::to_str_exact, c as uint), + CountImplied => (float::to_str_digits, 6u) + }; + let mut s = unsafe { to_str(f, digits) }; + if 0.0 <= f { + if have_flag(cv.flags, flag_sign_always) { + s = ~"+" + s; + } else if have_flag(cv.flags, flag_space_for_sign) { + s = ~" " + s; + } + } + return unsafe { pad(cv, s, PadFloat) }; + } + pub pure fn conv_poly(cv: Conv, v: &T) -> ~str { + let s = sys::log_str(v); + return conv_str(cv, s); + } + + // Convert an int to string with minimum number of digits. If precision is + // 0 and num is 0 then the result is the empty string. + pub pure fn int_to_str_prec(num: int, radix: uint, prec: uint) -> ~str { + return if num < 0 { + ~"-" + uint_to_str_prec(-num as uint, radix, prec) + } else { uint_to_str_prec(num as uint, radix, prec) }; + } + + // Convert a uint to string with a minimum number of digits. If precision + // is 0 and num is 0 then the result is the empty string. Could move this + // to uint: but it doesn't seem all that useful. + pub pure fn uint_to_str_prec(num: uint, radix: uint, + prec: uint) -> ~str { + return if prec == 0u && num == 0u { + ~"" + } else { + let s = uint::to_str_radix(num, radix); + let len = str::char_len(s); + if len < prec { + let diff = prec - len; + let pad = str::from_chars(vec::from_elem(diff, '0')); + pad + s + } else { s } + }; + } + pub pure fn get_int_precision(cv: Conv) -> uint { + return match cv.precision { + CountIs(c) => c as uint, + CountImplied => 1u + }; + } + + #[deriving_eq] + pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat } + + pub fn pad(cv: Conv, s: ~str, mode: PadMode) -> ~str { + let mut s = s; // sadtimes + let uwidth : uint = match cv.width { + CountImplied => return (s), + CountIs(width) => { width as uint } + }; + let strlen = str::char_len(s); + if uwidth <= strlen { return (s); } + let mut padchar = ' '; + let diff = uwidth - strlen; + if have_flag(cv.flags, flag_left_justify) { + let padstr = str::from_chars(vec::from_elem(diff, padchar)); + return s + padstr; + } + let (might_zero_pad, signed) = match mode { + PadNozero => (false, true), + PadSigned => (true, true), + PadFloat => (true, true), + PadUnsigned => (true, false) + }; + pure fn have_precision(cv: Conv) -> bool { + return match cv.precision { CountImplied => false, _ => true }; + } + let zero_padding = { + if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) && + (!have_precision(cv) || mode == PadFloat) { + padchar = '0'; + true + } else { + false + } + }; + let padstr = str::from_chars(vec::from_elem(diff, padchar)); + // This is completely heinous. If we have a signed value then + // potentially rip apart the intermediate result and insert some + // zeros. It may make sense to convert zero padding to a precision + // instead. + + if signed && zero_padding && s.len() > 0 { + let head = str::shift_char(&mut s); + if head == '+' || head == '-' || head == ' ' { + let headstr = str::from_chars(vec::from_elem(1u, head)); + return headstr + padstr + s; + } + else { + str::unshift_char(&mut s, head); + } + } + return padstr + s; + } + pub pure fn have_flag(flags: u32, f: u32) -> bool { + flags & f != 0 + } +} + +// Bulk of the tests are in src/test/run-pass/syntax-extension-fmt.rs +#[cfg(test)] +mod test { + #[test] + fn fmt_slice() { + let s = "abc"; + let _s = fmt!("%s", s); + } +} + +// Local Variables: +// mode: rust; +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// End: diff --git a/src/libcore/unstable/finally.rs b/src/libcore/unstable/finally.rs new file mode 100644 index 00000000000..ff75963511c --- /dev/null +++ b/src/libcore/unstable/finally.rs @@ -0,0 +1,97 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +The Finally trait provides a method, `finally` on +stack closures that emulates Java-style try/finally blocks. + +# Example + +~~~ +do || { + ... +}.finally { + alway_run_this(); +} +~~~ +*/ + +use ops::Drop; +use task::{spawn, failing}; + +pub trait Finally { + fn finally(&self, dtor: &fn()) -> T; +} + +impl Finally for &fn() -> T { + fn finally(&self, dtor: &fn()) -> T { + let _d = Finallyalizer { + dtor: dtor + }; + + (*self)() + } +} + +struct Finallyalizer { + dtor: &fn() +} + +impl Drop for Finallyalizer { + fn finalize(&self) { + (self.dtor)(); + } +} + +#[test] +fn test_success() { + let mut i = 0; + do (|| { + i = 10; + }).finally { + assert !failing(); + assert i == 10; + i = 20; + } + assert i == 20; +} + +#[test] +#[ignore(cfg(windows))] +#[should_fail] +fn test_fail() { + let mut i = 0; + do (|| { + i = 10; + fail!(); + }).finally { + assert failing(); + assert i == 10; + } +} + +#[test] +fn test_retval() { + let i = do (fn&() -> int { + 10 + }).finally { }; + assert i == 10; +} + +#[test] +fn test_compact() { + // FIXME #4727: Should be able to use a fn item instead + // of a closure for do_some_fallible_work, + // but it's a type error. + let do_some_fallible_work: &fn() = || { }; + fn but_always_run_this_function() { } + do_some_fallible_work.finally( + but_always_run_this_function); +} diff --git a/src/libcore/unstable/global.rs b/src/libcore/unstable/global.rs new file mode 100644 index 00000000000..aa28310f7ba --- /dev/null +++ b/src/libcore/unstable/global.rs @@ -0,0 +1,294 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Global data + +An interface for creating and retrieving values with global +(per-runtime) scope. + +Global values are stored in a map and protected by a single global +mutex. Operations are provided for accessing and cloning the value +under the mutex. + +Because all globals go through a single mutex, they should be used +sparingly. The interface is intended to be used with clonable, +atomically reference counted synchronization types, like ARCs, in +which case the value should be cached locally whenever possible to +avoid hitting the mutex. +*/ + +use cast::{transmute, reinterpret_cast}; +use clone::Clone; +use kinds::Owned; +use libc::{c_void, uintptr_t}; +use option::{Option, Some, None}; +use ops::Drop; +use pipes; +use unstable::{Exclusive, exclusive}; +use unstable::{SharedMutableState, shared_mutable_state}; +use unstable::{get_shared_immutable_state}; +use unstable::at_exit::at_exit; +use unstable::intrinsics::atomic_cxchg; +use hashmap::linear::LinearMap; +use sys::Closure; +use task::spawn; +use uint; + +pub type GlobalDataKey = &fn(v: T); + +pub unsafe fn global_data_clone_create( + key: GlobalDataKey, create: &fn() -> ~T) -> T { + /*! + * Clone a global value or, if it has not been created, + * first construct the value then return a clone. + * + * # Safety note + * + * Both the clone operation and the constructor are + * called while the global lock is held. Recursive + * use of the global interface in either of these + * operations will result in deadlock. + */ + global_data_clone_create_(key_ptr(key), create) +} + +unsafe fn global_data_clone_create_( + key: uint, create: &fn() -> ~T) -> T { + + let mut clone_value: Option = None; + do global_data_modify_(key) |value: Option<~T>| { + match value { + None => { + let value = create(); + clone_value = Some(value.clone()); + Some(value) + } + Some(value) => { + clone_value = Some(value.clone()); + Some(value) + } + } + } + return clone_value.unwrap(); +} + +unsafe fn global_data_modify( + key: GlobalDataKey, op: &fn(Option<~T>) -> Option<~T>) { + + global_data_modify_(key_ptr(key), op) +} + +unsafe fn global_data_modify_( + key: uint, op: &fn(Option<~T>) -> Option<~T>) { + + let mut old_dtor = None; + do get_global_state().with |gs| { + let (maybe_new_value, maybe_dtor) = match gs.map.pop(&key) { + Some((ptr, dtor)) => { + let value: ~T = transmute(ptr); + (op(Some(value)), Some(dtor)) + } + None => { + (op(None), None) + } + }; + match maybe_new_value { + Some(value) => { + let data: *c_void = transmute(value); + let dtor: ~fn() = match maybe_dtor { + Some(dtor) => dtor, + None => { + let dtor: ~fn() = || unsafe { + let _destroy_value: ~T = transmute(data); + }; + dtor + } + }; + let value = (data, dtor); + gs.map.insert(key, value); + } + None => { + match maybe_dtor { + Some(dtor) => old_dtor = Some(dtor), + None => () + } + } + } + } +} + +pub unsafe fn global_data_clone( + key: GlobalDataKey) -> Option { + let mut maybe_clone: Option = None; + do global_data_modify(key) |current| { + match ¤t { + &Some(~ref value) => { + maybe_clone = Some(value.clone()); + } + &None => () + } + current + } + return maybe_clone; +} + +// GlobalState is a map from keys to unique pointers and a +// destructor. Keys are pointers derived from the type of the +// global value. There is a single GlobalState instance per runtime. +struct GlobalState { + map: LinearMap +} + +impl Drop for GlobalState { + fn finalize(&self) { + for self.map.each_value |v| { + match v { + &(_, ref dtor) => (*dtor)() + } + } + } +} + +fn get_global_state() -> Exclusive { + + const POISON: int = -1; + + // FIXME #4728: Doing atomic_cxchg to initialize the global state + // lazily, which wouldn't be necessary with a runtime written + // in Rust + let global_ptr = unsafe { rust_get_global_data_ptr() }; + + if unsafe { *global_ptr } == 0 { + // Global state doesn't exist yet, probably + + // The global state object + let state = GlobalState { + map: LinearMap::new() + }; + + // It's under a reference-counted mutex + let state = ~exclusive(state); + + // Convert it to an integer + let state_i: int = unsafe { + let state_ptr: &Exclusive = state; + transmute(state_ptr) + }; + + // Swap our structure into the global pointer + let prev_i = unsafe { atomic_cxchg(&mut *global_ptr, 0, state_i) }; + + // Sanity check that we're not trying to reinitialize after shutdown + assert prev_i != POISON; + + if prev_i == 0 { + // Successfully installed the global pointer + + // Take a handle to return + let clone = state.clone(); + + // Install a runtime exit function to destroy the global object + do at_exit { + // Poison the global pointer + let prev_i = unsafe { + atomic_cxchg(&mut *global_ptr, state_i, POISON) + }; + assert prev_i == state_i; + + // Capture the global state object in the at_exit closure + // so that it is destroyed at the right time + let _capture_global_state = &state; + }; + return clone; + } else { + // Somebody else initialized the globals first + let state: &Exclusive = unsafe { transmute(prev_i) }; + return state.clone(); + } + } else { + let state: &Exclusive = unsafe { + transmute(*global_ptr) + }; + return state.clone(); + } +} + +fn key_ptr(key: GlobalDataKey) -> uint { + unsafe { + let closure: Closure = reinterpret_cast(&key); + return transmute(closure.code); + } +} + +extern { + fn rust_get_global_data_ptr() -> *mut int; +} + +#[test] +fn test_clone_rc() { + type MyType = SharedMutableState; + + fn key(_v: SharedMutableState) { } + + for uint::range(0, 100) |_| { + do spawn { + unsafe { + let val = do global_data_clone_create(key) { + ~shared_mutable_state(10) + }; + + assert get_shared_immutable_state(&val) == &10; + } + } + } +} + +#[test] +fn test_modify() { + type MyType = SharedMutableState; + + fn key(_v: SharedMutableState) { } + + unsafe { + do global_data_modify(key) |v| { + match v { + None => { + unsafe { + Some(~shared_mutable_state(10)) + } + } + _ => fail!() + } + } + + do global_data_modify(key) |v| { + match v { + Some(sms) => { + let v = get_shared_immutable_state(sms); + assert *v == 10; + None + }, + _ => fail!() + } + } + + do global_data_modify(key) |v| { + match v { + None => { + unsafe { + Some(~shared_mutable_state(10)) + } + } + _ => fail!() + } + } + } +} diff --git a/src/libcore/unstable/intrinsics.rs b/src/libcore/unstable/intrinsics.rs new file mode 100644 index 00000000000..8f0067b7393 --- /dev/null +++ b/src/libcore/unstable/intrinsics.rs @@ -0,0 +1,131 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +An attempt to move all intrinsic declarations to a single place, +as mentioned in #3369 +The intrinsics are defined in librustc/middle/trans/foreign.rs. +*/ + +#[abi = "rust-intrinsic"] +pub extern { + pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int; + pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int; + pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int; + + pub fn atomic_xchg(dst: &mut int, src: int) -> int; + pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int; + pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int; + + pub fn atomic_xadd(dst: &mut int, src: int) -> int; + pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int; + pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int; + + pub fn atomic_xsub(dst: &mut int, src: int) -> int; + pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int; + pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int; + + pub fn size_of() -> uint; + + pub fn move_val(dst: &mut T, -src: T); + pub fn move_val_init(dst: &mut T, -src: T); + + pub fn min_align_of() -> uint; + pub fn pref_align_of() -> uint; + + pub fn get_tydesc() -> *(); + + pub fn init() -> T; + + pub fn forget(_: T) -> (); + + // XXX: intrinsic uses legacy modes + fn reinterpret_cast(&&src: T) -> U; + // XXX: intrinsic uses legacy modes + fn addr_of(&&scr: T) -> *T; + + pub fn needs_drop() -> bool; + + // XXX: intrinsic uses legacy modes and has reference to TyDesc + // and TyVisitor which are in librustc + //fn visit_tydesc(++td: *TyDesc, &&tv: TyVisitor) -> (); + // XXX: intrinsic uses legacy modes + //fn frame_address(f: &once fn(*u8)); + + pub fn morestack_addr() -> *(); + + pub fn memmove32(dst: *mut u8, src: *u8, size: u32); + pub fn memmove64(dst: *mut u8, src: *u8, size: u64); + + pub fn sqrtf32(x: f32) -> f32; + pub fn sqrtf64(x: f64) -> f64; + + pub fn powif32(a: f32, x: i32) -> f32; + pub fn powif64(a: f64, x: i32) -> f64; + + pub fn sinf32(x: f32) -> f32; + pub fn sinf64(x: f64) -> f64; + + pub fn cosf32(x: f32) -> f32; + pub fn cosf64(x: f64) -> f64; + + pub fn powf32(a: f32, x: f32) -> f32; + pub fn powf64(a: f64, x: f64) -> f64; + + pub fn expf32(x: f32) -> f32; + pub fn expf64(x: f64) -> f64; + + pub fn exp2f32(x: f32) -> f32; + pub fn exp2f64(x: f64) -> f64; + + pub fn logf32(x: f32) -> f32; + pub fn logf64(x: f64) -> f64; + + pub fn log10f32(x: f32) -> f32; + pub fn log10f64(x: f64) -> f64; + + pub fn log2f32(x: f32) -> f32; + pub fn log2f64(x: f64) -> f64; + + pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; + pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; + + pub fn fabsf32(x: f32) -> f32; + pub fn fabsf64(x: f64) -> f64; + + pub fn floorf32(x: f32) -> f32; + pub fn floorf64(x: f64) -> f64; + + pub fn ceilf32(x: f32) -> f32; + pub fn ceilf64(x: f64) -> f64; + + pub fn truncf32(x: f32) -> f32; + pub fn truncf64(x: f64) -> f64; + + pub fn ctpop8(x: i8) -> i8; + pub fn ctpop16(x: i16) -> i16; + pub fn ctpop32(x: i32) -> i32; + pub fn ctpop64(x: i64) -> i64; + + pub fn ctlz8(x: i8) -> i8; + pub fn ctlz16(x: i16) -> i16; + pub fn ctlz32(x: i32) -> i32; + pub fn ctlz64(x: i64) -> i64; + + pub fn cttz8(x: i8) -> i8; + pub fn cttz16(x: i16) -> i16; + pub fn cttz32(x: i32) -> i32; + pub fn cttz64(x: i64) -> i64; + + pub fn bswap16(x: i16) -> i16; + pub fn bswap32(x: i32) -> i32; + pub fn bswap64(x: i64) -> i64; +} + diff --git a/src/libcore/unstable/weak_task.rs b/src/libcore/unstable/weak_task.rs new file mode 100644 index 00000000000..0e1181f43db --- /dev/null +++ b/src/libcore/unstable/weak_task.rs @@ -0,0 +1,207 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Weak tasks + +Weak tasks are a runtime feature for building global services that +do not keep the runtime alive. Normally the runtime exits when all +tasks exits, but if a task is weak then the runtime may exit while +it is running, sending a notification to the task that the runtime +is trying to shut down. +*/ + +use cell::Cell; +use comm::{GenericSmartChan, stream}; +use comm::{Port, Chan, SharedChan, GenericChan, GenericPort}; +use hashmap::linear::LinearMap; +use ops::Drop; +use option::{Some, None, swap_unwrap}; +use unstable::at_exit::at_exit; +use unstable::finally::Finally; +use unstable::global::global_data_clone_create; +use task::rt::{task_id, get_task_id}; +use task::{Task, task, spawn}; + +type ShutdownMsg = (); + +// FIXME #4729: This could be a PortOne but I've experienced bugginess +// with oneshot pipes and try_send +pub unsafe fn weaken_task(f: &fn(Port)) { + let service = global_data_clone_create(global_data_key, + create_global_service); + let (shutdown_port, shutdown_chan) = stream::(); + let shutdown_port = Cell(shutdown_port); + let task = get_task_id(); + // Expect the weak task service to be alive + assert service.try_send(RegisterWeakTask(task, shutdown_chan)); + unsafe { rust_dec_kernel_live_count(); } + do fn&() { + f(shutdown_port.take()) + }.finally || { + unsafe { rust_inc_kernel_live_count(); } + // Service my have already exited + service.send(UnregisterWeakTask(task)); + } +} + +type WeakTaskService = SharedChan; +type TaskHandle = task_id; + +fn global_data_key(_v: WeakTaskService) { } + +enum ServiceMsg { + RegisterWeakTask(TaskHandle, Chan), + UnregisterWeakTask(TaskHandle), + Shutdown +} + +fn create_global_service() -> ~WeakTaskService { + + debug!("creating global weak task service"); + let (port, chan) = stream::(); + let port = Cell(port); + let chan = SharedChan(chan); + let chan_clone = chan.clone(); + + do task().unlinked().spawn { + debug!("running global weak task service"); + let port = Cell(port.take()); + do fn&() { + let port = port.take(); + // The weak task service is itself a weak task + debug!("weakening the weak service task"); + unsafe { rust_dec_kernel_live_count(); } + run_weak_task_service(port); + }.finally { + debug!("unweakening the weak service task"); + unsafe { rust_inc_kernel_live_count(); } + } + } + + do at_exit { + debug!("shutting down weak task service"); + chan.send(Shutdown); + } + + return ~chan_clone; +} + +fn run_weak_task_service(port: Port) { + + let mut shutdown_map = LinearMap::new(); + + loop { + match port.recv() { + RegisterWeakTask(task, shutdown_chan) => { + let previously_unregistered = + shutdown_map.insert(task, shutdown_chan); + assert previously_unregistered; + } + UnregisterWeakTask(task) => { + match shutdown_map.pop(&task) { + Some(shutdown_chan) => { + // Oneshot pipes must send, even though + // nobody will receive this + shutdown_chan.send(()); + } + None => fail!() + } + } + Shutdown => break + } + } + + do shutdown_map.consume |_, shutdown_chan| { + // Weak task may have already exited + shutdown_chan.send(()); + } +} + +extern { + unsafe fn rust_inc_kernel_live_count(); + unsafe fn rust_dec_kernel_live_count(); +} + +#[test] +fn test_simple() { + let (port, chan) = stream(); + do spawn { + unsafe { + do weaken_task |_signal| { + } + } + chan.send(()); + } + port.recv(); +} + +#[test] +fn test_weak_weak() { + let (port, chan) = stream(); + do spawn { + unsafe { + do weaken_task |_signal| { + } + do weaken_task |_signal| { + } + } + chan.send(()); + } + port.recv(); +} + +#[test] +fn test_wait_for_signal() { + do spawn { + unsafe { + do weaken_task |signal| { + signal.recv(); + } + } + } +} + +#[test] +fn test_wait_for_signal_many() { + use uint; + for uint::range(0, 100) |_| { + do spawn { + unsafe { + do weaken_task |signal| { + signal.recv(); + } + } + } + } +} + +#[test] +fn test_select_stream_and_oneshot() { + use comm::select2i; + use either::{Left, Right}; + + let (port, chan) = stream(); + let (waitport, waitchan) = stream(); + do spawn { + unsafe { + do weaken_task |signal| { + match select2i(&port, &signal) { + Left(*) => (), + Right(*) => fail!() + } + } + } + waitchan.send(()); + } + chan.send(()); + waitport.recv(); +} + diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 4d28c769b18..0d1be03638a 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -22,7 +22,7 @@ use kinds::Copy; use libc; use libc::size_t; use option::{None, Option, Some}; -use private::intrinsics; +use unstable::intrinsics; use ptr; use ptr::addr_of; use sys; @@ -2008,7 +2008,7 @@ pub mod raw { use managed; use option::{None, Some}; use option; - use private::intrinsics; + use unstable::intrinsics; use ptr::addr_of; use ptr; use sys; @@ -2622,8 +2622,8 @@ mod tests { #[test] fn test_swap_remove_noncopyable() { // Tests that we don't accidentally run destructors twice. - let mut v = ~[::private::exclusive(()), ::private::exclusive(()), - ::private::exclusive(())]; + let mut v = ~[::unstable::exclusive(()), ::unstable::exclusive(()), + ::unstable::exclusive(())]; let mut _e = v.swap_remove(0); assert (len(v) == 2); _e = v.swap_remove(1); diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs index 69c5026cbd1..ea59d6a54c6 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -20,9 +20,9 @@ use core::cast; use core::cell::Cell; use core::pipes; use core::prelude::*; -use core::private::{SharedMutableState, shared_mutable_state}; -use core::private::{clone_shared_mutable_state}; -use core::private::{get_shared_mutable_state, get_shared_immutable_state}; +use core::unstable::{SharedMutableState, shared_mutable_state}; +use core::unstable::{clone_shared_mutable_state}; +use core::unstable::{get_shared_mutable_state, get_shared_immutable_state}; use core::ptr; use core::task; use core::util; diff --git a/src/libstd/sync.rs b/src/libstd/sync.rs index 39d3fd569a6..1289bc8e889 100644 --- a/src/libstd/sync.rs +++ b/src/libstd/sync.rs @@ -19,7 +19,7 @@ use core::cell::Cell; use core::option; use core::pipes; use core::prelude::*; -use core::private::{Exclusive, exclusive}; +use core::unstable::{Exclusive, exclusive}; use core::ptr; use core::task; use core::util; diff --git a/src/libstd/uv_global_loop.rs b/src/libstd/uv_global_loop.rs index 37d9b3221b2..52cfc078bac 100644 --- a/src/libstd/uv_global_loop.rs +++ b/src/libstd/uv_global_loop.rs @@ -18,9 +18,9 @@ use uv_iotask::{IoTask, spawn_iotask}; use core::either::{Left, Right}; use core::libc; use core::comm::{Port, Chan, SharedChan, select2i}; -use core::private::global::{global_data_clone_create, +use core::unstable::global::{global_data_clone_create, global_data_clone}; -use core::private::weak_task::weaken_task; +use core::unstable::weak_task::weaken_task; use core::str; use core::task::{task, SingleThreaded, spawn}; use core::task; diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index b8781130562..3861db28e1d 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -24,7 +24,7 @@ use ext::base::*; use ext::base; use ext::build; use ext::build::*; -use private::extfmt::ct::*; +use unstable::extfmt::ct::*; pub fn expand_syntax_ext(cx: ext_ctxt, sp: span, tts: ~[ast::token_tree]) -> base::MacResult { @@ -57,7 +57,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, -> @ast::expr { fn make_path_vec(cx: ext_ctxt, ident: @~str) -> ~[ast::ident] { let intr = cx.parse_sess().interner; - return ~[intr.intern(@~"private"), intr.intern(@~"extfmt"), + return ~[intr.intern(@~"unstable"), intr.intern(@~"extfmt"), intr.intern(@~"rt"), intr.intern(ident)]; } fn make_rt_path_expr(cx: ext_ctxt, sp: span, nm: @~str) -> @ast::expr { diff --git a/src/test/compile-fail/noncopyable-match-pattern.rs b/src/test/compile-fail/noncopyable-match-pattern.rs index 9f21d5a647a..d90e2f372a8 100644 --- a/src/test/compile-fail/noncopyable-match-pattern.rs +++ b/src/test/compile-fail/noncopyable-match-pattern.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let x = Some(private::exclusive(false)); + let x = Some(unstable::exclusive(false)); match x { Some(copy z) => { //~ ERROR copying a value of non-copyable type do z.with |b| { assert !*b; } diff --git a/src/test/run-pass/alt-ref-binding-in-guard-3256.rs b/src/test/run-pass/alt-ref-binding-in-guard-3256.rs index 4474aec3d2e..d9c348cf993 100644 --- a/src/test/run-pass/alt-ref-binding-in-guard-3256.rs +++ b/src/test/run-pass/alt-ref-binding-in-guard-3256.rs @@ -9,7 +9,7 @@ // except according to those terms. pub fn main() { - let x = Some(private::exclusive(true)); + let x = Some(unstable::exclusive(true)); match x { Some(ref z) if z.with(|b| *b) => { do z.with |b| { assert *b; } diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs index 5d400e98d41..86f23dd5210 100644 --- a/src/test/run-pass/foreign-call-no-runtime.rs +++ b/src/test/run-pass/foreign-call-no-runtime.rs @@ -1,4 +1,4 @@ -use core::private::run_in_bare_thread; +use core::unstable::run_in_bare_thread; extern { pub fn rust_dbg_call(cb: *u8, diff --git a/src/test/run-pass/type-use-i1-versus-i8.rs b/src/test/run-pass/type-use-i1-versus-i8.rs index d16b2e3e996..d180f6c7260 100644 --- a/src/test/run-pass/type-use-i1-versus-i8.rs +++ b/src/test/run-pass/type-use-i1-versus-i8.rs @@ -11,5 +11,5 @@ pub fn main() { let mut x: bool = false; // this line breaks it - private::intrinsics::move_val_init(&mut x, false); + unstable::intrinsics::move_val_init(&mut x, false); } -- cgit 1.4.1-3-g733a5 From 95bc9ea26df56b29f74583317ab080fdc7b99757 Mon Sep 17 00:00:00 2001 From: Jihyun Yu Date: Sat, 2 Mar 2013 12:57:05 +0900 Subject: Remove REC, change related tests/docs --- doc/rust.md | 109 +++------------------ doc/tutorial-borrowed-ptr.md | 11 ++- src/libcore/dvec.rs | 8 +- src/libcore/os.rs | 18 ++-- src/libcore/ptr.rs | 6 +- src/libstd/ebml.rs | 4 +- src/libstd/sync.rs | 4 +- src/libsyntax/parse/parser.rs | 16 ++- src/libsyntax/print/pprust.rs | 2 +- src/test/compile-fail/autoderef-full-lval.rs | 17 ++-- src/test/compile-fail/bad-record-pat-2.rs | 13 --- src/test/compile-fail/bad-record-pat.rs | 13 --- src/test/compile-fail/binop-add-tup-assign.rs | 13 --- src/test/compile-fail/binop-add-tup.rs | 13 --- src/test/compile-fail/break-outside-loop.rs | 7 +- src/test/compile-fail/fru-extra-field.rs | 21 ---- src/test/compile-fail/let-destruct-refutable.rs | 21 ---- src/test/compile-fail/nonscalar-cast.rs | 8 +- src/test/compile-fail/rec-expected.rs | 19 ---- src/test/compile-fail/rec-extend.rs | 18 ---- src/test/compile-fail/rec-missing-fields.rs | 19 ---- .../compile-fail/writing-through-read-alias.rs | 19 ---- src/test/compile-fail/writing-to-immutable-rec.rs | 12 --- src/test/run-pass/lint-structural-records.rs | 14 --- src/test/run-pass/uniq-cc-generic.rs | 4 +- 25 files changed, 74 insertions(+), 335 deletions(-) delete mode 100644 src/test/compile-fail/bad-record-pat-2.rs delete mode 100644 src/test/compile-fail/bad-record-pat.rs delete mode 100644 src/test/compile-fail/binop-add-tup-assign.rs delete mode 100644 src/test/compile-fail/binop-add-tup.rs delete mode 100644 src/test/compile-fail/fru-extra-field.rs delete mode 100644 src/test/compile-fail/let-destruct-refutable.rs delete mode 100644 src/test/compile-fail/rec-expected.rs delete mode 100644 src/test/compile-fail/rec-extend.rs delete mode 100644 src/test/compile-fail/rec-missing-fields.rs delete mode 100644 src/test/compile-fail/writing-through-read-alias.rs delete mode 100644 src/test/compile-fail/writing-to-immutable-rec.rs delete mode 100644 src/test/run-pass/lint-structural-records.rs (limited to 'src/libstd') diff --git a/doc/rust.md b/doc/rust.md index 13d897a00d2..e8018671fde 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1285,19 +1285,22 @@ An _implementation_ is an item that implements a [trait](#traits) for a specific Implementations are defined with the keyword `impl`. ~~~~ -# type Point = {x: float, y: float}; +# struct Point {x: float, y: float}; # type Surface = int; -# type BoundingBox = {x: float, y: float, width: float, height: float}; +# struct BoundingBox {x: float, y: float, width: float, height: float}; # trait Shape { fn draw(Surface); fn bounding_box() -> BoundingBox; } # fn do_draw_circle(s: Surface, c: Circle) { } -type Circle = {radius: float, center: Point}; +struct Circle { + radius: float, + center: Point, +} impl Shape for Circle { fn draw(s: Surface) { do_draw_circle(s, self); } fn bounding_box() -> BoundingBox { let r = self.radius; - {x: self.center.x - r, y: self.center.y - r, + BoundingBox{x: self.center.x - r, y: self.center.y - r, width: 2.0 * r, height: 2.0 * r} } } @@ -1637,38 +1640,6 @@ rec_expr : '{' ident ':' expr [ ".." expr ] '}' ~~~~~~~~ -> **Note:** In future versions of Rust, record expressions and [record types](#record-types) will be removed. - -A [_record_](#record-types) _expression_ is one or more comma-separated -name-value pairs enclosed by braces. A fieldname can be any identifier, -and is separated from its value expression by a -colon. To indicate that a field is mutable, the `mut` keyword is -written before its name. - -~~~~ -{x: 10f, y: 20f}; -{name: "Joe", age: 35u, score: 100_000}; -{ident: "X", mut count: 0u}; -~~~~ - -The order of the fields in a record expression is significant, and -determines the type of the resulting value. `{a: u8, b: u8}` and `{b: -u8, a: u8}` are two different fields. - -A record expression can terminate with the syntax `..` followed by an -expression to denote a functional update. The expression following -`..` (the base) must be of a record type that includes at least all the -fields mentioned in the record expression. A new record will be -created, of the same type as the base expression, with the given -values for the fields that were explicitly specified, and the values -in the base record for all other fields. The ordering of the fields in -such a record expression is not significant. - -~~~~ -let base = {x: 1, y: 2, z: 3}; -{y: 0, z: 10, .. base}; -~~~~ - ### Method-call expressions ~~~~~~~~{.ebnf .gram} @@ -1689,7 +1660,7 @@ field_expr : expr '.' ident A _field expression_ consists of an expression followed by a single dot and an identifier, when not immediately followed by a parenthesized expression-list (the latter is a [method call expression](#method-call-expressions)). -A field expression denotes a field of a [structure](#structure-types) or [record](#record-types). +A field expression denotes a field of a [structure](#structure-types). ~~~~~~~~ {.field} myrecord.myfield; @@ -1905,8 +1876,10 @@ An example of three different swap expressions: # let mut x = &mut [0]; # let mut a = &mut [0]; # let i = 0; -# let y = {mut z: 0}; -# let b = {mut c: 0}; +# struct S1 { z: int }; +# struct S2 { c: int }; +# let mut y = S1{z: 0}; +# let mut b = S2{c: 0}; x <-> a; x[i] <-> a[i]; @@ -2328,42 +2301,6 @@ match x { } ~~~~ -Records and structures can also be pattern-matched and their fields bound to variables. -When matching fields of a record, -the fields being matched are specified first, -then a placeholder (`_`) represents the remaining fields. - -~~~~ -# type options = {choose: bool, size: ~str}; -# type player = {player: ~str, stats: (), options: options}; -# fn load_stats() { } -# fn choose_player(r: &player) { } -# fn next_player() { } - -fn main() { - let r = { - player: ~"ralph", - stats: load_stats(), - options: { - choose: true, - size: ~"small" - } - }; - - match r { - {options: {choose: true, _}, _} => { - choose_player(&r) - } - {player: ref p, options: {size: ~"small", _}, _} => { - log(info, (copy *p) + ~" is small"); - } - _ => { - next_player(); - } - } -} -~~~~ - Patterns that bind variables default to binding to a copy of the matched value. This can be made explicit using the ```copy``` keyword, changed to bind to a borrowed pointer by using the ```ref``` keyword, or to a mutable borrowed pointer using ```ref mut```, or the value can be moved into @@ -2692,25 +2629,6 @@ let a: List = Cons(7, @Cons(13, @Nil)); ~~~~ -### Record types - -> **Note:** Records are not nominal types, thus do not directly support recursion, visibility control, -> out-of-order field initialization, or coherent trait implementation. -> Records are therefore deprecated and will be removed in future versions of Rust. -> [Structure types](#structure-types) should be used instead. - -The record type-constructor forms a new heterogeneous product of values. -Fields of a record type are accessed by name and are arranged in memory in the order specified by the record type. - -An example of a record type and its use: - -~~~~ -type Point = {x: int, y: int}; -let p: Point = {x: 10, y: 11}; -let px: int = p.x; -~~~~ - - ### Pointer types All pointers in Rust are explicit first-class values. @@ -3040,7 +2958,8 @@ Some operations (such as field selection) implicitly dereference boxes. An example of an _implicit dereference_ operation performed on box values: ~~~~~~~~ -let x = @{y: 10}; +struct Foo { y: int } +let x = @Foo{y: 10}; assert x.y == 10; ~~~~~~~~ diff --git a/doc/tutorial-borrowed-ptr.md b/doc/tutorial-borrowed-ptr.md index 0c1624706bf..e638579253f 100644 --- a/doc/tutorial-borrowed-ptr.md +++ b/doc/tutorial-borrowed-ptr.md @@ -166,9 +166,9 @@ operator. For example, I could write: # struct Point {x: float, y: float} // as before # struct Size {w: float, h: float} // as before # struct Rectangle {origin: Point, size: Size} -# let rect_stack = &{origin: Point {x: 1f, y: 2f}, size: Size {w: 3f, h: 4f}}; -# let rect_managed = @{origin: Point {x: 3f, y: 4f}, size: Size {w: 3f, h: 4f}}; -# let rect_unique = ~{origin: Point {x: 5f, y: 6f}, size: Size {w: 3f, h: 4f}}; +# let rect_stack = &Rectangle {origin: Point {x: 1f, y: 2f}, size: Size {w: 3f, h: 4f}}; +# let rect_managed = @Rectangle {origin: Point {x: 3f, y: 4f}, size: Size {w: 3f, h: 4f}}; +# let rect_unique = ~Rectangle {origin: Point {x: 5f, y: 6f}, size: Size {w: 3f, h: 4f}}; # fn compute_distance(p1: &Point, p2: &Point) -> float { 0f } compute_distance(&rect_stack.origin, &rect_managed.origin); ~~~ @@ -274,13 +274,14 @@ the following function is legal: ~~~ # fn some_condition() -> bool { true } +# struct Foo { f: int } fn example3() -> int { - let mut x = ~{f: 3}; + let mut x = ~Foo {f: 3}; if some_condition() { let y = &x.f; // -+ L return *y; // | } // -+ - x = ~{f: 4}; + x = ~Foo {f: 4}; ... # return 0; } diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs index 1fef4ad42f1..7197de36404 100644 --- a/src/libcore/dvec.rs +++ b/src/libcore/dvec.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -62,17 +62,17 @@ pub struct DVec { /// Creates a new, empty dvec pub pure fn DVec() -> DVec { - DVec {mut data: ~[]} + DVec {data: ~[]} } /// Creates a new dvec with a single element pub pure fn from_elem(e: A) -> DVec { - DVec {mut data: ~[e]} + DVec {data: ~[e]} } /// Creates a new dvec with the contents of a vector pub pure fn from_vec(v: ~[A]) -> DVec { - DVec {mut data: v} + DVec {data: v} } /// Consumes the vector and returns its contents diff --git a/src/libcore/os.rs b/src/libcore/os.rs index 8b6d27496d9..09588f3280d 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -322,8 +322,8 @@ pub struct Pipe { mut in: c_int, mut out: c_int } #[cfg(unix)] pub fn pipe() -> Pipe { unsafe { - let mut fds = Pipe {mut in: 0 as c_int, - mut out: 0 as c_int }; + let mut fds = Pipe {in: 0 as c_int, + out: 0 as c_int }; assert (libc::pipe(&mut fds.in) == (0 as c_int)); return Pipe {in: fds.in, out: fds.out}; } @@ -339,8 +339,8 @@ pub fn pipe() -> Pipe { // fully understand. Here we explicitly make the pipe non-inheritable, // which means to pass it to a subprocess they need to be duplicated // first, as in rust_run_program. - let mut fds = Pipe { mut in: 0 as c_int, - mut out: 0 as c_int }; + let mut fds = Pipe {in: 0 as c_int, + out: 0 as c_int }; let res = libc::pipe(&mut fds.in, 1024 as c_uint, (libc::O_BINARY | libc::O_NOINHERIT) as c_int); assert (res == 0 as c_int); @@ -566,13 +566,17 @@ pub fn path_exists(p: &Path) -> bool { * * If the given path is relative, return it prepended with the current working * directory. If the given path is already an absolute path, return it - * as is. This is a shortcut for calling os::getcwd().unsafe_join(p) + * as is. */ // NB: this is here rather than in path because it is a form of environment // querying; what it does depends on the process working directory, not just // the input paths. pub fn make_absolute(p: &Path) -> Path { - getcwd().unsafe_join(p) + if p.is_absolute { + copy *p + } else { + getcwd().push_many(p.components) + } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 2266c2511f8..ca5f6671130 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -300,7 +300,7 @@ impl Ord for &const T { pub fn test() { unsafe { struct Pair {mut fst: int, mut snd: int}; - let mut p = Pair {mut fst: 10, mut snd: 20}; + let mut p = Pair {fst: 10, snd: 20}; let pptr: *mut Pair = &mut p; let iptr: *mut int = cast::reinterpret_cast(&pptr); assert (*iptr == 10);; @@ -308,7 +308,7 @@ pub fn test() { assert (*iptr == 30); assert (p.fst == 30);; - *pptr = Pair {mut fst: 50, mut snd: 60}; + *pptr = Pair {fst: 50, snd: 60}; assert (*iptr == 50); assert (p.fst == 50); assert (p.snd == 60); diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 7d04f676079..cbe0580a609 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -219,7 +219,7 @@ pub mod reader { } pub fn Decoder(d: Doc) -> Decoder { - Decoder { mut parent: d, mut pos: d.start } + Decoder { parent: d, pos: d.start } } priv impl Decoder { diff --git a/src/libstd/sync.rs b/src/libstd/sync.rs index 39d3fd569a6..51ff69da98d 100644 --- a/src/libstd/sync.rs +++ b/src/libstd/sync.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -87,7 +87,7 @@ enum Sem = Exclusive>; #[doc(hidden)] fn new_sem(count: int, q: Q) -> Sem { Sem(exclusive(SemInner { - mut count: count, waiters: new_waitqueue(), blocked: q })) + count: count, waiters: new_waitqueue(), blocked: q })) } #[doc(hidden)] fn new_sem_and_signal(count: int, num_condvars: uint) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6294243d486..444f1201fc3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -1093,15 +1093,10 @@ pub impl Parser { self.mk_expr(lo, hi, expr_tup(es)) } } else if *self.token == token::LBRACE { - if self.looking_at_record_literal() { - ex = self.parse_record_literal(); - hi = self.span.hi; - } else { - self.bump(); - let blk = self.parse_block_tail(lo, default_blk); - return self.mk_expr(blk.span.lo, blk.span.hi, - expr_block(blk)); - } + self.bump(); + let blk = self.parse_block_tail(lo, default_blk); + return self.mk_expr(blk.span.lo, blk.span.hi, + expr_block(blk)); } else if token::is_bar(*self.token) { return self.parse_lambda_expr(); } else if self.eat_keyword(~"if") { @@ -1223,6 +1218,7 @@ pub impl Parser { self.bump(); let mut fields = ~[]; let mut base = None; + fields.push(self.parse_field(token::COLON)); while *self.token != token::RBRACE { if self.try_parse_obsolete_with() { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0f161a444bd..ac21e27bb8b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1213,7 +1213,7 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) { print_expr(s, expr); end(s); } - _ => word(s.s, ~",") + _ => (word(s.s, ~",")) } word(s.s, ~"}"); } diff --git a/src/test/compile-fail/autoderef-full-lval.rs b/src/test/compile-fail/autoderef-full-lval.rs index fec5c994de7..cbbf484ad55 100644 --- a/src/test/compile-fail/autoderef-full-lval.rs +++ b/src/test/compile-fail/autoderef-full-lval.rs @@ -9,18 +9,23 @@ // except according to those terms. // error-pattern: mismatched types -type clam = {x: @int, y: @int}; +struct clam { + x: @int, + y: @int, +} -type fish = {a: @int}; +struct fish { + a: @int, +} fn main() { - let a: clam = {x: @1, y: @2}; - let b: clam = {x: @10, y: @20}; + let a: clam = clam{x: @1, y: @2}; + let b: clam = clam{x: @10, y: @20}; let z: int = a.x + b.y; log(debug, z); assert (z == 21); - let forty: fish = {a: @40}; - let two: fish = {a: @2}; + let forty: fish = fish{a: @40}; + let two: fish = fish{a: @2}; let answer: int = forty.a + two.a; log(debug, answer); assert (answer == 42); diff --git a/src/test/compile-fail/bad-record-pat-2.rs b/src/test/compile-fail/bad-record-pat-2.rs deleted file mode 100644 index 3707dc923c8..00000000000 --- a/src/test/compile-fail/bad-record-pat-2.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:did not expect a record with a field `q` - -fn main() { match {x: 1, y: 2} { {x: x, q: q} => { } } } diff --git a/src/test/compile-fail/bad-record-pat.rs b/src/test/compile-fail/bad-record-pat.rs deleted file mode 100644 index a7ce8e2ef5c..00000000000 --- a/src/test/compile-fail/bad-record-pat.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:expected a record with 2 fields, found one with 1 - -fn main() { match {x: 1, y: 2} { {x: x} => { } } } diff --git a/src/test/compile-fail/binop-add-tup-assign.rs b/src/test/compile-fail/binop-add-tup-assign.rs deleted file mode 100644 index 3e560c8eaf6..00000000000 --- a/src/test/compile-fail/binop-add-tup-assign.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:+ cannot be applied to type `{x: bool}` - -fn main() { let x = {x: true}; x += {x: false}; } diff --git a/src/test/compile-fail/binop-add-tup.rs b/src/test/compile-fail/binop-add-tup.rs deleted file mode 100644 index 660e951c847..00000000000 --- a/src/test/compile-fail/binop-add-tup.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:+ cannot be applied to type `{x: bool}` - -fn main() { let x = {x: true} + {x: false}; } diff --git a/src/test/compile-fail/break-outside-loop.rs b/src/test/compile-fail/break-outside-loop.rs index c36d60fdac1..b3154c9742a 100644 --- a/src/test/compile-fail/break-outside-loop.rs +++ b/src/test/compile-fail/break-outside-loop.rs @@ -9,9 +9,14 @@ // except according to those terms. // error-pattern:`break` outside of loop + +struct Foo { + t: ~str +} + fn main() { let pth = break; - let rs: {t: ~str} = {t: pth}; + let rs: Foo = Foo{t: pth}; } diff --git a/src/test/compile-fail/fru-extra-field.rs b/src/test/compile-fail/fru-extra-field.rs deleted file mode 100644 index 64d76d6fb74..00000000000 --- a/src/test/compile-fail/fru-extra-field.rs +++ /dev/null @@ -1,21 +0,0 @@ -// -*- rust -*- -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -// error-pattern: record - -type point = {x: int, y: int}; - -fn main() { - let origin: point = {x: 0, y: 0}; - - let origin3d: point = {z: 0,.. origin}; -} diff --git a/src/test/compile-fail/let-destruct-refutable.rs b/src/test/compile-fail/let-destruct-refutable.rs deleted file mode 100644 index 9bd9db20779..00000000000 --- a/src/test/compile-fail/let-destruct-refutable.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:refutable pattern -// error-pattern:refutable pattern - -enum xx { xx(int), yy, } - -fn main() { - let @{x: xx(x), y: y} = @{x: xx(10), y: 20}; - assert (x + y == 30); - - let [a, b] = ~[1, 2]; -} diff --git a/src/test/compile-fail/nonscalar-cast.rs b/src/test/compile-fail/nonscalar-cast.rs index 54c0f6ca07f..d84775d02ac 100644 --- a/src/test/compile-fail/nonscalar-cast.rs +++ b/src/test/compile-fail/nonscalar-cast.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -10,6 +10,10 @@ // error-pattern:non-scalar cast +struct foo { + x:int +} + fn main() { - log(debug, { x: 1 } as int); + log(debug, foo{ x: 1 } as int); } diff --git a/src/test/compile-fail/rec-expected.rs b/src/test/compile-fail/rec-expected.rs deleted file mode 100644 index 962201aa9b9..00000000000 --- a/src/test/compile-fail/rec-expected.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -type foo = {a: int}; -type bar = {b: int}; - -fn want_foo(f: foo) {} -fn have_bar(b: bar) { - want_foo(b); //~ ERROR expected a record with field `a` -} - -fn main() {} diff --git a/src/test/compile-fail/rec-extend.rs b/src/test/compile-fail/rec-extend.rs deleted file mode 100644 index aa4f9d0501a..00000000000 --- a/src/test/compile-fail/rec-extend.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:expected `int` but found `bool` - -fn main() { - - let a = {foo: 0i}; - - let b = {foo: true,.. a}; -} diff --git a/src/test/compile-fail/rec-missing-fields.rs b/src/test/compile-fail/rec-missing-fields.rs deleted file mode 100644 index 2ad2f00ee26..00000000000 --- a/src/test/compile-fail/rec-missing-fields.rs +++ /dev/null @@ -1,19 +0,0 @@ -// -*- rust -*- -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -// error-pattern: mismatched types - -// Issue #51. - -type point = {x: int, y: int}; - -fn main() { let p: point = {x: 10}; log(debug, p.y); } diff --git a/src/test/compile-fail/writing-through-read-alias.rs b/src/test/compile-fail/writing-through-read-alias.rs deleted file mode 100644 index 3b2591c3bfa..00000000000 --- a/src/test/compile-fail/writing-through-read-alias.rs +++ /dev/null @@ -1,19 +0,0 @@ -// -*- rust -*- -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -// error-pattern:assigning to immutable field - -type point = {x: int, y: int, z: int}; - -fn f(p: point) { p.x = 13; } - -fn main() { let x: point = {x: 10, y: 11, z: 12}; f(x); } diff --git a/src/test/compile-fail/writing-to-immutable-rec.rs b/src/test/compile-fail/writing-to-immutable-rec.rs deleted file mode 100644 index 4cc9dae7deb..00000000000 --- a/src/test/compile-fail/writing-to-immutable-rec.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: assigning to immutable field -fn main() { let r: {x: int} = {x: 1}; r.x = 6; } diff --git a/src/test/run-pass/lint-structural-records.rs b/src/test/run-pass/lint-structural-records.rs deleted file mode 100644 index e5107ba187c..00000000000 --- a/src/test/run-pass/lint-structural-records.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[warn(structural_records)]; -pub fn main() { - let _foo = {x:5}; -} diff --git a/src/test/run-pass/uniq-cc-generic.rs b/src/test/run-pass/uniq-cc-generic.rs index 1b602ab7d30..def49ef0f8c 100644 --- a/src/test/run-pass/uniq-cc-generic.rs +++ b/src/test/run-pass/uniq-cc-generic.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -24,7 +24,7 @@ fn make_uniq_closure(a: A) -> fn~() -> uint { fn empty_pointy() -> @mut Pointy { return @mut Pointy { - mut a : none, + a : none, d : make_uniq_closure(~"hi") } } -- cgit 1.4.1-3-g733a5 From 035233a25907af8206d254878e7e04048fcac95e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 2 Mar 2013 13:27:29 -0500 Subject: treemap: reimplement using TotalOrd --- src/libcore/prelude.rs | 2 +- src/libstd/treemap.rs | 167 +++++++++++++++++++++++++------------------------ 2 files changed, 87 insertions(+), 82 deletions(-) (limited to 'src/libstd') diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index a7b4500c3e3..186253761fa 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -27,7 +27,7 @@ pub use clone::Clone; pub use cmp::{Eq, Ord, TotalOrd, Ordering, Less, Equal, Greater}; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; -pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter}; +pub use iter::{BaseIter, ReverseIter, ExtendedIter, EqIter, CopyableIter}; pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times}; pub use num::NumCast; pub use path::GenericPath; diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 88e4ade4b82..a093351c4a7 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -10,12 +10,8 @@ //! An ordered map and set implemented as self-balancing binary search //! trees. The only requirement for the types is that the key implements -//! `Ord`, and that the `lt` method provides a total ordering. +//! `TotalOrd`. -use core::container::{Container, Mutable, Map, Set}; -use core::cmp::{Eq, Ord}; -use core::iter::{BaseIter, ReverseIter}; -use core::option::{Option, Some, None}; use core::prelude::*; // This is implemented as an AA tree, which is a simplified variation of @@ -39,7 +35,7 @@ pub struct TreeMap { priv length: uint } -impl Eq for TreeMap { +impl Eq for TreeMap { pure fn eq(&self, other: &TreeMap) -> bool { if self.len() != other.len() { false @@ -61,7 +57,8 @@ impl Eq for TreeMap { } // Lexicographical comparison -pure fn lt(a: &TreeMap, b: &TreeMap) -> bool { +pure fn lt(a: &TreeMap, + b: &TreeMap) -> bool { let mut x = a.iter(); let mut y = b.iter(); @@ -78,7 +75,7 @@ pure fn lt(a: &TreeMap, b: &TreeMap) -> bool { return a_len < b_len; } -impl Ord for TreeMap { +impl Ord for TreeMap { #[inline(always)] pure fn lt(&self, other: &TreeMap) -> bool { lt(self, other) @@ -97,7 +94,7 @@ impl Ord for TreeMap { } } -impl BaseIter<(&K, &V)> for TreeMap { +impl BaseIter<(&K, &V)> for TreeMap { /// Visit all key-value pairs in order pure fn each(&self, f: fn(&(&self/K, &self/V)) -> bool) { each(&self.root, f) @@ -105,14 +102,14 @@ impl BaseIter<(&K, &V)> for TreeMap { pure fn size_hint(&self) -> Option { Some(self.len()) } } -impl ReverseIter<(&K, &V)> for TreeMap { +impl ReverseIter<(&K, &V)> for TreeMap { /// Visit all key-value pairs in reverse order pure fn each_reverse(&self, f: fn(&(&self/K, &self/V)) -> bool) { each_reverse(&self.root, f); } } -impl Container for TreeMap { +impl Container for TreeMap { /// Return the number of elements in the map pure fn len(&self) -> uint { self.length } @@ -120,7 +117,7 @@ impl Container for TreeMap { pure fn is_empty(&self) -> bool { self.root.is_none() } } -impl Mutable for TreeMap { +impl Mutable for TreeMap { /// Clear the map, removing all key-value pairs. fn clear(&mut self) { self.root = None; @@ -128,7 +125,7 @@ impl Mutable for TreeMap { } } -impl Map for TreeMap { +impl Map for TreeMap { /// Return true if the map contains a value for the specified key pure fn contains_key(&self, key: &K) -> bool { self.find(key).is_some() @@ -146,12 +143,10 @@ impl Map for TreeMap { loop { match *current { Some(ref r) => { - if *key < r.key { - current = &r.left; - } else if r.key < *key { - current = &r.right; - } else { - return Some(&r.value); + match key.cmp(&r.key) { + Less => current = &r.left, + Greater => current = &r.right, + Equal => return Some(&r.value) } } None => return None @@ -177,7 +172,7 @@ impl Map for TreeMap { } } -pub impl TreeMap { +pub impl TreeMap { /// Create an empty TreeMap static pure fn new() -> TreeMap { TreeMap{root: None, length: 0} } @@ -207,7 +202,7 @@ pub struct TreeMapIterator { /// Advance the iterator to the next node (in order) and return a /// tuple with a reference to the key and value. If there are no /// more nodes, return `None`. -pub fn map_next(iter: &mut TreeMapIterator/&r) +pub fn map_next(iter: &mut TreeMapIterator/&r) -> Option<(&r/K, &r/V)> { while !iter.stack.is_empty() || iter.node.is_some() { match *iter.node { @@ -226,8 +221,8 @@ pub fn map_next(iter: &mut TreeMapIterator/&r) } /// Advance the iterator through the map -pub fn map_advance(iter: &mut TreeMapIterator/&r, - f: fn((&r/K, &r/V)) -> bool) { +pub fn map_advance(iter: &mut TreeMapIterator/&r, + f: fn((&r/K, &r/V)) -> bool) { loop { match map_next(iter) { Some(x) => { @@ -242,25 +237,25 @@ pub struct TreeSet { priv map: TreeMap } -impl BaseIter for TreeSet { +impl BaseIter for TreeSet { /// Visit all values in order pure fn each(&self, f: fn(&T) -> bool) { self.map.each_key(f) } pure fn size_hint(&self) -> Option { Some(self.len()) } } -impl ReverseIter for TreeSet { +impl ReverseIter for TreeSet { /// Visit all values in reverse order pure fn each_reverse(&self, f: fn(&T) -> bool) { self.map.each_key_reverse(f) } } -impl Eq for TreeSet { +impl Eq for TreeSet { pure fn eq(&self, other: &TreeSet) -> bool { self.map == other.map } pure fn ne(&self, other: &TreeSet) -> bool { self.map != other.map } } -impl Ord for TreeSet { +impl Ord for TreeSet { #[inline(always)] pure fn lt(&self, other: &TreeSet) -> bool { self.map < other.map } #[inline(always)] @@ -271,7 +266,7 @@ impl Ord for TreeSet { pure fn gt(&self, other: &TreeSet) -> bool { self.map > other.map } } -impl Container for TreeSet { +impl Container for TreeSet { /// Return the number of elements in the set pure fn len(&self) -> uint { self.map.len() } @@ -279,12 +274,12 @@ impl Container for TreeSet { pure fn is_empty(&self) -> bool { self.map.is_empty() } } -impl Mutable for TreeSet { +impl Mutable for TreeSet { /// Clear the set, removing all values. fn clear(&mut self) { self.map.clear() } } -impl Set for TreeSet { +impl Set for TreeSet { /// Return true if the set contains a value pure fn contains(&self, value: &T) -> bool { self.map.contains_key(value) @@ -309,12 +304,10 @@ impl Set for TreeSet { while a.is_some() && b.is_some() { let a1 = a.unwrap(); let b1 = b.unwrap(); - if a1 < b1 { - a = set_next(&mut x); - } else if b1 < a1 { - b = set_next(&mut y); - } else { - return false; + match a1.cmp(b1) { + Less => a = set_next(&mut x), + Greater => b = set_next(&mut y), + Equal => return false } } } @@ -341,13 +334,12 @@ impl Set for TreeSet { let a1 = a.unwrap(); let b1 = b.unwrap(); - if b1 < a1 { - return false + match a1.cmp(b1) { + Less => (), + Greater => return false, + Equal => b = set_next(&mut y), } - if !(a1 < b1) { - b = set_next(&mut y); - } a = set_next(&mut x); } } @@ -373,11 +365,13 @@ impl Set for TreeSet { let a1 = a.unwrap(); let b1 = b.unwrap(); - if a1 < b1 { + let cmp = a1.cmp(b1); + + if cmp == Less { if !f(a1) { return } a = set_next(&mut x); } else { - if !(b1 < a1) { a = set_next(&mut x) } + if cmp == Equal { a = set_next(&mut x) } b = set_next(&mut y); } } @@ -404,11 +398,13 @@ impl Set for TreeSet { let a1 = a.unwrap(); let b1 = b.unwrap(); - if a1 < b1 { + let cmp = a1.cmp(b1); + + if cmp == Less { if !f(a1) { return } a = set_next(&mut x); } else { - if b1 < a1 { + if cmp == Greater { if !f(b1) { return } } else { a = set_next(&mut x); @@ -434,10 +430,13 @@ impl Set for TreeSet { while a.is_some() && b.is_some() { let a1 = a.unwrap(); let b1 = b.unwrap(); - if a1 < b1 { + + let cmp = a1.cmp(b1); + + if cmp == Less { a = set_next(&mut x); } else { - if !(b1 < a1) { + if cmp == Equal { if !f(a1) { return } } b = set_next(&mut y); @@ -465,12 +464,14 @@ impl Set for TreeSet { let a1 = a.unwrap(); let b1 = b.unwrap(); - if b1 < a1 { + let cmp = a1.cmp(b1); + + if cmp == Greater { if !f(b1) { return } b = set_next(&mut y); } else { if !f(a1) { return } - if !(a1 < b1) { + if cmp == Equal { b = set_next(&mut y); } a = set_next(&mut x); @@ -480,7 +481,7 @@ impl Set for TreeSet { } } -pub impl TreeSet { +pub impl TreeSet { /// Create an empty TreeSet static pure fn new() -> TreeSet { TreeSet{map: TreeMap::new()} } @@ -498,12 +499,12 @@ pub struct TreeSetIterator { /// Advance the iterator to the next node (in order). If this iterator is /// finished, does nothing. -pub fn set_next(iter: &mut TreeSetIterator/&r) -> Option<&r/T> { +pub fn set_next(iter: &mut TreeSetIterator/&r) -> Option<&r/T> { do map_next(&mut iter.iter).map |&(value, _)| { value } } /// Advance the iterator through the set -fn set_advance(iter: &mut TreeSetIterator/&r, +fn set_advance(iter: &mut TreeSetIterator/&r, f: fn(&r/T) -> bool) { do map_advance(&mut iter.iter) |(k, _)| { f(k) } } @@ -518,14 +519,14 @@ struct TreeNode { level: uint } -pub impl TreeNode { +pub impl TreeNode { #[inline(always)] static pure fn new(key: K, value: V) -> TreeNode { TreeNode{key: key, value: value, left: None, right: None, level: 1} } } -pure fn each(node: &r/Option<~TreeNode>, +pure fn each(node: &r/Option<~TreeNode>, f: fn(&(&r/K, &r/V)) -> bool) { do node.iter |x| { each(&x.left, f); @@ -533,7 +534,7 @@ pure fn each(node: &r/Option<~TreeNode>, } } -pure fn each_reverse(node: &r/Option<~TreeNode>, +pure fn each_reverse(node: &r/Option<~TreeNode>, f: fn(&(&r/K, &r/V)) -> bool) { do node.iter |x| { each_reverse(&x.right, f); @@ -542,7 +543,7 @@ pure fn each_reverse(node: &r/Option<~TreeNode>, } // Remove left horizontal link by rotating right -fn skew(node: &mut ~TreeNode) { +fn skew(node: &mut ~TreeNode) { if node.left.map_default(false, |x| x.level == node.level) { let mut save = node.left.swap_unwrap(); node.left <-> save.right; // save.right now None @@ -553,7 +554,7 @@ fn skew(node: &mut ~TreeNode) { // Remove dual horizontal link by rotating left and increasing level of // the parent -fn split(node: &mut ~TreeNode) { +fn split(node: &mut ~TreeNode) { if node.right.map_default(false, |x| x.right.map_default(false, |y| y.level == node.level)) { let mut save = node.right.swap_unwrap(); @@ -564,24 +565,28 @@ fn split(node: &mut ~TreeNode) { } } -fn insert(node: &mut Option<~TreeNode>, key: K, - value: V) -> bool { +fn insert(node: &mut Option<~TreeNode>, key: K, + value: V) -> bool { match *node { Some(ref mut save) => { - if key < save.key { + match key.cmp(&save.key) { + Less => { let inserted = insert(&mut save.left, key, value); skew(save); split(save); inserted - } else if save.key < key { + } + Greater => { let inserted = insert(&mut save.right, key, value); skew(save); split(save); inserted - } else { + } + Equal => { save.key = key; save.value = value; false + } } } None => { @@ -591,8 +596,9 @@ fn insert(node: &mut Option<~TreeNode>, key: K, } } -fn remove(node: &mut Option<~TreeNode>, key: &K) -> bool { - fn heir_swap(node: &mut ~TreeNode, +fn remove(node: &mut Option<~TreeNode>, + key: &K) -> bool { + fn heir_swap(node: &mut ~TreeNode, child: &mut Option<~TreeNode>) { // *could* be done without recursion, but it won't borrow check do child.mutate |mut child| { @@ -611,11 +617,10 @@ fn remove(node: &mut Option<~TreeNode>, key: &K) -> bool { return false // bottom of tree } Some(ref mut save) => { - let (removed, this) = if save.key < *key { - (remove(&mut save.right, key), false) - } else if *key < save.key { - (remove(&mut save.left, key), false) - } else { + let (removed, this) = match key.cmp(&save.key) { + Less => (remove(&mut save.left, key), false), + Greater => (remove(&mut save.right, key), false), + Equal => { if save.left.is_some() { if save.right.is_some() { let mut left = save.left.swap_unwrap(); @@ -637,6 +642,7 @@ fn remove(node: &mut Option<~TreeNode>, key: &K) -> bool { } else { (true, true) } + } }; if !this { @@ -682,12 +688,9 @@ fn remove(node: &mut Option<~TreeNode>, key: &K) -> bool { #[cfg(test)] mod test_treemap { + use core::prelude::*; use super::*; - use core::cmp::{Ord, Eq}; - use core::option::{Some, Option, None}; use core::rand; - use core::str; - use core::vec; #[test] fn find_empty() { @@ -742,7 +745,8 @@ mod test_treemap { assert m.find(&k1) == Some(&v1); } - fn check_equal(ctrl: &[(K, V)], map: &TreeMap) { + fn check_equal(ctrl: &[(K, V)], + map: &TreeMap) { assert ctrl.is_empty() == map.is_empty(); for ctrl.each |x| { let &(k, v) = x; @@ -762,11 +766,11 @@ mod test_treemap { } } - fn check_left(node: &Option<~TreeNode>, - parent: &~TreeNode) { + fn check_left(node: &Option<~TreeNode>, + parent: &~TreeNode) { match *node { Some(ref r) => { - assert r.key < parent.key; + assert r.key.cmp(&parent.key) == Less; assert r.level == parent.level - 1; // left is black check_left(&r.left, r); check_right(&r.right, r, false); @@ -775,11 +779,12 @@ mod test_treemap { } } - fn check_right(node: &Option<~TreeNode>, - parent: &~TreeNode, parent_red: bool) { + fn check_right(node: &Option<~TreeNode>, + parent: &~TreeNode, + parent_red: bool) { match *node { Some(ref r) => { - assert r.key > parent.key; + assert r.key.cmp(&parent.key) == Greater; let red = r.level == parent.level; if parent_red { assert !red } // no dual horizontal links assert red || r.level == parent.level - 1; // right red or black @@ -790,7 +795,7 @@ mod test_treemap { } } - fn check_structure(map: &TreeMap) { + fn check_structure(map: &TreeMap) { match map.root { Some(ref r) => { check_left(&r.left, r); -- cgit 1.4.1-3-g733a5