LIBSYNTAX_CRATE := $(S)src/libsyntax/syntax.rs
LIBSYNTAX_INPUTS := $(wildcard $(addprefix $(S)src/libsyntax/, \
- *.rs */*.rs */*/*.rs))
+ *.rs */*.rs */*/*.rs */*/*/*.rs))
DRIVER_CRATE := $(S)src/driver/driver.rs
This function can only be called from an `unsafe` block or another `unsafe` function.
+# Accessing foreign globals
+
+Foreign APIs often export a global variable which could do something like track
+global state. In order to access these variables, you declare them in `extern`
+blocks with the `static` keyword:
+
+~~~{.xfail-test}
+use std::libc;
+
+#[link_args = "-lreadline"]
+extern {
+ static rl_readline_version: libc::c_int;
+}
+
+fn main() {
+ println(fmt!("You have readline version %d installed.",
+ rl_readline_version as int));
+}
+~~~
+
+Alternatively, you may need to alter global state provided by a foreign
+interface. To do this, statics can be declared with `mut` so rust can mutate
+them.
+
+~~~{.xfail-test}
+use std::libc;
+use std::ptr;
+
+#[link_args = "-lreadline"]
+extern {
+ static mut rl_prompt: *libc::c_char;
+}
+
+fn main() {
+ do "[my-awesome-shell] $".as_c_str |buf| {
+ unsafe { rl_prompt = buf; }
+ // get a line, process it
+ unsafe { rl_prompt = ptr::null(); }
+ }
+}
+~~~
+
# Foreign calling conventions
Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when
All tasks are, by default, _linked_ to each other. That means that the fates
of all tasks are intertwined: if one fails, so do all the others.
-~~~
+~~~{.xfail-test .linked-failure}
# use std::task::spawn;
# use std::task;
# fn do_some_work() { loop { task::yield() } }
field (representing a successful result) or an `Err` result (representing
termination with an error).
-~~~
+~~~{.xfail-test .linked-failure}
# use std::task;
# fn some_condition() -> bool { false }
# fn calculate_result() -> int { 0 }
By default, task failure is _bidirectionally linked_, which means that if
either task fails, it kills the other one.
-~~~
+~~~{.xfail-test .linked-failure}
# use std::task;
-# fn sleep_forever() { loop { task::yield() } }
+# use std::comm::oneshot;
+# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }
# do task::try {
do spawn {
do spawn {
internally, with additional logic to wait for the child task to finish
before returning. Hence:
-~~~
+~~~{.xfail-test .linked-failure}
# use std::comm::{stream, Chan, Port};
+# use std::comm::oneshot;
# use std::task::{spawn, try};
# use std::task;
-# fn sleep_forever() { loop { task::yield() } }
+# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }
# do task::try {
let (receiver, sender): (Port<int>, Chan<int>) = stream();
do spawn { // Bidirectionally linked
Supervised task failure propagates across multiple generations even if
an intermediate generation has already exited:
-~~~
+~~~{.xfail-test .linked-failure}
# use std::task;
-# fn sleep_forever() { loop { task::yield() } }
-# fn wait_for_a_while() { do 1000.times { task::yield() } }
+# use std::comm::oneshot;
+# fn sleep_forever() { loop { let (p, c) = oneshot::<()>(); p.recv(); } }
+# fn wait_for_a_while() { for _ in range(0, 1000u) { task::yield() } }
# do task::try::<int> {
do task::spawn_supervised {
do task::spawn_supervised {
Finally, tasks can be configured to not propagate failure to each
other at all, using `task::spawn_unlinked` for _isolated failure_.
-~~~
+~~~{.xfail-test .linked-failure}
# use std::task;
# fn random() -> uint { 100 }
-# fn sleep_for(i: uint) { do i.times { task::yield() } }
+# fn sleep_for(i: uint) { for _ in range(0, i) { task::yield() } }
# do task::try::<()> {
let (time1, time2) = (random(), random());
do task::spawn_unlinked {
the string in response. The child terminates when it receives `0`.
Here is the function that implements the child task:
-~~~~
+~~~{.xfail-test .linked-failure}
# use extra::comm::DuplexStream;
# use std::uint;
fn stringifier(channel: &DuplexStream<~str, uint>) {
Here is the code for the parent task:
-~~~~
+~~~{.xfail-test .linked-failure}
# use std::task::spawn;
# use std::uint;
# use extra::comm::DuplexStream;
impl Drop for TimeBomb {
fn drop(&self) {
- do self.explosivity.times {
+ for _ in range(0, self.explosivity) {
println("blam!");
}
}
}
impl Farm {
- priv fn feed_chickens(&self) { ... }
- priv fn feed_cows(&self) { ... }
+ fn feed_chickens(&self) { ... }
+ fn feed_cows(&self) { ... }
pub fn add_chicken(&self, c: Chicken) { ... }
}
compile_lib_path: getopts::opt_str(matches, "compile-lib-path"),
run_lib_path: getopts::opt_str(matches, "run-lib-path"),
rustc_path: opt_path(matches, "rustc-path"),
- clang_path: getopts::opt_maybe_str(matches, "clang-path").map(|s| Path(*s)),
- llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map(|s| Path(*s)),
+ clang_path: getopts::opt_maybe_str(matches, "clang-path").map_move(|s| Path(s)),
+ llvm_bin_path: getopts::opt_maybe_str(matches, "llvm-bin-path").map_move(|s| Path(s)),
src_base: opt_path(matches, "src-base"),
build_base: opt_path(matches, "build-base"),
aux_base: opt_path(matches, "aux-base"),
} else {
None
},
- logfile: getopts::opt_maybe_str(matches, "logfile").map(|s| Path(*s)),
- save_metrics: getopts::opt_maybe_str(matches, "save-metrics").map(|s| Path(*s)),
+ logfile: getopts::opt_maybe_str(matches, "logfile").map_move(|s| Path(s)),
+ save_metrics: getopts::opt_maybe_str(matches, "save-metrics").map_move(|s| Path(s)),
ratchet_metrics:
- getopts::opt_maybe_str(matches, "ratchet-metrics").map(|s| Path(*s)),
+ getopts::opt_maybe_str(matches, "ratchet-metrics").map_move(|s| Path(s)),
ratchet_noise_percent:
getopts::opt_maybe_str(matches,
- "ratchet-noise-percent").map(|s|
- f64::from_str(*s).unwrap()),
+ "ratchet-noise-percent").map_move(|s|
+ f64::from_str(s).unwrap()),
runtool: getopts::opt_maybe_str(matches, "runtool"),
rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
jit: getopts::opt_present(matches, "jit"),
round += 1;
}
- let mut expected =
- match props.pp_exact {
- Some(ref file) => {
+ let mut expected = match props.pp_exact {
+ Some(ref file) => {
let filepath = testfile.dir_path().push_rel(file);
io::read_whole_file_str(&filepath).unwrap()
}
}
}
- for i in range(0u, found_flags.len()) {
- if !found_flags[i] {
+ for (i, &flag) in found_flags.iter().enumerate() {
+ if !flag {
let ee = &expected_errors[i];
fatal_ProcRes(fmt!("expected %s on line %u not found: %s",
ee.kind, ee.line, ee.msg), ProcRes);
<keyword>for</keyword>
<keyword>if</keyword>
<keyword>impl</keyword>
+ <keyword>in</keyword>
<keyword>let</keyword>
<keyword>log</keyword>
<keyword>loop</keyword>
}
}
}
+
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_arc_condvar_poison() {
unsafe {
}
assert_eq!(*state, 42);
*state = 31337;
- // FIXME: #7372: hits type inference bug with iterators
// send to other readers
- for i in range(0u, reader_convos.len()) {
- match reader_convos[i] {
- (ref rc, _) => rc.send(()),
- }
+ for &(ref rc, _) in reader_convos.iter() {
+ rc.send(())
}
}
let read_mode = arc.downgrade(write_mode);
do (&read_mode).read |state| {
- // FIXME: #7372: hits type inference bug with iterators
// complete handshake with other readers
- for i in range(0u, reader_convos.len()) {
- match reader_convos[i] {
- (_, ref rp) => rp.recv(),
- }
+ for &(_, ref rp) in reader_convos.iter() {
+ rp.recv()
}
wc1.send(()); // tell writer to try again
assert_eq!(*state, 31337);
// except according to those terms.
//! Base64 binary-to-text encoding
+use std::str;
/// Available encoding character sets
pub enum CharacterSet {
pub static MIME: Config =
Config {char_set: Standard, pad: true, line_length: Some(76)};
-static STANDARD_CHARS: [char, ..64] = [
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
-];
-
-static URLSAFE_CHARS: [char, ..64] = [
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
-];
+static STANDARD_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "abcdefghijklmnopqrstuvwxyz",
+ "0123456789+/");
+
+static URLSAFE_CHARS: &'static[u8] = bytes!("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "abcdefghijklmnopqrstuvwxyz",
+ "0123456789-_");
/// A trait for converting a value to base64 encoding.
pub trait ToBase64 {
* ~~~
*/
fn to_base64(&self, config: Config) -> ~str {
- let chars = match config.char_set {
+ let bytes = match config.char_set {
Standard => STANDARD_CHARS,
UrlSafe => URLSAFE_CHARS
};
- let mut s = ~"";
+ let mut v: ~[u8] = ~[];
let mut i = 0;
let mut cur_length = 0;
let len = self.len();
match config.line_length {
Some(line_length) =>
if cur_length >= line_length {
- s.push_str("\r\n");
+ v.push('\r' as u8);
+ v.push('\n' as u8);
cur_length = 0;
},
None => ()
(self[i + 2] as u32);
// This 24-bit number gets separated into four 6-bit numbers.
- s.push_char(chars[(n >> 18) & 63]);
- s.push_char(chars[(n >> 12) & 63]);
- s.push_char(chars[(n >> 6 ) & 63]);
- s.push_char(chars[n & 63]);
+ v.push(bytes[(n >> 18) & 63]);
+ v.push(bytes[(n >> 12) & 63]);
+ v.push(bytes[(n >> 6 ) & 63]);
+ v.push(bytes[n & 63]);
cur_length += 4;
i += 3;
match config.line_length {
Some(line_length) =>
if cur_length >= line_length {
- s.push_str("\r\n");
+ v.push('\r' as u8);
+ v.push('\n' as u8);
},
None => ()
}
0 => (),
1 => {
let n = (self[i] as u32) << 16;
- s.push_char(chars[(n >> 18) & 63]);
- s.push_char(chars[(n >> 12) & 63]);
+ v.push(bytes[(n >> 18) & 63]);
+ v.push(bytes[(n >> 12) & 63]);
if config.pad {
- s.push_str("==");
+ v.push('=' as u8);
+ v.push('=' as u8);
}
}
2 => {
let n = (self[i] as u32) << 16 |
(self[i + 1u] as u32) << 8;
- s.push_char(chars[(n >> 18) & 63]);
- s.push_char(chars[(n >> 12) & 63]);
- s.push_char(chars[(n >> 6 ) & 63]);
+ v.push(bytes[(n >> 18) & 63]);
+ v.push(bytes[(n >> 12) & 63]);
+ v.push(bytes[(n >> 6 ) & 63]);
if config.pad {
- s.push_char('=');
+ v.push('=' as u8);
}
}
_ => fail!("Algebra is broken, please alert the math police")
}
- s
- }
-}
-impl<'self> ToBase64 for &'self str {
- /**
- * Convert any string (literal, `@`, `&`, or `~`) to base64 encoding.
- *
- *
- * # Example
- *
- * ~~~ {.rust}
- * extern mod extra;
- * use extra::base64::{ToBase64, standard};
- *
- * fn main () {
- * let str = "Hello, World".to_base64(standard);
- * printfln!("%s", str);
- * }
- * ~~~
- *
- */
- fn to_base64(&self, config: Config) -> ~str {
- self.as_bytes().to_base64(config)
+ unsafe {
+ str::raw::from_bytes_owned(v)
+ }
}
}
fn from_base64(&self) -> Result<~[u8], ~str>;
}
-impl<'self> FromBase64 for &'self [u8] {
+impl<'self> FromBase64 for &'self str {
/**
- * Convert base64 `u8` vector into u8 byte values.
- * Every 4 encoded characters is converted into 3 octets, modulo padding.
+ * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
+ * to the byte values it encodes.
+ *
+ * You can use the `from_bytes` function in `std::str`
+ * to turn a `[u8]` into a string with characters corresponding to those
+ * values.
*
* # Example
*
+ * This converts a string literal to base64 and back.
+ *
* ~~~ {.rust}
* extern mod extra;
* use extra::base64::{ToBase64, FromBase64, standard};
+ * use std::str;
*
* fn main () {
- * let str = [52,32].to_base64(standard);
- * printfln!("%s", str);
- * let bytes = str.from_base64();
+ * let hello_str = "Hello, World".to_base64(standard);
+ * printfln!("%s", hello_str);
+ * let bytes = hello_str.from_base64();
* printfln!("%?", bytes);
+ * let result_str = str::from_bytes(bytes);
+ * printfln!("%s", result_str);
* }
* ~~~
*/
let mut buf: u32 = 0;
let mut modulus = 0;
- let mut it = self.iter();
- for &byte in it {
- let ch = byte as char;
+ let mut it = self.byte_iter().enumerate();
+ for (idx, byte) in it {
let val = byte as u32;
- match ch {
+ match byte as char {
'A'..'Z' => buf |= val - 0x41,
'a'..'z' => buf |= val - 0x47,
'0'..'9' => buf |= val + 0x04,
'/'|'_' => buf |= 0x3F,
'\r'|'\n' => loop,
'=' => break,
- _ => return Err(~"Invalid Base64 character")
+ _ => return Err(fmt!("Invalid character '%c' at position %u",
+ self.char_at(idx), idx))
}
buf <<= 6;
}
}
- if !it.all(|&byte| {byte as char == '='}) {
- return Err(~"Invalid Base64 character");
+ for (idx, byte) in it {
+ if (byte as char) != '=' {
+ return Err(fmt!("Invalid character '%c' at position %u",
+ self.char_at(idx), idx));
+ }
}
match modulus {
}
}
-impl<'self> FromBase64 for &'self str {
- /**
- * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
- * to the byte values it encodes.
- *
- * You can use the `from_bytes` function in `std::str`
- * to turn a `[u8]` into a string with characters corresponding to those
- * values.
- *
- * # Example
- *
- * This converts a string literal to base64 and back.
- *
- * ~~~ {.rust}
- * extern mod extra;
- * use extra::base64::{ToBase64, FromBase64, standard};
- * use std::str;
- *
- * fn main () {
- * let hello_str = "Hello, World".to_base64(standard);
- * printfln!("%s", hello_str);
- * let bytes = hello_str.from_base64();
- * printfln!("%?", bytes);
- * let result_str = str::from_bytes(bytes);
- * printfln!("%s", result_str);
- * }
- * ~~~
- */
- fn from_base64(&self) -> Result<~[u8], ~str> {
- self.as_bytes().from_base64()
- }
-}
-
#[cfg(test)]
mod test {
use test::BenchHarness;
#[test]
fn test_to_base64_basic() {
- assert_eq!("".to_base64(STANDARD), ~"");
- assert_eq!("f".to_base64(STANDARD), ~"Zg==");
- assert_eq!("fo".to_base64(STANDARD), ~"Zm8=");
- assert_eq!("foo".to_base64(STANDARD), ~"Zm9v");
- assert_eq!("foob".to_base64(STANDARD), ~"Zm9vYg==");
- assert_eq!("fooba".to_base64(STANDARD), ~"Zm9vYmE=");
- assert_eq!("foobar".to_base64(STANDARD), ~"Zm9vYmFy");
+ assert_eq!("".as_bytes().to_base64(STANDARD), ~"");
+ assert_eq!("f".as_bytes().to_base64(STANDARD), ~"Zg==");
+ assert_eq!("fo".as_bytes().to_base64(STANDARD), ~"Zm8=");
+ assert_eq!("foo".as_bytes().to_base64(STANDARD), ~"Zm9v");
+ assert_eq!("foob".as_bytes().to_base64(STANDARD), ~"Zm9vYg==");
+ assert_eq!("fooba".as_bytes().to_base64(STANDARD), ~"Zm9vYmE=");
+ assert_eq!("foobar".as_bytes().to_base64(STANDARD), ~"Zm9vYmFy");
}
#[test]
fn test_to_base64_line_break() {
assert!(![0u8, 1000].to_base64(Config {line_length: None, ..STANDARD})
.contains("\r\n"));
- assert_eq!("foobar".to_base64(Config {line_length: Some(4), ..STANDARD}),
+ assert_eq!("foobar".as_bytes().to_base64(Config {line_length: Some(4),
+ ..STANDARD}),
~"Zm9v\r\nYmFy");
}
#[test]
fn test_to_base64_padding() {
- assert_eq!("f".to_base64(Config {pad: false, ..STANDARD}), ~"Zg");
- assert_eq!("fo".to_base64(Config {pad: false, ..STANDARD}), ~"Zm8");
+ assert_eq!("f".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zg");
+ assert_eq!("fo".as_bytes().to_base64(Config {pad: false, ..STANDARD}), ~"Zm8");
}
#[test]
#[test]
fn test_from_base64_invalid_char() {
assert!("Zm$=".from_base64().is_err())
- assert!("Zg==$".from_base64().is_err());
+ assert!("Zg==$".from_base64().is_err());
}
#[test]
}
#[bench]
- pub fn to_base64(bh: & mut BenchHarness) {
+ pub fn bench_to_base64(bh: & mut BenchHarness) {
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
do bh.iter {
- s.to_base64(STANDARD);
+ s.as_bytes().to_base64(STANDARD);
}
bh.bytes = s.len() as u64;
}
#[bench]
- pub fn from_base64(bh: & mut BenchHarness) {
+ pub fn bench_from_base64(bh: & mut BenchHarness) {
let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
- let b = s.to_base64(STANDARD);
+ let b = s.as_bytes().to_base64(STANDARD);
do bh.iter {
b.from_base64();
}
let len = b.storage.len();
assert_eq!(self.storage.len(), len);
let mut changed = false;
- for i in range(0, len) {
+ for (i, (a, b)) in self.storage.mut_iter()
+ .zip(b.storage.iter())
+ .enumerate() {
let mask = big_mask(nbits, i);
- let w0 = self.storage[i] & mask;
- let w1 = b.storage[i] & mask;
+ let w0 = *a & mask;
+ let w1 = *b & mask;
let w = op(w0, w1) & mask;
if w0 != w {
changed = true;
- self.storage[i] = w;
+ *a = w;
}
}
changed
#[inline]
pub fn each_storage(&mut self, op: &fn(v: &mut uint) -> bool) -> bool {
- range(0u, self.storage.len()).advance(|i| op(&mut self.storage[i]))
+ self.storage.mut_iter().advance(|elt| op(elt))
}
#[inline]
#[inline]
pub fn equals(&self, b: &BigBitv, nbits: uint) -> bool {
- let len = b.storage.len();
- for i in range(0, len) {
+ for (i, elt) in b.storage.iter().enumerate() {
let mask = big_mask(nbits, i);
- if mask & self.storage[i] != mask & b.storage[i] {
+ if mask & self.storage[i] != mask & *elt {
return false;
}
}
/// Remove the first Node and return it, or None if the list is empty
#[inline]
fn pop_front_node(&mut self) -> Option<~Node<T>> {
- do self.list_head.take().map_consume |mut front_node| {
+ do self.list_head.take().map_move |mut front_node| {
self.length -= 1;
match front_node.next.take() {
Some(node) => self.list_head = link_with_prev(node, Rawlink::none()),
/// Remove the last Node and return it, or None if the list is empty
#[inline]
fn pop_back_node(&mut self) -> Option<~Node<T>> {
- do self.list_tail.resolve().map_consume_default(None) |tail| {
+ do self.list_tail.resolve().map_move_default(None) |tail| {
self.length -= 1;
self.list_tail = tail.prev;
match tail.prev.resolve() {
///
/// O(1)
fn pop_front(&mut self) -> Option<T> {
- self.pop_front_node().map_consume(|~Node{value, _}| value)
+ self.pop_front_node().map_move(|~Node{value, _}| value)
}
/// Add an element last in the list
///
/// O(1)
fn pop_back(&mut self) -> Option<T> {
- self.pop_back_node().map_consume(|~Node{value, _}| value)
+ self.pop_back_node().map_move(|~Node{value, _}| value)
}
}
/// If the list is empty, do nothing.
#[inline]
pub fn rotate_forward(&mut self) {
- do self.pop_back_node().map_consume |tail| {
+ do self.pop_back_node().map_move |tail| {
self.push_front_node(tail)
};
}
/// If the list is empty, do nothing.
#[inline]
pub fn rotate_backward(&mut self) {
- do self.pop_front_node().map_consume |head| {
+ do self.pop_front_node().map_move |head| {
self.push_back_node(head)
};
}
if self.nelem == 0 {
return None;
}
- do self.tail.resolve().map_consume |prev| {
+ do self.tail.resolve().map_move |prev| {
self.nelem -= 1;
self.tail = prev.prev;
&prev.value
if self.nelem == 0 {
return None;
}
- do self.head.resolve().map_consume |next| {
+ do self.head.resolve().map_move |next| {
self.nelem -= 1;
self.head = match next.next {
Some(ref mut node) => Rawlink::some(&mut **node),
if self.nelem == 0 {
return None;
}
- do self.tail.resolve().map_consume |prev| {
+ do self.tail.resolve().map_move |prev| {
self.nelem -= 1;
self.tail = prev.prev;
&mut prev.value
if self.nelem == 0 {
return None
}
- self.head.resolve().map_consume(|head| &mut head.value)
+ self.head.resolve().map_move(|head| &mut head.value)
}
}
pub mod semver;
pub mod fileinput;
pub mod flate;
+pub mod hex;
#[cfg(unicode)]
mod unicode;
`Some(path)` is the file represented by `path`, `None` is
`stdin`. Consumed as the files are read.
*/
- priv files: ~[Option<Path>],
+ files: ~[Option<Path>],
/**
The current file: `Some(r)` for an open file, `None` before
starting and after reading everything.
*/
- priv current_reader: Option<@io::Reader>,
- priv state: FileInputState,
+ current_reader: Option<@io::Reader>,
+ state: FileInputState,
/**
Used to keep track of whether we need to insert the newline at the
end of a file that is missing it, which is needed to separate the
last and first lines.
*/
- priv previous_was_newline: bool
+ previous_was_newline: bool
}
// XXX: remove this when Reader has &mut self. Should be removable via
// "self.fi." -> "self." and renaming FileInput_. Documentation above
// will likely have to be updated to use `let mut in = ...`.
pub struct FileInput {
- priv fi: @mut FileInput_
+ fi: @mut FileInput_
}
impl FileInput {
FileInput::from_vec(pathed)
}
- priv fn current_file_eof(&self) -> bool {
+ fn current_file_eof(&self) -> bool {
match self.fi.current_reader {
None => false,
Some(r) => r.eof()
Returns `true` if it had to move to the next file and did
so successfully.
*/
- priv fn next_file_if_eof(&self) -> bool {
+ fn next_file_if_eof(&self) -> bool {
match self.fi.current_reader {
None => self.next_file(),
Some(r) => {
static LZ_FAST : c_int = 0x1; // LZ with only one probe
static LZ_NORM : c_int = 0x80; // LZ with 128 probes, "normal"
static LZ_BEST : c_int = 0xfff; // LZ with 4095 probes, "best"
+static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adler32 checksum
+static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
-pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] {
+fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;
rustrt::tdefl_compress_mem_to_heap(b as *c_void,
len as size_t,
&mut outsz,
- LZ_NORM);
+ flags);
assert!(res as int != 0);
let out = vec::raw::from_buf_raw(res as *u8,
outsz as uint);
}
}
-pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] {
+pub fn deflate_bytes(bytes: &[u8]) -> ~[u8] {
+ deflate_bytes_internal(bytes, LZ_NORM)
+}
+
+pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
+ deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
+}
+
+fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;
rustrt::tinfl_decompress_mem_to_heap(b as *c_void,
len as size_t,
&mut outsz,
- 0);
+ flags);
assert!(res as int != 0);
let out = vec::raw::from_buf_raw(res as *u8,
outsz as uint);
}
}
+pub fn inflate_bytes(bytes: &[u8]) -> ~[u8] {
+ inflate_bytes_internal(bytes, 0)
+}
+
+pub fn inflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
+ inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
+}
+
#[cfg(test)]
mod tests {
use super::*;
assert_eq!(input, out);
}
}
+
+ #[test]
+ fn test_zlib_flate() {
+ let bytes = ~[1, 2, 3, 4, 5];
+ let deflated = deflate_bytes(bytes);
+ let inflated = inflate_bytes(deflated);
+ assert_eq!(inflated, bytes);
+ }
}
fn drop(&self) {}
}
-priv enum FutureState<A> {
+enum FutureState<A> {
Pending(~fn() -> A),
Evaluating,
Forced(A)
pub struct Opt {
name: Name,
hasarg: HasArg,
- occur: Occur
+ occur: Occur,
+ aliases: ~[Opt],
}
fn mkname(nm: &str) -> Name {
/// Create an option that is required and takes an argument
pub fn reqopt(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: Yes, occur: Req};
+ return Opt {name: mkname(name), hasarg: Yes, occur: Req, aliases: ~[]};
}
/// Create an option that is optional and takes an argument
pub fn optopt(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: Yes, occur: Optional};
+ return Opt {name: mkname(name), hasarg: Yes, occur: Optional, aliases: ~[]};
}
/// Create an option that is optional and does not take an argument
pub fn optflag(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: No, occur: Optional};
+ return Opt {name: mkname(name), hasarg: No, occur: Optional, aliases: ~[]};
}
/** Create an option that is optional, does not take an argument,
* and may occur multiple times.
*/
pub fn optflagmulti(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: No, occur: Multi};
+ return Opt {name: mkname(name), hasarg: No, occur: Multi, aliases: ~[]};
}
/// Create an option that is optional and takes an optional argument
pub fn optflagopt(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: Maybe, occur: Optional};
+ return Opt {name: mkname(name), hasarg: Maybe, occur: Optional, aliases: ~[]};
}
/**
* multiple times
*/
pub fn optmulti(name: &str) -> Opt {
- return Opt {name: mkname(name), hasarg: Yes, occur: Multi};
+ return Opt {name: mkname(name), hasarg: Yes, occur: Multi, aliases: ~[]};
}
#[deriving(Clone, Eq)]
}
fn find_opt(opts: &[Opt], nm: Name) -> Option<uint> {
- opts.iter().position(|opt| opt.name == nm)
+ // search main options
+ let pos = opts.iter().position(|opt| opt.name == nm);
+ if pos.is_some() {
+ return pos
+ }
+
+ // search in aliases
+ for candidate in opts.iter() {
+ if candidate.aliases.iter().position(|opt| opt.name == nm).is_some() {
+ return opts.iter().position(|opt| opt.name == candidate.name);
+ }
+ }
+
+ None
}
/**
use getopts::{HasArg, Long, Maybe, Multi, No, Occur, Opt, Optional, Req};
use getopts::{Short, Yes};
- use std::vec;
-
/** one group of options, e.g., both -h and --help, along with
* their shared description and properties
*/
occur: Optional};
}
+ /// Create a long option that can occur more than once and does not
+ /// take an argument
+ pub fn optflagmulti(short_name: &str, long_name: &str,
+ desc: &str) -> OptGroup {
+ let len = short_name.len();
+ assert!(len == 1 || len == 0);
+ return OptGroup {short_name: short_name.to_owned(),
+ long_name: long_name.to_owned(),
+ hint: ~"",
+ desc: desc.to_owned(),
+ hasarg: No,
+ occur: Multi};
+ }
+
/// Create a long option that is optional and takes an optional argument
pub fn optflagopt(short_name: &str, long_name: &str,
desc: &str, hint: &str) -> OptGroup {
// translate OptGroup into Opt
// (both short and long names correspond to different Opts)
- pub fn long_to_short(lopt: &OptGroup) -> ~[Opt] {
+ pub fn long_to_short(lopt: &OptGroup) -> Opt {
let OptGroup{short_name: short_name,
long_name: long_name,
hasarg: hasarg,
_} = (*lopt).clone();
match (short_name.len(), long_name.len()) {
- (0,0) => fail!("this long-format option was given no name"),
-
- (0,_) => ~[Opt {name: Long((long_name)),
- hasarg: hasarg,
- occur: occur}],
-
- (1,0) => ~[Opt {name: Short(short_name.char_at(0)),
- hasarg: hasarg,
- occur: occur}],
-
- (1,_) => ~[Opt {name: Short(short_name.char_at(0)),
- hasarg: hasarg,
- occur: occur},
- Opt {name: Long((long_name)),
- hasarg: hasarg,
- occur: occur}],
-
- (_,_) => fail!("something is wrong with the long-form opt")
+ (0,0) => fail!("this long-format option was given no name"),
+
+ (0,_) => Opt {name: Long((long_name)),
+ hasarg: hasarg,
+ occur: occur,
+ aliases: ~[]},
+
+ (1,0) => Opt {name: Short(short_name.char_at(0)),
+ hasarg: hasarg,
+ occur: occur,
+ aliases: ~[]},
+
+ (1,_) => Opt {name: Long((long_name)),
+ hasarg: hasarg,
+ occur: occur,
+ aliases: ~[Opt {
+ name: Short(short_name.char_at(0)),
+ hasarg: hasarg,
+ occur: occur,
+ aliases: ~[]
+ }]},
+
+ (_,_) => fail!("something is wrong with the long-form opt")
}
}
* Parse command line args with the provided long format options
*/
pub fn getopts(args: &[~str], opts: &[OptGroup]) -> ::getopts::Result {
- ::getopts::getopts(args, vec::flat_map(opts, long_to_short))
+ ::getopts::getopts(args, opts.map(long_to_short))
}
/**
* Fails during iteration if the string contains a non-whitespace
* sequence longer than the limit.
*/
- priv fn each_split_within<'a>(ss: &'a str,
- lim: uint,
- it: &fn(&'a str) -> bool) -> bool {
+ fn each_split_within<'a>(ss: &'a str,
+ lim: uint,
+ it: &fn(&'a str) -> bool) -> bool {
// Just for fun, let's write this as an state machine:
enum SplitWithinState {
}
#[test]
- priv fn test_split_within() {
+ fn test_split_within() {
fn t(s: &str, i: uint, u: &[~str]) {
let mut v = ~[];
do each_split_within(s, i) |s| { v.push(s.to_owned()); true };
#[test]
fn test_groups_long_to_short() {
- let short = ~[reqopt("b"), reqopt("banana")];
+ let mut short = reqopt("banana");
+ short.aliases = ~[reqopt("b")];
let verbose = groups::reqopt("b", "banana", "some bananas", "VAL");
assert_eq!(groups::long_to_short(&verbose), short);
#[test]
fn test_groups_getopts() {
+ let mut banana = reqopt("banana");
+ banana.aliases = ~[reqopt("b")];
+ let mut apple = optopt("apple");
+ apple.aliases = ~[optopt("a")];
+ let mut kiwi = optflag("kiwi");
+ kiwi.aliases = ~[optflag("k")];
let short = ~[
- reqopt("b"), reqopt("banana"),
- optopt("a"), optopt("apple"),
- optflag("k"), optflagopt("kiwi"),
+ banana,
+ apple,
+ kiwi,
optflagopt("p"),
optmulti("l")
];
groups::optmulti("l", "", "Desc", "VAL"),
];
- let sample_args = ~[~"-k", ~"15", ~"--apple", ~"1", ~"k",
+ let sample_args = ~[~"--kiwi", ~"15", ~"--apple", ~"1", ~"k",
~"-p", ~"16", ~"l", ~"35"];
// FIXME #4681: sort options here?
== groups::getopts(sample_args, verbose));
}
+ #[test]
+ fn test_groups_aliases_long_and_short() {
+ let opts = ~[
+ groups::optflagmulti("a", "apple", "Desc"),
+ ];
+
+ let args = ~[~"-a", ~"--apple", ~"-a"];
+
+ let matches = groups::getopts(args, opts).unwrap();
+ assert_eq!(3, opt_count(&matches, "a"));
+ assert_eq!(3, opt_count(&matches, "apple"));
+ }
+
#[test]
fn test_groups_usage() {
let optgroups = ~[
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Hex binary-to-text encoding
+use std::str;
+use std::vec;
+
+/// A trait for converting a value to hexadecimal encoding
+pub trait ToHex {
+ /// Converts the value of `self` to a hex value, returning the owned
+ /// string.
+ fn to_hex(&self) -> ~str;
+}
+
+static CHARS: &'static[u8] = bytes!("0123456789abcdef");
+
+impl<'self> ToHex for &'self [u8] {
+ /**
+ * Turn a vector of `u8` bytes into a hexadecimal string.
+ *
+ * # Example
+ *
+ * ~~~ {.rust}
+ * extern mod extra;
+ * use extra::hex::ToHex;
+ *
+ * fn main () {
+ * let str = [52,32].to_hex();
+ * printfln!("%s", str);
+ * }
+ * ~~~
+ */
+ fn to_hex(&self) -> ~str {
+ let mut v = vec::with_capacity(self.len() * 2);
+ for &byte in self.iter() {
+ v.push(CHARS[byte >> 4]);
+ v.push(CHARS[byte & 0xf]);
+ }
+
+ unsafe {
+ str::raw::from_bytes_owned(v)
+ }
+ }
+}
+
+/// A trait for converting hexadecimal encoded values
+pub trait FromHex {
+ /// Converts the value of `self`, interpreted as hexadecimal encoded data,
+ /// into an owned vector of bytes, returning the vector.
+ fn from_hex(&self) -> Result<~[u8], ~str>;
+}
+
+impl<'self> FromHex for &'self str {
+ /**
+ * Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)
+ * to the byte values it encodes.
+ *
+ * You can use the `from_bytes` function in `std::str`
+ * to turn a `[u8]` into a string with characters corresponding to those
+ * values.
+ *
+ * # Example
+ *
+ * This converts a string literal to hexadecimal and back.
+ *
+ * ~~~ {.rust}
+ * extern mod extra;
+ * use extra::hex::{FromHex, ToHex};
+ * use std::str;
+ *
+ * fn main () {
+ * let hello_str = "Hello, World".to_hex();
+ * printfln!("%s", hello_str);
+ * let bytes = hello_str.from_hex().unwrap();
+ * printfln!("%?", bytes);
+ * let result_str = str::from_bytes(bytes);
+ * printfln!("%s", result_str);
+ * }
+ * ~~~
+ */
+ fn from_hex(&self) -> Result<~[u8], ~str> {
+ // This may be an overestimate if there is any whitespace
+ let mut b = vec::with_capacity(self.len() / 2);
+ let mut modulus = 0;
+ let mut buf = 0u8;
+
+ for (idx, byte) in self.byte_iter().enumerate() {
+ buf <<= 4;
+
+ match byte as char {
+ 'A'..'F' => buf |= byte - ('A' as u8) + 10,
+ 'a'..'f' => buf |= byte - ('a' as u8) + 10,
+ '0'..'9' => buf |= byte - ('0' as u8),
+ ' '|'\r'|'\n'|'\t' => {
+ buf >>= 4;
+ loop
+ }
+ _ => return Err(fmt!("Invalid character '%c' at position %u",
+ self.char_at(idx), idx))
+ }
+
+ modulus += 1;
+ if modulus == 2 {
+ modulus = 0;
+ b.push(buf);
+ }
+ }
+
+ match modulus {
+ 0 => Ok(b),
+ _ => Err(~"Invalid input length")
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use test::BenchHarness;
+ use hex::*;
+
+ #[test]
+ pub fn test_to_hex() {
+ assert_eq!("foobar".as_bytes().to_hex(), ~"666f6f626172");
+ }
+
+ #[test]
+ pub fn test_from_hex_okay() {
+ assert_eq!("666f6f626172".from_hex().unwrap(),
+ "foobar".as_bytes().to_owned());
+ assert_eq!("666F6F626172".from_hex().unwrap(),
+ "foobar".as_bytes().to_owned());
+ }
+
+ #[test]
+ pub fn test_from_hex_odd_len() {
+ assert!("666".from_hex().is_err());
+ assert!("66 6".from_hex().is_err());
+ }
+
+ #[test]
+ pub fn test_from_hex_invalid_char() {
+ assert!("66y6".from_hex().is_err());
+ }
+
+ #[test]
+ pub fn test_from_hex_ignores_whitespace() {
+ assert_eq!("666f 6f6\r\n26172 ".from_hex().unwrap(),
+ "foobar".as_bytes().to_owned());
+ }
+
+ #[test]
+ pub fn test_to_hex_all_bytes() {
+ for i in range(0, 256) {
+ assert_eq!([i as u8].to_hex(), fmt!("%02x", i as uint));
+ }
+ }
+
+ #[test]
+ pub fn test_from_hex_all_bytes() {
+ for i in range(0, 256) {
+ assert_eq!(fmt!("%02x", i as uint).from_hex().unwrap(), ~[i as u8]);
+ assert_eq!(fmt!("%02X", i as uint).from_hex().unwrap(), ~[i as u8]);
+ }
+ }
+
+ #[bench]
+ pub fn bench_to_hex(bh: & mut BenchHarness) {
+ let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+ do bh.iter {
+ s.as_bytes().to_hex();
+ }
+ bh.bytes = s.len() as u64;
+ }
+
+ #[bench]
+ pub fn bench_from_hex(bh: & mut BenchHarness) {
+ let s = "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
+ ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
+ let b = s.as_bytes().to_hex();
+ do bh.iter {
+ b.from_hex();
+ }
+ bh.bytes = b.len() as u64;
+ }
+}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*! Composable internal iterators
-
-Internal iterators are functions implementing the protocol used by the `for` loop.
-
-An internal iterator takes `fn(...) -> bool` as a parameter, with returning `false` used to signal
-breaking out of iteration. The adaptors in the module work with any such iterator, not just ones
-tied to specific traits. For example:
-
-~~~ {.rust}
-println(iter::to_vec(|f| uint::range(0, 20, f)).to_str());
-~~~
-
-An external iterator object implementing the interface in the `iterator` module can be used as an
-internal iterator by calling the `advance` method. For example:
-
-~~~ {.rust}
-let xs = [0u, 1, 2, 3, 4, 5];
-let ys = [30, 40, 50, 60];
-let mut it = xs.iter().chain(ys.iter());
-for &x: &uint in it {
- println(x.to_str());
-}
-~~~
-
-Internal iterators provide a subset of the functionality of an external iterator. It's not possible
-to interleave them to implement algorithms like `zip`, `union` and `merge`. However, they're often
-much easier to implement.
-
-*/
-
-use std::vec;
-use std::cmp::Ord;
-use std::option::{Option, Some, None};
-use std::num::{One, Zero};
-use std::ops::{Add, Mul};
-
-#[allow(missing_doc)]
-pub trait FromIter<T> {
- /// Build a container with elements from an internal iterator.
- ///
- /// # Example:
- ///
- /// ~~~ {.rust}
- /// let xs = ~[1, 2, 3];
- /// let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) };
- /// assert_eq!(xs, ys);
- /// ~~~
- pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> Self;
-}
-
-/**
- * Return true if `predicate` is true for any values yielded by an internal iterator.
- *
- * Example:
- *
- * ~~~ {.rust}
- * let xs = ~[1u, 2, 3, 4, 5];
- * assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f)));
- * assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f)));
- * ~~~
- */
-#[inline]
-pub fn any<T>(predicate: &fn(T) -> bool,
- iter: &fn(f: &fn(T) -> bool) -> bool) -> bool {
- do iter |x| {
- predicate(x)
- }
-}
-
-/**
- * Return true if `predicate` is true for all values yielded by an internal iterator.
- *
- * # Example:
- *
- * ~~~ {.rust}
- * assert!(all(|&x: &uint| x < 6, |f| uint::range(1, 6, f)));
- * assert!(!all(|&x: &uint| x < 5, |f| uint::range(1, 6, f)));
- * ~~~
- */
-#[inline]
-pub fn all<T>(predicate: &fn(T) -> bool,
- iter: &fn(f: &fn(T) -> bool) -> bool) -> bool {
- // If we ever break, iter will return false, so this will only return true
- // if predicate returns true for everything.
- iter(|x| predicate(x))
-}
-
-/**
- * Return the first element where `predicate` returns `true`. Return `None` if no element is found.
- *
- * # Example:
- *
- * ~~~ {.rust}
- * let xs = ~[1u, 2, 3, 4, 5, 6];
- * assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4);
- * ~~~
- */
-#[inline]
-pub fn find<T>(predicate: &fn(&T) -> bool,
- iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
- let mut ret = None;
- do iter |x| {
- if predicate(&x) {
- ret = Some(x);
- false
- } else { true }
- };
- ret
-}
-
-/**
- * Return the largest item yielded by an iterator. Return `None` if the iterator is empty.
- *
- * # Example:
- *
- * ~~~ {.rust}
- * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
- * assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15);
- * ~~~
- */
-#[inline]
-pub fn max<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
- let mut result = None;
- do iter |x| {
- match result {
- Some(ref mut y) => {
- if x > *y {
- *y = x;
- }
- }
- None => result = Some(x)
- }
- true
- };
- result
-}
-
-/**
- * Return the smallest item yielded by an iterator. Return `None` if the iterator is empty.
- *
- * # Example:
- *
- * ~~~ {.rust}
- * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
- * assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &-5);
- * ~~~
- */
-#[inline]
-pub fn min<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> {
- let mut result = None;
- do iter |x| {
- match result {
- Some(ref mut y) => {
- if x < *y {
- *y = x;
- }
- }
- None => result = Some(x)
- }
- true
- };
- result
-}
-
-/**
- * Reduce an iterator to an accumulated value.
- *
- * # Example:
- *
- * ~~~ {.rust}
- * assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
- * ~~~
- */
-#[inline]
-pub fn fold<T, U>(start: T, iter: &fn(f: &fn(U) -> bool) -> bool, f: &fn(&mut T, U)) -> T {
- let mut result = start;
- do iter |x| {
- f(&mut result, x);
- true
- };
- result
-}
-
-/**
- * Reduce an iterator to an accumulated value.
- *
- * `fold_ref` is usable in some generic functions where `fold` is too lenient to type-check, but it
- * forces the iterator to yield borrowed pointers.
- *
- * # Example:
- *
- * ~~~ {.rust}
- * fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
- * fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
- * }
- * ~~~
- */
-#[inline]
-pub fn fold_ref<T, U>(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&mut T, &U)) -> T {
- let mut result = start;
- do iter |x| {
- f(&mut result, x);
- true
- };
- result
-}
-
-/**
- * Return the sum of the items yielding by an iterator.
- *
- * # Example:
- *
- * ~~~ {.rust}
- * let xs: ~[int] = ~[1, 2, 3, 4];
- * assert_eq!(do sum |f| { xs.iter().advance(f) }, 10);
- * ~~~
- */
-#[inline]
-pub fn sum<T: Zero + Add<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
- fold_ref(Zero::zero::<T>(), iter, |a, x| *a = a.add(x))
-}
-
-/**
- * Return the product of the items yielded by an iterator.
- *
- * # Example:
- *
- * ~~~ {.rust}
- * let xs: ~[int] = ~[1, 2, 3, 4];
- * assert_eq!(do product |f| { xs.iter().advance(f) }, 24);
- * ~~~
- */
-#[inline]
-pub fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T {
- fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x))
-}
-
-impl<T> FromIter<T> for ~[T]{
- #[inline]
- pub fn from_iter(iter: &fn(f: &fn(T) -> bool) -> bool) -> ~[T] {
- let mut v = ~[];
- do iter |x| { v.push(x); true };
- v
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use prelude::*;
-
- use int;
- use uint;
-
- #[test]
- fn test_from_iter() {
- let xs = ~[1, 2, 3];
- let ys: ~[int] = do FromIter::from_iter |f| { xs.iter().advance(|x| f(*x)) };
- assert_eq!(xs, ys);
- }
-
- #[test]
- fn test_any() {
- let xs = ~[1u, 2, 3, 4, 5];
- assert!(any(|&x: &uint| x > 2, |f| xs.iter().advance(f)));
- assert!(!any(|&x: &uint| x > 5, |f| xs.iter().advance(f)));
- }
-
- #[test]
- fn test_all() {
- assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f)));
- assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f)));
- }
-
- #[test]
- fn test_find() {
- let xs = ~[1u, 2, 3, 4, 5, 6];
- assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.iter().advance(f)).unwrap(), 4);
- }
-
- #[test]
- fn test_max() {
- let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
- assert_eq!(max(|f| xs.iter().advance(f)).unwrap(), &15);
- }
-
- #[test]
- fn test_min() {
- let xs = ~[8, 2, 3, 1, -5, 9, 11, 15];
- assert_eq!(min(|f| xs.iter().advance(f)).unwrap(), &-5);
- }
-
- #[test]
- fn test_fold() {
- assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10);
- }
-
- #[test]
- fn test_sum() {
- let xs: ~[int] = ~[1, 2, 3, 4];
- assert_eq!(do sum |f| { xs.iter().advance(f) }, 10);
- }
-
- #[test]
- fn test_empty_sum() {
- let xs: ~[int] = ~[];
- assert_eq!(do sum |f| { xs.iter().advance(f) }, 0);
- }
-
- #[test]
- fn test_product() {
- let xs: ~[int] = ~[1, 2, 3, 4];
- assert_eq!(do product |f| { xs.iter().advance(f) }, 24);
- }
-
- #[test]
- fn test_empty_product() {
- let xs: ~[int] = ~[];
- assert_eq!(do product |f| { xs.iter().advance(f) }, 1);
- }
-}
pub static bits: uint = 32;
pub static base: uint = 1 << bits;
- priv static hi_mask: uint = (-1 as uint) << bits;
- priv static lo_mask: uint = (-1 as uint) >> bits;
+ static hi_mask: uint = (-1 as uint) << bits;
+ static lo_mask: uint = (-1 as uint) >> bits;
- priv fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit }
+ fn get_hi(n: uint) -> BigDigit { (n >> bits) as BigDigit }
- priv fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit }
+ fn get_lo(n: uint) -> BigDigit { (n & lo_mask) as BigDigit }
/// Split one machine sized unsigned integer into two BigDigits.
pub fn new(v: ~[BigDigit]) -> BigUint {
// omit trailing zeros
- let new_len = v.rposition(|n| *n != 0).map_default(0, |p| *p + 1);
+ let new_len = v.rposition(|n| *n != 0).map_move_default(0, |p| p + 1);
if new_len == v.len() { return BigUint { data: v }; }
let mut v = v;
}
- priv fn shl_unit(&self, n_unit: uint) -> BigUint {
+ fn shl_unit(&self, n_unit: uint) -> BigUint {
if n_unit == 0 || self.is_zero() { return (*self).clone(); }
return BigUint::new(vec::from_elem(n_unit, ZERO_BIG_DIGIT)
}
- priv fn shl_bits(&self, n_bits: uint) -> BigUint {
+ fn shl_bits(&self, n_bits: uint) -> BigUint {
if n_bits == 0 || self.is_zero() { return (*self).clone(); }
let mut carry = 0;
}
- priv fn shr_unit(&self, n_unit: uint) -> BigUint {
+ fn shr_unit(&self, n_unit: uint) -> BigUint {
if n_unit == 0 { return (*self).clone(); }
if self.data.len() < n_unit { return Zero::zero(); }
return BigUint::from_slice(
}
- priv fn shr_bits(&self, n_bits: uint) -> BigUint {
+ fn shr_bits(&self, n_bits: uint) -> BigUint {
if n_bits == 0 || self.data.is_empty() { return (*self).clone(); }
let mut borrow = 0;
#[cfg(target_arch = "x86_64")]
-priv fn get_radix_base(radix: uint) -> (uint, uint) {
+fn get_radix_base(radix: uint) -> (uint, uint) {
assert!(1 < radix && radix <= 16);
match radix {
2 => (4294967296, 32),
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "mips")]
-priv fn get_radix_base(radix: uint) -> (uint, uint) {
+fn get_radix_base(radix: uint) -> (uint, uint) {
assert!(1 < radix && radix <= 16);
match radix {
2 => (65536, 16),
start = 1;
}
return BigUint::parse_bytes(buf.slice(start, buf.len()), radix)
- .map_consume(|bu| BigInt::from_biguint(sign, bu));
+ .map_move(|bu| BigInt::from_biguint(sign, bu));
}
pub fn to_uint(&self) -> uint {
#[test]
fn test_from_str_radix() {
fn check(s: &str, ans: Option<int>) {
- let ans = ans.map(|&n| IntConvertible::from_int::<BigInt>(n));
+ let ans = ans.map_move(|n| IntConvertible::from_int::<BigInt>(n));
assert_eq!(FromStrRadix::from_str_radix(s, 10), ans);
}
check("10", Some(10));
let u: ~[int] = deq.iter().transform(|&x| x).collect();
assert_eq!(u, v);
- let mut seq = iterator::Counter::new(0u, 2).take_(256);
+ let mut seq = iterator::count(0u, 2).take_(256);
let deq: RingBuf<uint> = seq.collect();
for (i, &x) in deq.iter().enumerate() {
assert_eq!(2*i, x);
#[allow(missing_doc)];
use std::iterator::{Iterator, IteratorUtil, Enumerate, FilterMap, Invert};
-use std::uint;
use std::util::replace;
use std::vec::{VecIterator, VecMutIterator};
use std::vec;
impl<V> Container for SmallIntMap<V> {
/// Return the number of elements in the map
fn len(&self) -> uint {
- let mut sz = 0;
- for i in range(0u, self.v.len()) {
- match self.v[i] {
- Some(_) => sz += 1,
- None => {}
- }
- }
- sz
+ self.v.iter().count(|elt| elt.is_some())
+ }
+
+ /// Return true if there are no elements in the map
+ fn is_empty(&self) -> bool {
+ self.v.iter().all(|elt| elt.is_none())
}
}
/// Create an empty SmallIntMap
pub fn new() -> SmallIntMap<V> { SmallIntMap{v: ~[]} }
- /// Visit all key-value pairs in order
- pub fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) -> bool {
- for i in range(0u, self.v.len()) {
- match self.v[i] {
- Some(ref elt) => if !it(&i, elt) { return false; },
- None => ()
- }
- }
- true
- }
-
- /// Visit all keys in order
- pub fn each_key(&self, blk: &fn(key: &uint) -> bool) -> bool {
- self.each(|k, _| blk(k))
- }
-
- /// Visit all values in order
- pub fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) -> bool {
- self.each(|_, v| blk(v))
- }
-
- /// Iterate over the map and mutate the contained values
- pub fn mutate_values(&mut self, it: &fn(&uint, &mut V) -> bool) -> bool {
- for i in range(0, self.v.len()) {
- match self.v[i] {
- Some(ref mut elt) => if !it(&i, elt) { return false; },
- None => ()
- }
- }
- true
- }
-
- /// Visit all key-value pairs in reverse order
- pub fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) -> bool {
- do uint::range_rev(self.v.len(), 0) |i| {
- match self.v[i] {
- Some(ref elt) => it(i, elt),
- None => true
- }
- }
- }
-
pub fn get<'a>(&'a self, key: &uint) -> &'a V {
self.find(key).expect("key not present")
}
{
let values = replace(&mut self.v, ~[]);
values.consume_iter().enumerate().filter_map(|(i, v)| {
- v.map_consume(|v| (i, v))
+ v.map_move(|v| (i, v))
})
}
}
base2: uint, len2: uint) {
assert!(len1 != 0 && len2 != 0 && base1+len1 == base2);
- let mut tmp = ~[];
- for i in range(base1, base1+len1) {
- tmp.push(array[i].clone());
- }
+ let mut tmp = array.slice(base1, base1 + len1).to_owned();
let mut c1 = 0;
let mut c2 = base2;
base2: uint, len2: uint) {
assert!(len1 != 1 && len2 != 0 && base1 + len1 == base2);
- let mut tmp = ~[];
- for i in range(base2, base2+len2) {
- tmp.push(array[i].clone());
- }
+ let mut tmp = array.slice(base2, base2 + len2).to_owned();
let mut c1 = base1 + len1 - 1;
let mut c2 = len2 - 1;
use sort;
use std::cmp;
+use std::hashmap;
use std::io;
use std::num;
// Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using
// linear interpolation. If samples are not sorted, return nonsensical value.
-priv fn percentile_of_sorted(sorted_samples: &[f64],
+fn percentile_of_sorted(sorted_samples: &[f64],
pct: f64) -> f64 {
assert!(sorted_samples.len() != 0);
if sorted_samples.len() == 1 {
w.write_str(histr);
}
+/// Returns a HashMap with the number of occurences of every element in the
+/// sequence that the iterator exposes.
+pub fn freq_count<T: Iterator<U>, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap<U, uint> {
+ let mut map = hashmap::HashMap::new::<U, uint>();
+ for elem in iter {
+ map.insert_or_update_with(elem, 1, |_, count| *count += 1);
+ }
+ map
+}
+
// Test vectors generated from R, using the script src/etc/stat-test-vectors.r.
#[cfg(test)]
// child task must have finished by the time try returns
do m.lock { }
}
+ #[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_mutex_killed_cond() {
// Getting killed during cond wait must not corrupt the mutex while
assert!(!woken);
}
}
+ #[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_mutex_killed_broadcast() {
use std::unstable::finally::Finally;
}
#[cfg(not(target_os = "win32"))]
-priv fn cap_for_attr(attr: attr::Attr) -> &'static str {
+fn cap_for_attr(attr: attr::Attr) -> &'static str {
match attr {
attr::Bold => "bold",
attr::Dim => "dim",
let inf = ti.unwrap();
let nc = if inf.strings.find_equiv(&("setaf")).is_some()
&& inf.strings.find_equiv(&("setab")).is_some() {
- inf.numbers.find_equiv(&("colors")).map_consume_default(0, |&n| n)
+ inf.numbers.find_equiv(&("colors")).map_move_default(0, |&n| n)
} else { 0 };
return Ok(Terminal {out: out, ti: inf, num_colors: nc});
cap = self.ti.strings.find_equiv(&("op"));
}
}
- let s = do cap.map_consume_default(Err(~"can't find terminfo capability `sgr0`")) |op| {
+ let s = do cap.map_move_default(Err(~"can't find terminfo capability `sgr0`")) |op| {
expand(*op, [], &mut Variables::new())
};
if s.is_ok() {
}
}
- priv fn dim_if_necessary(&self, color: color::Color) -> color::Color {
+ fn dim_if_necessary(&self, color: color::Color) -> color::Color {
if color >= self.num_colors && color >= 8 && color < 16 {
color-8
} else { color }
}
#[deriving(Eq)]
-priv struct Flags {
+struct Flags {
width: uint,
precision: uint,
alternate: bool,
}
impl Flags {
- priv fn new() -> Flags {
+ fn new() -> Flags {
Flags{ width: 0, precision: 0, alternate: false,
left: false, sign: false, space: false }
}
}
-priv enum FormatOp {
+enum FormatOp {
FormatDigit,
FormatOctal,
FormatHex,
}
impl FormatOp {
- priv fn from_char(c: char) -> FormatOp {
+ fn from_char(c: char) -> FormatOp {
match c {
'd' => FormatDigit,
'o' => FormatOctal,
_ => fail!("bad FormatOp char")
}
}
- priv fn to_char(self) -> char {
+ fn to_char(self) -> char {
match self {
FormatDigit => 'd',
FormatOctal => 'o',
}
}
-priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> {
+fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> {
let mut s = match val {
Number(d) => {
match op {
let run_ignored = getopts::opt_present(&matches, "ignored");
let logfile = getopts::opt_maybe_str(&matches, "logfile");
- let logfile = logfile.map(|s| Path(*s));
+ let logfile = logfile.map_move(|s| Path(s));
let run_benchmarks = getopts::opt_present(&matches, "bench");
let run_tests = ! run_benchmarks ||
getopts::opt_present(&matches, "test");
let ratchet_metrics = getopts::opt_maybe_str(&matches, "ratchet-metrics");
- let ratchet_metrics = ratchet_metrics.map(|s| Path(*s));
+ let ratchet_metrics = ratchet_metrics.map_move(|s| Path(s));
let ratchet_noise_percent = getopts::opt_maybe_str(&matches, "ratchet-noise-percent");
- let ratchet_noise_percent = ratchet_noise_percent.map(|s| f64::from_str(*s).unwrap());
+ let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| f64::from_str(s).unwrap());
let save_metrics = getopts::opt_maybe_str(&matches, "save-metrics");
- let save_metrics = save_metrics.map(|s| Path(*s));
+ let save_metrics = save_metrics.map_move(|s| Path(s));
let test_opts = TestOpts {
filter: filter,
}
}
-priv fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> {
+fn do_strptime(s: &str, format: &str) -> Result<Tm, ~str> {
fn match_str(s: &str, pos: uint, needle: &str) -> bool {
let mut i = pos;
for ch in needle.byte_iter() {
}
}
-priv fn do_strftime(format: &str, tm: &Tm) -> ~str {
+fn do_strftime(format: &str, tm: &Tm) -> ~str {
fn parse_type(ch: char, tm: &Tm) -> ~str {
//FIXME (#2350): Implement missing types.
let die = || fmt!("strftime: can't understand this format %c ", ch);
//! `TotalOrd`.
-use std::num;
use std::util::{swap, replace};
use std::iterator::{FromIterator, Extendable};
impl<K: Eq + TotalOrd, V: Eq> Eq for TreeMap<K, V> {
fn eq(&self, other: &TreeMap<K, V>) -> bool {
- if self.len() != other.len() {
- false
- } else {
- let mut x = self.iter();
- let mut y = other.iter();
- for _ in range(0u, self.len()) {
- if x.next().unwrap() != y.next().unwrap() {
- return false
- }
- }
- true
- }
+ self.len() == other.len() &&
+ self.iter().zip(other.iter()).all(|(a, b)| a == b)
}
- fn ne(&self, other: &TreeMap<K, V>) -> bool { !self.eq(other) }
}
// Lexicographical comparison
fn lt<K: Ord + TotalOrd, V: Ord>(a: &TreeMap<K, V>,
b: &TreeMap<K, V>) -> bool {
- let mut x = a.iter();
- let mut y = b.iter();
-
- let (a_len, b_len) = (a.len(), b.len());
- for _ in range(0u, num::min(a_len, b_len)) {
- let (key_a, value_a) = x.next().unwrap();
- let (key_b, value_b) = y.next().unwrap();
+ // the Zip iterator is as long as the shortest of a and b.
+ for ((key_a, value_a), (key_b, value_b)) in a.iter().zip(b.iter()) {
if *key_a < *key_b { return true; }
if *key_a > *key_b { return false; }
if *value_a < *value_b { return true; }
if *value_a > *value_b { return false; }
}
- a_len < b_len
+ a.len() < b.len()
}
impl<K: Ord + TotalOrd, V: Ord> Ord for TreeMap<K, V> {
/// Create an empty TreeMap
pub fn new() -> TreeMap<K, V> { TreeMap{root: None, length: 0} }
- /// Visit all keys in order
- pub fn each_key(&self, f: &fn(&K) -> bool) -> bool {
- self.iter().advance(|(k, _)| f(k))
- }
-
- /// Visit all values in order
- pub fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) -> bool {
- self.iter().advance(|(_, v)| f(v))
- }
-
/// Iterate over the map and mutate the contained values
pub fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) -> bool {
mutate_values(&mut self.root, f)
}
- /// Visit all key-value pairs in reverse order
- pub fn each_reverse<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) -> bool {
- each_reverse(&self.root, f)
- }
-
- /// Visit all keys in reverse order
- pub fn each_key_reverse(&self, f: &fn(&K) -> bool) -> bool {
- self.each_reverse(|k, _| f(k))
- }
-
- /// Visit all values in reverse order
- pub fn each_value_reverse(&self, f: &fn(&V) -> bool) -> bool {
- self.each_reverse(|_, v| f(v))
- }
-
/// Get a lazy iterator over the key-value pairs in the map.
/// Requires that it be frozen (immutable).
pub fn iter<'a>(&'a self) -> TreeMapIterator<'a, K, V> {
}
}
+ /// Get a lazy reverse iterator over the key-value pairs in the map.
+ /// Requires that it be frozen (immutable).
+ pub fn rev_iter<'a>(&'a self) -> TreeMapRevIterator<'a, K, V> {
+ TreeMapRevIterator{iter: self.iter()}
+ }
+
/// Get a lazy iterator that should be initialized using
/// `iter_traverse_left`/`iter_traverse_right`/`iter_traverse_complete`.
fn iter_for_traversal<'a>(&'a self) -> TreeMapIterator<'a, K, V> {
priv remaining_max: uint
}
-impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> {
- /// 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`.
- fn next(&mut self) -> Option<(&'self K, &'self V)> {
+impl<'self, K, V> TreeMapIterator<'self, K, V> {
+ #[inline(always)]
+ fn next_(&mut self, forward: bool) -> Option<(&'self K, &'self V)> {
while !self.stack.is_empty() || self.node.is_some() {
match *self.node {
Some(ref x) => {
self.stack.push(x);
- self.node = &x.left;
+ self.node = if forward { &x.left } else { &x.right };
}
None => {
let res = self.stack.pop();
- self.node = &res.right;
+ self.node = if forward { &res.right } else { &res.left };
self.remaining_max -= 1;
if self.remaining_min > 0 {
self.remaining_min -= 1;
}
None
}
+}
+
+impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> {
+ /// 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`.
+ fn next(&mut self) -> Option<(&'self K, &'self V)> {
+ self.next_(true)
+ }
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
}
}
+/// Lazy backward iterator over a map
+pub struct TreeMapRevIterator<'self, K, V> {
+ priv iter: TreeMapIterator<'self, K, V>,
+}
+
+impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapRevIterator<'self, K, V> {
+ /// 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`.
+ fn next(&mut self) -> Option<(&'self K, &'self V)> {
+ self.iter.next_(false)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ self.iter.size_hint()
+ }
+}
+
/// iter_traverse_left, iter_traverse_right and iter_traverse_complete are used to
/// initialize TreeMapIterator pointing to element inside tree structure.
///
}
impl<'self, T> Iterator<&'self T> for TreeSetIterator<'self, T> {
+ /// Advance the iterator to the next node (in order). If there are no more nodes, return `None`.
+ #[inline]
+ fn next(&mut self) -> Option<&'self T> {
+ do self.iter.next().map_move |(value, _)| { value }
+ }
+}
+
+impl<'self, T> Iterator<&'self T> for TreeSetRevIterator<'self, T> {
/// Advance the iterator to the next node (in order). If there are no more nodes, return `None`.
#[inline]
fn next(&mut self) -> Option<&'self T> {
/// Return true if the set has no elements in common with `other`.
/// This is equivalent to checking for an empty intersection.
fn is_disjoint(&self, other: &TreeSet<T>) -> bool {
- let mut x = self.iter();
- let mut y = other.iter();
- let mut a = x.next();
- let mut b = y.next();
- while a.is_some() && b.is_some() {
- let a1 = a.unwrap();
- let b1 = b.unwrap();
- match a1.cmp(b1) {
- Less => a = x.next(),
- Greater => b = y.next(),
- Equal => return false
- }
- }
- true
+ self.intersection(other).next().is_none()
}
/// Return true if the set is a subset of another
TreeSetIterator{iter: self.map.iter()}
}
+ /// Get a lazy iterator over the values in the set.
+ /// Requires that it be frozen (immutable).
+ #[inline]
+ pub fn rev_iter<'a>(&'a self) -> TreeSetRevIterator<'a, T> {
+ TreeSetRevIterator{iter: self.map.rev_iter()}
+ }
+
/// Get a lazy iterator pointing to the first value not less than `v` (greater or equal).
/// If all elements in the set are less than `v` empty iterator is returned.
#[inline]
TreeSetIterator{iter: self.map.upper_bound_iter(v)}
}
- /// Visit all values in reverse order
- #[inline]
- pub fn each_reverse(&self, f: &fn(&T) -> bool) -> bool {
- self.map.each_key_reverse(f)
+ /// Visit the values (in-order) representing the difference
+ pub fn difference<'a>(&'a self, other: &'a TreeSet<T>) -> Difference<'a, T> {
+ Difference{a: Focus::new(self.iter()), b: Focus::new(other.iter())}
}
- /// Visit the values (in-order) representing the difference
- pub fn difference(&self, other: &TreeSet<T>, f: &fn(&T) -> bool) -> bool {
- let mut x = self.iter();
- let mut y = other.iter();
+ /// Visit the values (in-order) representing the symmetric difference
+ pub fn symmetric_difference<'a>(&'a self, other: &'a TreeSet<T>)
+ -> SymDifference<'a, T> {
+ SymDifference{a: Focus::new(self.iter()), b: Focus::new(other.iter())}
+ }
- let mut a = x.next();
- let mut b = y.next();
+ /// Visit the values (in-order) representing the intersection
+ pub fn intersection<'a>(&'a self, other: &'a TreeSet<T>)
+ -> Intersection<'a, T> {
+ Intersection{a: Focus::new(self.iter()), b: Focus::new(other.iter())}
+ }
- while a.is_some() {
- if b.is_none() {
- return f(a.unwrap()) && x.advance(f);
- }
+ /// Visit the values (in-order) representing the union
+ pub fn union<'a>(&'a self, other: &'a TreeSet<T>) -> Union<'a, T> {
+ Union{a: Focus::new(self.iter()), b: Focus::new(other.iter())}
+ }
+}
- let a1 = a.unwrap();
- let b1 = b.unwrap();
+/// Lazy forward iterator over a set
+pub struct TreeSetIterator<'self, T> {
+ priv iter: TreeMapIterator<'self, T, ()>
+}
- let cmp = a1.cmp(b1);
+/// Lazy backward iterator over a set
+pub struct TreeSetRevIterator<'self, T> {
+ priv iter: TreeMapRevIterator<'self, T, ()>
+}
- if cmp == Less {
- if !f(a1) { return false; }
- a = x.next();
- } else {
- if cmp == Equal { a = x.next() }
- b = y.next();
- }
- }
- return true;
- }
+// Encapsulate an iterator and hold its latest value until stepped forward
+struct Focus<A, T> {
+ priv iter: T,
+ priv focus: Option<A>,
+}
- /// Visit the values (in-order) representing the symmetric difference
- pub fn symmetric_difference(&self, other: &TreeSet<T>,
- f: &fn(&T) -> bool) -> bool {
- let mut x = self.iter();
- let mut y = other.iter();
+impl<A, T: Iterator<A>> Focus<A, T> {
+ fn new(mut it: T) -> Focus<A, T> {
+ Focus{focus: it.next(), iter: it}
+ }
+ fn step(&mut self) {
+ self.focus = self.iter.next()
+ }
+}
- let mut a = x.next();
- let mut b = y.next();
+/// Lazy iterator producing elements in the set difference (in-order)
+pub struct Difference<'self, T> {
+ priv a: Focus<&'self T, TreeSetIterator<'self, T>>,
+ priv b: Focus<&'self T, TreeSetIterator<'self, T>>,
+}
- while a.is_some() {
- if b.is_none() {
- return f(a.unwrap()) && x.advance(f);
- }
+/// Lazy iterator producing elements in the set symmetric difference (in-order)
+pub struct SymDifference<'self, T> {
+ priv a: Focus<&'self T, TreeSetIterator<'self, T>>,
+ priv b: Focus<&'self T, TreeSetIterator<'self, T>>,
+}
- let a1 = a.unwrap();
- let b1 = b.unwrap();
+/// Lazy iterator producing elements in the set intersection (in-order)
+pub struct Intersection<'self, T> {
+ priv a: Focus<&'self T, TreeSetIterator<'self, T>>,
+ priv b: Focus<&'self T, TreeSetIterator<'self, T>>,
+}
- let cmp = a1.cmp(b1);
+/// Lazy iterator producing elements in the set intersection (in-order)
+pub struct Union<'self, T> {
+ priv a: Focus<&'self T, TreeSetIterator<'self, T>>,
+ priv b: Focus<&'self T, TreeSetIterator<'self, T>>,
+}
- if cmp == Less {
- if !f(a1) { return false; }
- a = x.next();
- } else {
- if cmp == Greater {
- if !f(b1) { return false; }
- } else {
- a = x.next();
+impl<'self, T: TotalOrd> Iterator<&'self T> for Difference<'self, T> {
+ fn next(&mut self) -> Option<&'self T> {
+ loop {
+ match (self.a.focus, self.b.focus) {
+ (None , _ ) => return None,
+ (ret , None ) => { self.a.step(); return ret },
+ (Some(a1), Some(b1)) => {
+ let cmp = a1.cmp(b1);
+ if cmp == Less {
+ self.a.step();
+ return Some(a1);
+ } else {
+ if cmp == Equal { self.a.step() }
+ self.b.step();
+ }
}
- b = y.next();
}
}
- b.iter().advance(|&x| f(x)) && y.advance(f)
}
+}
- /// Visit the values (in-order) representing the intersection
- pub fn intersection(&self, other: &TreeSet<T>, f: &fn(&T) -> bool) -> bool {
- let mut x = self.iter();
- let mut y = other.iter();
-
- let mut a = x.next();
- let mut b = y.next();
-
- while a.is_some() && b.is_some() {
- let a1 = a.unwrap();
- let b1 = b.unwrap();
-
- let cmp = a1.cmp(b1);
-
- if cmp == Less {
- a = x.next();
- } else {
- if cmp == Equal {
- if !f(a1) { return false }
+impl<'self, T: TotalOrd> Iterator<&'self T> for SymDifference<'self, T> {
+ fn next(&mut self) -> Option<&'self T> {
+ loop {
+ match (self.a.focus, self.b.focus) {
+ (ret , None ) => { self.a.step(); return ret },
+ (None , ret ) => { self.b.step(); return ret },
+ (Some(a1), Some(b1)) => {
+ let cmp = a1.cmp(b1);
+ if cmp == Less {
+ self.a.step();
+ return Some(a1);
+ } else {
+ self.b.step();
+ if cmp == Greater {
+ return Some(b1);
+ } else {
+ self.a.step();
+ }
+ }
}
- b = y.next();
}
}
- return true;
}
+}
- /// Visit the values (in-order) representing the union
- pub fn union(&self, other: &TreeSet<T>, f: &fn(&T) -> bool) -> bool {
- let mut x = self.iter();
- let mut y = other.iter();
-
- let mut a = x.next();
- let mut b = y.next();
-
- while a.is_some() {
- if b.is_none() {
- return f(a.unwrap()) && x.advance(f);
+impl<'self, T: TotalOrd> Iterator<&'self T> for Intersection<'self, T> {
+ fn next(&mut self) -> Option<&'self T> {
+ loop {
+ match (self.a.focus, self.b.focus) {
+ (None , _ ) => return None,
+ (_ , None ) => return None,
+ (Some(a1), Some(b1)) => {
+ let cmp = a1.cmp(b1);
+ if cmp == Less {
+ self.a.step();
+ } else {
+ self.b.step();
+ if cmp == Equal {
+ return Some(a1);
+ }
+ }
+ },
}
+ }
+ }
+}
- let a1 = a.unwrap();
- let b1 = b.unwrap();
-
- let cmp = a1.cmp(b1);
-
- if cmp == Greater {
- if !f(b1) { return false; }
- b = y.next();
- } else {
- if !f(a1) { return false; }
- if cmp == Equal {
- b = y.next();
+impl<'self, T: TotalOrd> Iterator<&'self T> for Union<'self, T> {
+ fn next(&mut self) -> Option<&'self T> {
+ loop {
+ match (self.a.focus, self.b.focus) {
+ (ret , None) => { self.a.step(); return ret },
+ (None , ret ) => { self.b.step(); return ret },
+ (Some(a1), Some(b1)) => {
+ let cmp = a1.cmp(b1);
+ if cmp == Greater {
+ self.b.step();
+ return Some(b1);
+ } else {
+ self.a.step();
+ if cmp == Equal {
+ self.b.step();
+ }
+ return Some(a1);
+ }
}
- a = x.next();
}
}
- b.iter().advance(|&x| f(x)) && y.advance(f)
}
}
-/// Lazy forward iterator over a set
-pub struct TreeSetIterator<'self, T> {
- priv iter: TreeMapIterator<'self, T, ()>
-}
// Nodes keep track of their level in the tree, starting at 1 in the
// leaves and with a red child sharing the level of the parent.
}
}
-fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>,
- f: &fn(&'r K, &'r V) -> bool) -> bool {
- node.iter().advance(|x| each(&x.left, |k,v| f(k,v)) && f(&x.key, &x.value) &&
- each(&x.right, |k,v| f(k,v)))
-}
-
-fn each_reverse<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode<K, V>>,
- f: &fn(&'r K, &'r V) -> bool) -> bool {
- node.iter().advance(|x| each_reverse(&x.right, |k,v| f(k,v)) && f(&x.key, &x.value) &&
- each_reverse(&x.left, |k,v| f(k,v)))
-}
-
fn mutate_values<'r, K: TotalOrd, V>(node: &'r mut Option<~TreeNode<K, V>>,
f: &fn(&'r K, &'r mut V) -> bool)
-> bool {
}
#[test]
- fn test_each_reverse() {
+ fn test_rev_iter() {
let mut m = TreeMap::new();
assert!(m.insert(3, 6));
assert!(m.insert(1, 2));
let mut n = 4;
- do m.each_reverse |k, v| {
+ for (k, v) in m.rev_iter() {
assert_eq!(*k, n);
assert_eq!(*v, n * 2);
n -= 1;
- true
- };
+ }
}
#[test]
}
#[test]
- fn test_each_reverse() {
+ fn test_rev_iter() {
let mut m = TreeSet::new();
assert!(m.insert(3));
assert!(m.insert(1));
let mut n = 4;
- do m.each_reverse |x| {
+ for x in m.rev_iter() {
assert_eq!(*x, n);
n -= 1;
- true
- };
+ }
}
fn check(a: &[int], b: &[int], expected: &[int],
#[test]
fn test_intersection() {
fn check_intersection(a: &[int], b: &[int], expected: &[int]) {
- check(a, b, expected, |x, y, z| x.intersection(y, z))
+ check(a, b, expected, |x, y, f| x.intersection(y).advance(f))
}
check_intersection([], [], []);
#[test]
fn test_difference() {
fn check_difference(a: &[int], b: &[int], expected: &[int]) {
- check(a, b, expected, |x, y, z| x.difference(y, z))
+ check(a, b, expected, |x, y, f| x.difference(y).advance(f))
}
check_difference([], [], []);
fn test_symmetric_difference() {
fn check_symmetric_difference(a: &[int], b: &[int],
expected: &[int]) {
- check(a, b, expected, |x, y, z| x.symmetric_difference(y, z))
+ check(a, b, expected, |x, y, f| x.symmetric_difference(y).advance(f))
}
check_symmetric_difference([], [], []);
fn test_union() {
fn check_union(a: &[int], b: &[int],
expected: &[int]) {
- check(a, b, expected, |x, y, z| x.union(y, z))
+ check(a, b, expected, |x, y, f| x.union(y).advance(f))
}
check_union([], [], []);
fn digest_file(path: &Path) -> ~str {
let mut sha = ~Sha1::new();
let s = io::read_whole_file_str(path);
- (*sha).input_str(*s.get_ref());
+ (*sha).input_str(s.unwrap());
(*sha).result_str()
}
let pth = Path("foo.c");
{
let r = io::file_writer(&pth, [io::Create]);
- r.get_ref().write_str("int main() { return 0; }");
+ r.unwrap().write_str("int main() { return 0; }");
}
let cx = Context::new(RWArc::new(Database::new(Path("db.json"))),
fn find_cmd(command_string: &str) -> Option<Command> {
do COMMANDS.iter().find_ |command| {
command.cmd == command_string
- }.map_consume(|x| *x)
+ }.map_move(|x| *x)
}
fn cmd_help(args: &[~str]) -> ValidUsage {
} else if opt_present(matches, "emit-llvm") {
link::output_type_bitcode
} else { link::output_type_exe };
- let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot");
- let sysroot_opt = sysroot_opt.map(|m| @Path(*m));
+ let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
let target_opt = getopts::opt_maybe_str(matches, "target");
let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature");
let save_temps = getopts::opt_present(matches, "save-temps");
filter_item(cx, *a).chain(|x| fld.fold_item(x))
}.collect();
let filtered_view_items = do m.view_items.iter().filter_map |a| {
- filter_view_item(cx, a).map(|&x| fld.fold_view_item(x))
+ do filter_view_item(cx, a).map_move |x| {
+ fld.fold_view_item(x)
+ }
}.collect();
ast::_mod {
view_items: filtered_view_items,
) -> ast::foreign_mod {
let filtered_items = nm.items.iter().filter_map(|a| filter_foreign_item(cx, *a)).collect();
let filtered_view_items = do nm.view_items.iter().filter_map |a| {
- filter_view_item(cx, a).map(|&x| fld.fold_view_item(x))
+ do filter_view_item(cx, a).map_move |x| {
+ fld.fold_view_item(x)
+ }
}.collect();
ast::foreign_mod {
sort: nm.sort,
filter_stmt(cx, *a).chain(|stmt| fld.fold_stmt(stmt))
}.collect();
let filtered_view_items = do b.view_items.iter().filter_map |a| {
- filter_view_item(cx, a).map(|&x| fld.fold_view_item(x))
+ filter_view_item(cx, a).map(|x| fld.fold_view_item(*x))
}.collect();
ast::Block {
view_items: filtered_view_items,
}
pub fn find_type(&self, s: &str) -> Option<Type> {
- self.named_types.find_equiv(&s).map_consume(|x| Type::from_ref(*x))
+ self.named_types.find_equiv(&s).map_move(|x| Type::from_ref(*x))
}
// We have a depth count, because we seem to make infinite types.
pub fn find_extern_mod_stmt_cnum(cstore: &CStore,
emod_id: ast::NodeId)
-> Option<ast::CrateNum> {
- cstore.extern_mod_crate_map.find(&emod_id).map_consume(|x| *x)
+ cstore.extern_mod_crate_map.find(&emod_id).map_move(|x| *x)
}
#[deriving(Clone)]
}
fn get_provided_source(d: ebml::Doc, cdata: cmd) -> Option<ast::def_id> {
- do reader::maybe_get_doc(d, tag_item_method_provided_source).map |doc| {
- translate_def_id(cdata, reader::with_doc_data(*doc, parse_def_id))
+ do reader::maybe_get_doc(d, tag_item_method_provided_source).map_move |doc| {
+ translate_def_id(cdata, reader::with_doc_data(doc, parse_def_id))
}
}
}
fn item_ty_region_param(item: ebml::Doc) -> Option<ty::region_variance> {
- reader::maybe_get_doc(item, tag_region_param).map(|doc| {
- let mut decoder = reader::Decoder(*doc);
+ do reader::maybe_get_doc(item, tag_region_param).map_move |doc| {
+ let mut decoder = reader::Decoder(doc);
Decodable::decode(&mut decoder)
- })
+ }
}
fn item_ty_param_count(item: ebml::Doc) -> uint {
tcx: ty::ctxt) -> Option<@ty::TraitRef>
{
let item_doc = lookup_item(id, cdata.data);
- do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map |&tp| {
+ do reader::maybe_get_doc(item_doc, tag_item_trait_ref).map_move |tp| {
@doc_trait_ref(tp, tcx, cdata)
}
}
true
};
- for i in range(0u, new_loan_indices.len()) {
- let old_loan = &self.all_loans[new_loan_indices[i]];
- for j in range(i+1, new_loan_indices.len()) {
- let new_loan = &self.all_loans[new_loan_indices[j]];
+ for (i, &x) in new_loan_indices.iter().enumerate() {
+ let old_loan = &self.all_loans[x];
+ for &y in new_loan_indices.slice_from(i+1).iter() {
+ let new_loan = &self.all_loans[y];
self.report_error_if_loans_conflict(old_loan, new_loan);
}
}
}
mc::cat_deref(cmt_base, _, _) => {
- opt_loan_path(cmt_base).map(
- |&lp| @LpExtend(lp, cmt.mutbl, LpDeref))
+ do opt_loan_path(cmt_base).map_move |lp| {
+ @LpExtend(lp, cmt.mutbl, LpDeref)
+ }
}
mc::cat_interior(cmt_base, ik) => {
- opt_loan_path(cmt_base).map(
- |&lp| @LpExtend(lp, cmt.mutbl, LpInterior(ik)))
+ do opt_loan_path(cmt_base).map_move |lp| {
+ @LpExtend(lp, cmt.mutbl, LpInterior(ik))
+ }
}
mc::cat_downcast(cmt_base) |
}
pub fn lit_expr_eq(tcx: middle::ty::ctxt, a: &expr, b: &expr) -> Option<bool> {
- compare_lit_exprs(tcx, a, b).map(|&val| val == 0)
+ compare_lit_exprs(tcx, a, b).map_move(|val| val == 0)
}
pub fn lit_eq(a: &lit, b: &lit) -> Option<bool> {
- compare_const_vals(&lit_to_const(a), &lit_to_const(b)).map(|&val| val == 0)
+ compare_const_vals(&lit_to_const(a), &lit_to_const(b)).map_move(|val| val == 0)
}
op: &fn(uint, uint) -> uint) -> bool {
assert_eq!(out_vec.len(), in_vec.len());
let mut changed = false;
- for i in range(0u, out_vec.len()) {
- let old_val = out_vec[i];
- let new_val = op(old_val, in_vec[i]);
- out_vec[i] = new_val;
+ for (out_elt, in_elt) in out_vec.mut_iter().zip(in_vec.iter()) {
+ let old_val = *out_elt;
+ let new_val = op(old_val, *in_elt);
+ *out_elt = new_val;
changed |= (old_val != new_val);
}
changed
pub fn each_node(&self, f: &fn(NodeIndex, &Node<N>) -> bool) -> bool {
//! Iterates over all edges defined in the graph.
- range(0u, self.nodes.len()).advance(|i| f(NodeIndex(i), &self.nodes[i]))
+ self.nodes.iter().enumerate().advance(|(i, node)| f(NodeIndex(i), node))
}
pub fn each_edge(&self, f: &fn(EdgeIndex, &Edge<E>) -> bool) -> bool {
- //! Iterates over all edges defined in the graph.
- range(0u, self.nodes.len()).advance(|i| f(EdgeIndex(i), &self.edges[i]))
+ //! Iterates over all edges defined in the graph
+ self.edges.iter().enumerate().advance(|(i, edge)| f(EdgeIndex(i), edge))
}
pub fn each_outgoing_edge(&self,
return; // Didn't match.
}
- let item_index = self.item_refs.find(&value).map(|x| **x);
+ let item_index = self.item_refs.find(&value).map_move(|x| *x);
// prevent borrow checker from considering ^~~~~~~~~~~
// self to be borrowed (annoying)
match expr.node {
expr_path(_) => {
let def = self.tcx.def_map.get_copy(&expr.id);
- moves::moved_variable_node_id_from_def(def).map(
- |rdef| self.variable(*rdef, expr.span)
- )
+ do moves::moved_variable_node_id_from_def(def).map_move |rdef| {
+ self.variable(rdef, expr.span)
+ }
}
_ => None
}
-> Option<Variable> {
match self.tcx.def_map.find(&node_id) {
Some(&def) => {
- moves::moved_variable_node_id_from_def(def).map(
- |rdef| self.variable(*rdef, span)
- )
+ do moves::moved_variable_node_id_from_def(def).map_move |rdef| {
+ self.variable(rdef, span)
+ }
}
None => {
self.tcx.sess.span_bug(
pub fn opt_encl_scope(&self, id: ast::NodeId) -> Option<ast::NodeId> {
//! Returns the narrowest scope that encloses `id`, if any.
- self.scope_map.find(&id).map(|&x| *x)
+ self.scope_map.find(&id).map_move(|x| *x)
}
pub fn encl_scope(&self, id: ast::NodeId) -> ast::NodeId {
/// the new variance is joined with the old variance.
pub fn add_rp(&mut self, id: ast::NodeId, variance: region_variance) {
assert!(id != 0);
- let old_variance = self.region_paramd_items.find(&id).
- map_consume(|x| *x);
+ let old_variance = self.region_paramd_items.find(&id).map_move(|x| *x);
let joined_variance = match old_variance {
None => variance,
Some(v) => join_variance(v, variance)
use metadata::csearch::{each_path, get_trait_method_def_ids};
use metadata::csearch::get_method_name_and_explicit_self;
use metadata::csearch::get_static_methods_if_impl;
-use metadata::csearch::get_type_name_if_impl;
+use metadata::csearch::{get_type_name_if_impl, get_struct_fields};
use metadata::cstore::find_extern_mod_stmt_cnum;
use metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
use middle::lang_items::LanguageItems;
}
def_struct(def_id) => {
debug!("(building reduced graph for external \
- crate) building type %s",
+ crate) building type and value for %s",
final_ident);
child_name_bindings.define_type(privacy, def, dummy_sp());
+ if get_struct_fields(self.session.cstore, def_id).len() == 0 {
+ child_name_bindings.define_value(privacy, def, dummy_sp());
+ }
self.structs.insert(def_id);
}
def_method(*) => {
// item, it's ok
match def {
def_ty_param(did, _)
- if self.def_map.find(&did.node).map_consume(|x| *x)
+ if self.def_map.find(&did.node).map_move(|x| *x)
== Some(def_typaram_binder(item_id)) => {
// ok
}
static task_local_insn_key: local_data::Key<@~[&'static str]> = &local_data::Key;
pub fn with_insn_ctxt(blk: &fn(&[&'static str])) {
- let opt = local_data::get(task_local_insn_key, |k| k.map(|&k| *k));
+ let opt = local_data::get(task_local_insn_key, |k| k.map_move(|k| *k));
if opt.is_some() {
blk(*opt.unwrap());
}
impl Drop for _InsnCtxt {
fn drop(&self) {
do local_data::modify(task_local_insn_key) |c| {
- do c.map_consume |ctx| {
+ do c.map_move |ctx| {
let mut ctx = (*ctx).clone();
ctx.pop();
@ctx
pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
debug!("new InsnCtxt: %s", s);
do local_data::modify(task_local_insn_key) |c| {
- do c.map_consume |ctx| {
+ do c.map_move |ctx| {
let mut ctx = (*ctx).clone();
ctx.push(s);
@ctx
_ => {}
}
- for arg_n in range(0u, arg_tys.len()) {
- let arg_ty = arg_tys[arg_n];
+ for (arg_n, &arg_ty) in arg_tys.iter().enumerate() {
let raw_llarg = raw_llargs[arg_n];
// For certain mode/type combinations, the raw llarg values are passed
padding: Option<Type>,
coerce: bool) -> Type {
let size = ty_size(ty) * 8;
- let mut fields = padding.map_default(~[], |p| ~[*p]);
+ let mut fields = padding.map_move_default(~[], |p| ~[p]);
if coerce {
fields = vec::append(fields, coerce_to_int(size));
}
fn all_mem(cls: &mut [RegClass]) {
- for i in range(0u, cls.len()) {
- cls[i] = Memory;
+ for elt in cls.mut_iter() {
+ *elt = Memory;
}
}
pub fn node_vtables(bcx: @mut Block, id: ast::NodeId)
-> Option<typeck::vtable_res> {
let raw_vtables = bcx.ccx().maps.vtable_map.find(&id);
- raw_vtables.map(
- |&vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts))
+ raw_vtables.map_move(|vts| resolve_vtables_in_fn_ctxt(bcx.fcx, *vts))
}
pub fn resolve_vtables_in_fn_ctxt(fcx: &FunctionContext, vts: typeck::vtable_res)
static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;
pub fn task_llcx() -> ContextRef {
- let opt = local_data::get(task_local_llcx_key, |k| k.map(|&k| *k));
+ let opt = local_data::get(task_local_llcx_key, |k| k.map_move(|k| *k));
*opt.expect("task-local LLVMContextRef wasn't ever set!")
}
let offset = get_param(decl, first_real_arg + 1);
Ret(bcx, GEP(bcx, ptr, [offset]));
}
+ "offset_inbounds" => {
+ let ptr = get_param(decl, first_real_arg);
+ let offset = get_param(decl, first_real_arg + 1);
+ Ret(bcx, InBoundsGEP(bcx, ptr, [offset]));
+ }
"memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32),
"memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64),
"memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32),
data: Method(MethodData {
llfn: callee_fn.llfn,
llself: val,
- temp_cleanup: temp_cleanups.head_opt().map(|&v| *v),
+ temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v),
self_ty: node_id_type(bcx, this.id),
self_mode: mentry.self_mode,
})
data: Method(MethodData {
llfn: llfn_val,
llself: llself_val,
- temp_cleanup: temp_cleanups.head_opt().map(|&v| *v),
+ temp_cleanup: temp_cleanups.head_opt().map_move(|v| *v),
self_ty: node_id_type(bcx, base.id),
self_mode: mentry.self_mode,
})
"visit_tydesc" | "forget" | "frame_address" |
"morestack_addr" => 0,
- "offset" | "memcpy32" | "memcpy64" | "memmove32" | "memmove64" |
+ "offset" | "offset_inbounds" |
+ "memcpy32" | "memcpy64" | "memmove32" | "memmove64" |
"memset32" | "memset64" => use_repr,
"sqrtf32" | "sqrtf64" | "powif32" | "powif64" |
pub fn type_needs(cx: &Context, use_: uint, ty: ty::t) {
// Optimization -- don't descend type if all params already have this use
- let len = {
- let uses = &*cx.uses;
- uses.len()
- };
- for i in range(0u, len) {
- if cx.uses[i] & use_ != use_ {
- type_needs_inner(cx, use_, ty, @Nil);
- return;
- }
+ if cx.uses.iter().any(|&elt| elt & use_ != use_) {
+ type_needs_inner(cx, use_, ty, @Nil);
}
}
pub fn provided_source(cx: ctxt, id: ast::def_id)
-> Option<ast::def_id> {
- cx.provided_method_sources.find(&id).map(|x| **x)
+ cx.provided_method_sources.find(&id).map_move(|x| *x)
}
pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[@Method] {
Some(&ast_map::node_item(item, _)) => {
match item.node {
ast::item_struct(struct_def, _) => {
- struct_def.ctor_id.map(|ctor_id|
- ast_util::local_def(*ctor_id))
+ do struct_def.ctor_id.map_move |ctor_id| {
+ ast_util::local_def(ctor_id)
+ }
}
_ => cx.sess.bug("called struct_ctor_id on non-struct")
}
}
pub fn get_tydesc_ty(tcx: ctxt) -> Result<t, ~str> {
- do tcx.lang_items.require(TyDescStructLangItem).map |tydesc_lang_item| {
- tcx.intrinsic_defs.find_copy(tydesc_lang_item)
+ do tcx.lang_items.require(TyDescStructLangItem).map_move |tydesc_lang_item| {
+ tcx.intrinsic_defs.find_copy(&tydesc_lang_item)
.expect("Failed to resolve TyDesc")
}
}
pub fn get_opaque_ty(tcx: ctxt) -> Result<t, ~str> {
- do tcx.lang_items.require(OpaqueStructLangItem).map |opaque_lang_item| {
- tcx.intrinsic_defs.find_copy(opaque_lang_item)
+ do tcx.lang_items.require(OpaqueStructLangItem).map_move |opaque_lang_item| {
+ tcx.intrinsic_defs.find_copy(&opaque_lang_item)
.expect("Failed to resolve Opaque")
}
}
in_binding_rscope(rscope,
RegionParamNames(bound_lifetime_names.clone()));
- let opt_transformed_self_ty = opt_self_info.map(|&self_info| {
+ let opt_transformed_self_ty = do opt_self_info.map_move |self_info| {
transform_self_ty(this, &rb, self_info)
- });
+ };
let input_tys = decl.inputs.map(|a| ty_of_arg(this, &rb, a, None));
None => {
fcx.infcx().type_error_message_str_with_expected(pat.span,
|expected, actual| {
- expected.map_default(~"", |e| {
+ expected.map_move_default(~"", |e| {
fmt!("mismatched types: expected `%s` but found %s",
- *e, actual)})},
+ e, actual)})},
Some(expected), ~"a structure pattern",
None);
fcx.write_error(pat.id);
_ => {
fcx.infcx().type_error_message_str_with_expected(pat.span,
|expected, actual| {
- expected.map_default(~"", |e| {
+ expected.map_move_default(~"", |e| {
fmt!("mismatched types: expected `%s` but found %s",
- *e, actual)})},
+ e, actual)})},
Some(expected), ~"an enum or structure pattern",
None);
fcx.write_error(pat.id);
_ => ty::terr_mismatch
};
fcx.infcx().type_error_message_str_with_expected(pat.span, |expected, actual| {
- expected.map_default(~"", |e| {
+ expected.map_move_default(~"", |e| {
fmt!("mismatched types: expected `%s` but found %s",
- *e, actual)})}, Some(expected), ~"tuple", Some(&type_error));
+ e, actual)})}, Some(expected), ~"tuple", Some(&type_error));
fcx.write_error(pat.id);
}
}
fcx.infcx().type_error_message_str_with_expected(
pat.span,
|expected, actual| {
- expected.map_default(~"", |e| {
+ expected.map_move_default(~"", |e| {
fmt!("mismatched types: expected `%s` but found %s",
- *e, actual)})},
+ e, actual)})},
Some(expected),
~"a vector pattern",
None);
fcx.infcx().type_error_message_str_with_expected(
span,
|expected, actual| {
- expected.map_default(~"", |e| {
+ expected.map_move_default(~"", |e| {
fmt!("mismatched types: expected `%s` but found %s",
- *e, actual)})},
+ e, actual)})},
Some(expected),
fmt!("%s pattern", match pointer_kind {
Managed => "an @-box",
self.tcx().sess.span_err(
self.expr.span,
"multiple applicable methods in scope");
- for idx in range(0u, relevant_candidates.len()) {
- self.report_candidate(idx, &relevant_candidates[idx].origin);
+ for (idx, candidate) in relevant_candidates.iter().enumerate() {
+ self.report_candidate(idx, &candidate.origin);
}
}
|br| ty::re_free(ty::FreeRegion {scope_id: body.id,
bound_region: br}));
let opt_self_info =
- opt_self_info.map(
- |si| SelfInfo {self_ty: opt_self_ty.unwrap(), ..*si});
+ opt_self_info.map_move(
+ |si| SelfInfo {self_ty: opt_self_ty.unwrap(), .. si});
(isr, opt_self_info, fn_sig)
};
{
let method_def_id = local_def(method.id);
let method_ty = ty::method(ccx.tcx, method_def_id);
- let opt_self_info = method_ty.transformed_self_ty.map(|&ty| {
+ let opt_self_info = method_ty.transformed_self_ty.map_move(|ty| {
SelfInfo {self_ty: ty,
self_id: method.self_id,
span: method.explicit_self.span}
for p in fields.iter() {
let (id, sp) = *p;
- let orig_sp = field_names.find(&id).map_consume(|x| *x);
+ let orig_sp = field_names.find(&id).map_move(|x| *x);
match orig_sp {
Some(orig_sp) => {
tcx.sess.span_err(sp, fmt!("Duplicate field name %s in record type declaration",
check_bare_fn(ccx, decl, body, it.id, None);
}
ast::item_impl(_, _, _, ref ms) => {
- let rp = ccx.tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
+ let rp = ccx.tcx.region_paramd_items.find(&it.id).map_move(|x| *x);
debug!("item_impl %s with id %d rp %?",
ccx.tcx.sess.str_of(it.ident), it.id, rp);
for m in ms.iter() {
for field in ast_fields.iter() {
let mut expected_field_type = ty::mk_err();
- let pair = class_field_map.find(&field.ident).
- map_consume(|x| *x);
+ let pair = class_field_map.find(&field.ident).map_move(|x| *x);
match pair {
None => {
tcx.sess.span_err(
if class_id.crate == ast::LOCAL_CRATE {
region_parameterized =
tcx.region_paramd_items.find(&class_id.node).
- map_consume(|x| *x);
+ map_move(|x| *x);
match tcx.items.find(&class_id.node) {
Some(&ast_map::node_item(@ast::item {
node: ast::item_struct(_, ref generics),
let raw_type;
if enum_id.crate == ast::LOCAL_CRATE {
region_parameterized =
- tcx.region_paramd_items.find(&enum_id.node).map_consume(|x| *x);
+ tcx.region_paramd_items.find(&enum_id.node).map_move(|x| *x);
match tcx.items.find(&enum_id.node) {
Some(&ast_map::node_item(@ast::item {
node: ast::item_enum(_, ref generics),
mutbl: ast::m_imm
}))
}
+ "offset_inbounds" => {
+ (1,
+ ~[
+ ty::mk_ptr(tcx, ty::mt {
+ ty: param(ccx, 0),
+ mutbl: ast::m_imm
+ }),
+ ty::mk_int()
+ ],
+ ty::mk_ptr(tcx, ty::mt {
+ ty: param(ccx, 0),
+ mutbl: ast::m_imm
+ }))
+ }
"memcpy32" => {
(1,
~[
debug!("replace_bound_regions_in_fn_sig(self_ty=%?, fn_sig=%s, \
all_tys=%?)",
- opt_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)),
+ opt_self_ty.map(|t| ppaux::ty_to_str(tcx, *t)),
ppaux::fn_sig_to_str(tcx, fn_sig),
- all_tys.map(|&t| ppaux::ty_to_str(tcx, t)));
+ all_tys.map(|t| ppaux::ty_to_str(tcx, *t)));
let _i = indenter();
let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| {
let new_fn_sig = ty::fold_sig(fn_sig, |t| {
replace_bound_regions(tcx, isr, t)
});
- let new_self_ty = opt_self_ty.map(|&t| replace_bound_regions(tcx, isr, t));
+ let new_self_ty = opt_self_ty.map(|t| replace_bound_regions(tcx, isr, *t));
debug!("result of replace_bound_regions_in_fn_sig: \
new_self_ty=%?, \
fn_sig=%s",
- new_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)),
+ new_self_ty.map(|t| ppaux::ty_to_str(tcx, *t)),
ppaux::fn_sig_to_str(tcx, &new_fn_sig));
return (isr, new_self_ty, new_fn_sig);
// ty is the value supplied for the type parameter A...
let mut param_result = ~[];
- do ty::each_bound_trait_and_supertraits(
- tcx, type_param_bounds.trait_bounds) |trait_ref|
- {
+ do ty::each_bound_trait_and_supertraits(tcx, type_param_bounds.trait_bounds) |trait_ref| {
// ...and here trait_ref is each bound that was declared on A,
// expressed in terms of the type parameters.
let mut provided_names = HashSet::new();
// Implemented methods
- for i in range(0u, all_methods.len()) {
- provided_names.insert(all_methods[i].ident);
+ for elt in all_methods.iter() {
+ provided_names.insert(elt.ident);
}
let r = ty::trait_methods(tcx, trait_did);
trait_id: ast::NodeId)
{
let tcx = ccx.tcx;
- let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|&x| *x);
+ let region_paramd = tcx.region_paramd_items.find(&trait_id).map_move(|x| *x);
match tcx.items.get_copy(&trait_id) {
ast_map::node_item(@ast::item {
node: ast::item_trait(ref generics, _, ref ms),
pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
let tcx = ccx.tcx;
- let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
+ let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x);
debug!("convert: item %s with id %d rp %?",
tcx.sess.str_of(it.ident), it.id, rp);
match it.node {
Some(&def) => return def,
_ => {}
}
- let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
+ let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x);
match it.node {
ast::item_trait(ref generics, _, _) => {
let self_ty = ty::mk_self(tcx, def_id);
Some(&tpt) => return tpt,
_ => {}
}
- let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
+ let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x);
match it.node {
ast::item_static(ref t, _, _) => {
let typ = ccx.to_ty(&empty_rscope, t);
None => { }
}
- let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x);
+ let rp = tcx.region_paramd_items.find(&it.id).map_move(|x| *x);
let region_parameterization =
RegionParameterization::from_variance_and_generics(rp, generics);
let tpt = {
err: Option<&ty::type_err>) {
debug!("hi! expected_ty = %?, actual_ty = %s", expected_ty, actual_ty);
- let error_str = err.map_default(~"", |t_err|
- fmt!(" (%s)",
- ty::type_err_to_str(self.tcx, *t_err)));
- let resolved_expected = expected_ty.map(|&e_ty|
- { self.resolve_type_vars_if_possible(e_ty) });
- if !resolved_expected.map_default(false, |&e| { ty::type_is_error(e) }) {
+ let error_str = do err.map_move_default(~"") |t_err| {
+ fmt!(" (%s)", ty::type_err_to_str(self.tcx, t_err))
+ };
+ let resolved_expected = do expected_ty.map_move |e_ty| {
+ self.resolve_type_vars_if_possible(e_ty)
+ };
+ if !resolved_expected.map_move_default(false, |e| { ty::type_is_error(e) }) {
match resolved_expected {
None => self.tcx.sess.span_err(sp,
fmt!("%s%s", mk_msg(None, actual_ty), error_str)),
pub fn vars_created_since_snapshot(&mut self, snapshot: uint)
-> ~[RegionVid] {
do vec::build |push| {
- for i in range(snapshot, self.undo_log.len()) {
- match self.undo_log[i] {
+ for &elt in self.undo_log.slice_from(snapshot).iter() {
+ match elt {
AddVar(vid) => push(vid),
_ => ()
}
pub struct type_rscope(Option<RegionParameterization>);
impl type_rscope {
- priv fn replacement(&self) -> ty::Region {
+ fn replacement(&self) -> ty::Region {
if self.is_some() {
ty::re_bound(ty::br_self)
} else {
pub fn describe_warnings() {
use extra::sort::Sort;
- printfln!("
+ println("
Available lint options:
-W <foo> Warn about <foo>
-A <foo> Allow <foo>
fn padded(max: uint, s: &str) -> ~str {
str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s
}
- printfln!("\nAvailable lint checks:\n");
+ println("\nAvailable lint checks:\n");
printfln!(" %s %7.7s %s",
padded(max_key, "name"), "default", "meaning");
printfln!(" %s %7.7s %s\n",
}
pub fn describe_debug_flags() {
- printfln!("\nAvailable debug options:\n");
+ println("\nAvailable debug options:\n");
let r = session::debugging_opts_map();
for tuple in r.iter() {
match *tuple {
let sopts = build_session_options(binary, matches, demitter);
let sess = build_session(sopts, demitter);
- let odir = getopts::opt_maybe_str(matches, "out-dir");
- let odir = odir.map(|o| Path(*o));
- let ofile = getopts::opt_maybe_str(matches, "o");
- let ofile = ofile.map(|o| Path(*o));
+ let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
+ let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
let cfg = build_configuration(sess, binary, &input);
- let pretty = getopts::opt_default(matches, "pretty", "normal").map(
- |a| parse_pretty(sess, *a));
+ let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
+ parse_pretty(sess, a)
+ };
match pretty {
Some::<pp_mode>(ppm) => {
pretty_print_input(sess, cfg, &input, ppm);
*/
pub fn monitor(f: ~fn(diagnostic::Emitter)) {
use std::comm::*;
+
+ // XXX: This is a hack for newsched since it doesn't support split stacks.
+ // rustc needs a lot of stack!
+ static STACK_SIZE: uint = 4000000;
+
let (p, ch) = stream();
let ch = SharedChan::new(ch);
let ch_capture = ch.clone();
- match do task::try || {
+ let mut task_builder = task::task();
+ task_builder.supervised();
+ task_builder.opts.stack_size = Some(STACK_SIZE);
+ match do task_builder.try {
let ch = ch_capture.clone();
let ch_capture = ch.clone();
// The 'diagnostics emitter'. Every error, warning, etc. should
let result = result::Ok(config);
let result = do result.chain |config| {
let output_dir = getopts::opt_maybe_str(matches, opt_output_dir());
- let output_dir = output_dir.map(|s| Path(*s));
+ let output_dir = output_dir.map_move(|s| Path(s));
result::Ok(Config {
output_dir: output_dir.unwrap_or_default(config.output_dir.clone()),
.. config
};
let result = do result.chain |config| {
let output_format = getopts::opt_maybe_str(matches, opt_output_format());
- do output_format.map_default(result::Ok(config.clone())) |output_format| {
- do parse_output_format(*output_format).chain |output_format| {
+ do output_format.map_move_default(result::Ok(config.clone())) |output_format| {
+ do parse_output_format(output_format).chain |output_format| {
result::Ok(Config {
output_format: output_format,
.. config.clone()
let result = do result.chain |config| {
let output_style =
getopts::opt_maybe_str(matches, opt_output_style());
- do output_style.map_default(result::Ok(config.clone())) |output_style| {
- do parse_output_style(*output_style).chain |output_style| {
+ do output_style.map_move_default(result::Ok(config.clone())) |output_style| {
+ do parse_output_style(output_style).chain |output_style| {
result::Ok(Config {
output_style: output_style,
.. config.clone()
pub enum ItemTag {
ModTag(ModDoc),
NmodTag(NmodDoc),
- ConstTag(ConstDoc),
+ StaticTag(StaticDoc),
FnTag(FnDoc),
EnumTag(EnumDoc),
TraitTag(TraitDoc),
index: Option<Index>
}
-pub type ConstDoc = SimpleItemDoc;
+pub type StaticDoc = SimpleItemDoc;
pub type FnDoc = SimpleItemDoc;
md!(FnTag)
}
- pub fn consts(&self) -> ~[ConstDoc] {
- md!(ConstTag)
+ pub fn statics(&self) -> ~[StaticDoc] {
+ md!(StaticTag)
}
pub fn enums(&self) -> ~[EnumDoc] {
fn mods(&self) -> ~[ModDoc];
fn nmods(&self) -> ~[NmodDoc];
fn fns(&self) -> ~[FnDoc];
- fn consts(&self) -> ~[ConstDoc];
+ fn statics(&self) -> ~[StaticDoc];
fn enums(&self) -> ~[EnumDoc];
fn traits(&self) -> ~[TraitDoc];
fn impls(&self) -> ~[ImplDoc];
pu!(FnTag)
}
- fn consts(&self) -> ~[ConstDoc] {
- pu!(ConstTag)
+ fn statics(&self) -> ~[StaticDoc] {
+ pu!(StaticTag)
}
fn enums(&self) -> ~[EnumDoc] {
&doc::ModTag(ref doc) => doc.item.clone(),
&doc::NmodTag(ref doc) => doc.item.clone(),
&doc::FnTag(ref doc) => doc.item.clone(),
- &doc::ConstTag(ref doc) => doc.item.clone(),
+ &doc::StaticTag(ref doc) => doc.item.clone(),
&doc::EnumTag(ref doc) => doc.item.clone(),
&doc::TraitTag(ref doc) => doc.item.clone(),
&doc::ImplTag(ref doc) => doc.item.clone(),
))
}
ast::item_static(*) => {
- Some(doc::ConstTag(
- constdoc_from_const(ItemDoc)
+ Some(doc::StaticTag(
+ staticdoc_from_static(ItemDoc)
))
}
ast::item_enum(enum_definition, _) => {
}
}
-fn constdoc_from_const(itemdoc: doc::ItemDoc) -> doc::ConstDoc {
+fn staticdoc_from_static(itemdoc: doc::ItemDoc) -> doc::StaticDoc {
doc::SimpleItemDoc {
item: itemdoc,
sig: None
}
#[test]
- fn should_extract_const_name_and_id() {
+ fn should_extract_static_name_and_id() {
let doc = mk_doc(@"static a: int = 0;");
- assert!(doc.cratemod().consts()[0].id() != 0);
- assert!(doc.cratemod().consts()[0].name_() == ~"a");
+ assert!(doc.cratemod().statics()[0].id() != 0);
+ assert!(doc.cratemod().statics()[0].name_() == ~"a");
}
#[test]
fold_mod: FoldMod<T>,
fold_nmod: FoldNmod<T>,
fold_fn: FoldFn<T>,
- fold_const: FoldConst<T>,
+ fold_static: FoldStatic<T>,
fold_enum: FoldEnum<T>,
fold_trait: FoldTrait<T>,
fold_impl: FoldImpl<T>,
fold_mod: self.fold_mod,
fold_nmod: self.fold_nmod,
fold_fn: self.fold_fn,
- fold_const: self.fold_const,
+ fold_static: self.fold_static,
fold_enum: self.fold_enum,
fold_trait: self.fold_trait,
fold_impl: self.fold_impl,
type FoldMod<T> = @fn(fold: &Fold<T>, doc: doc::ModDoc) -> doc::ModDoc;
type FoldNmod<T> = @fn(fold: &Fold<T>, doc: doc::NmodDoc) -> doc::NmodDoc;
type FoldFn<T> = @fn(fold: &Fold<T>, doc: doc::FnDoc) -> doc::FnDoc;
-type FoldConst<T> = @fn(fold: &Fold<T>, doc: doc::ConstDoc) -> doc::ConstDoc;
+type FoldStatic<T> = @fn(fold: &Fold<T>, doc: doc::StaticDoc) -> doc::StaticDoc;
type FoldEnum<T> = @fn(fold: &Fold<T>, doc: doc::EnumDoc) -> doc::EnumDoc;
type FoldTrait<T> = @fn(fold: &Fold<T>, doc: doc::TraitDoc) -> doc::TraitDoc;
type FoldImpl<T> = @fn(fold: &Fold<T>, doc: doc::ImplDoc) -> doc::ImplDoc;
fold_mod: FoldMod<T>,
fold_nmod: FoldNmod<T>,
fold_fn: FoldFn<T>,
- fold_const: FoldConst<T>,
+ fold_static: FoldStatic<T>,
fold_enum: FoldEnum<T>,
fold_trait: FoldTrait<T>,
fold_impl: FoldImpl<T>,
fold_mod: fold_mod,
fold_nmod: fold_nmod,
fold_fn: fold_fn,
- fold_const: fold_const,
+ fold_static: fold_static,
fold_enum: fold_enum,
fold_trait: fold_trait,
fold_impl: fold_impl,
|f, d| default_any_fold_mod(f, d),
|f, d| default_any_fold_nmod(f, d),
|f, d| default_seq_fold_fn(f, d),
- |f, d| default_seq_fold_const(f, d),
+ |f, d| default_seq_fold_static(f, d),
|f, d| default_seq_fold_enum(f, d),
|f, d| default_seq_fold_trait(f, d),
|f, d| default_seq_fold_impl(f, d),
|f, d| default_seq_fold_mod(f, d),
|f, d| default_seq_fold_nmod(f, d),
|f, d| default_seq_fold_fn(f, d),
- |f, d| default_seq_fold_const(f, d),
+ |f, d| default_seq_fold_static(f, d),
|f, d| default_seq_fold_enum(f, d),
|f, d| default_seq_fold_trait(f, d),
|f, d| default_seq_fold_impl(f, d),
|f, d| default_par_fold_mod(f, d),
|f, d| default_par_fold_nmod(f, d),
|f, d| default_seq_fold_fn(f, d),
- |f, d| default_seq_fold_const(f, d),
+ |f, d| default_seq_fold_static(f, d),
|f, d| default_seq_fold_enum(f, d),
|f, d| default_seq_fold_trait(f, d),
|f, d| default_seq_fold_impl(f, d),
doc::FnTag(FnDoc) => {
doc::FnTag((fold.fold_fn)(fold, FnDoc))
}
- doc::ConstTag(ConstDoc) => {
- doc::ConstTag((fold.fold_const)(fold, ConstDoc))
+ doc::StaticTag(StaticDoc) => {
+ doc::StaticTag((fold.fold_static)(fold, StaticDoc))
}
doc::EnumTag(EnumDoc) => {
doc::EnumTag((fold.fold_enum)(fold, EnumDoc))
}
}
-pub fn default_seq_fold_const<T>(
+pub fn default_seq_fold_static<T>(
fold: &Fold<T>,
- doc: doc::ConstDoc
-) -> doc::ConstDoc {
+ doc: doc::StaticDoc
+) -> doc::StaticDoc {
doc::SimpleItemDoc {
item: (fold.fold_item)(fold, doc.item.clone()),
.. doc
}
#[test]
-fn default_fold_should_produce_same_consts() {
+fn default_fold_should_produce_same_statics() {
let source = @"static a: int = 0;";
let ast = parse::from_str(source);
let doc = extract::extract(ast, ~"");
doc::FnTag(_) => {
~"Function"
}
- doc::ConstTag(_) => {
- ~"Freeze"
+ doc::StaticTag(_) => {
+ ~"Static"
}
doc::EnumTag(_) => {
~"Enum"
doc::ModTag(ModDoc) => write_mod(ctxt, ModDoc),
doc::NmodTag(nModDoc) => write_nmod(ctxt, nModDoc),
doc::FnTag(FnDoc) => write_fn(ctxt, FnDoc),
- doc::ConstTag(ConstDoc) => write_const(ctxt, ConstDoc),
+ doc::StaticTag(StaticDoc) => write_static(ctxt, StaticDoc),
doc::EnumTag(EnumDoc) => write_enum(ctxt, EnumDoc),
doc::TraitTag(TraitDoc) => write_trait(ctxt, TraitDoc),
doc::ImplTag(ImplDoc) => write_impl(ctxt, ImplDoc),
~~~", s)
}
-fn write_const(
+fn write_static(
ctxt: &Ctxt,
- doc: doc::ConstDoc
+ doc: doc::StaticDoc
) {
write_sig(ctxt, doc.sig.clone());
write_common(ctxt, doc.desc(), doc.sections());
let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc);
write_markdown(doc, writer_factory);
// We expect two pages to have been written
- do 2.times {
+ for _ in range(0, 2u) {
po.recv();
}
}
~"#[link(name = \"core\")]; mod a { }");
let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc);
write_markdown(doc, writer_factory);
- do 2.times {
+ for _ in range(0, 2u) {
let (page, markdown) = po.recv();
match page {
doc::CratePage(_) => {
}
#[test]
- fn should_write_const_header() {
+ fn should_write_static_header() {
let markdown = render(~"static a: bool = true;");
- assert!(markdown.contains("## Freeze `a`\n\n"));
+ assert!(markdown.contains("## Static `a`\n\n"));
}
#[test]
- fn should_write_const_description() {
+ fn should_write_static_description() {
let markdown = render(
~"#[doc = \"b\"]\
static a: bool = true;");
let doc = mk_doc(
~"impl Foo {\
pub fn bar() { }\
- priv fn baz() { }\
+ fn baz() { }\
}");
assert_eq!(doc.cratemod().impls()[0].methods.len(), 1);
}
let doc = mk_doc(
~"impl Foo {\
pub fn bar() { }\
- priv fn baz() { }\
+ fn baz() { }\
}");
assert_eq!(doc.cratemod().impls()[0].methods.len(), 1);
}
let doc = mk_doc(
~"impl Foo {\
pub fn bar() { }\
- priv fn baz() { }\
+ fn baz() { }\
}");
assert_eq!(doc.cratemod().impls()[0].methods.len(), 1);
}
fn by_score(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool {
fn score(item: &doc::ItemTag) -> int {
match *item {
- doc::ConstTag(_) => 0,
+ doc::StaticTag(_) => 0,
doc::TyTag(_) => 1,
doc::EnumTag(_) => 2,
doc::StructTag(_) => 3,
let source =
~"mod imod { } \
- static iconst: int = 0; \
+ static istatic: int = 0; \
fn ifn() { } \
enum ienum { ivar } \
trait itrait { fn a(); } \
let doc = extract::from_srv(srv.clone(), ~"");
let doc = (mk_pass().f)(srv.clone(), doc);
// hidden __std_macros module at the start.
- assert_eq!(doc.cratemod().items[0].name_(), ~"iconst");
+ assert_eq!(doc.cratemod().items[0].name_(), ~"istatic");
assert_eq!(doc.cratemod().items[1].name_(), ~"itype");
assert_eq!(doc.cratemod().items[2].name_(), ~"ienum");
assert_eq!(doc.cratemod().items[3].name_(), ~"istruct");
let fold = Fold {
ctxt: srv.clone(),
fold_fn: fold_fn,
- fold_const: fold_const,
+ fold_static: fold_static,
fold_enum: fold_enum,
fold_trait: fold_trait,
fold_impl: fold_impl,
}
}
-fn fold_const(
+fn fold_static(
fold: &fold::Fold<astsrv::Srv>,
- doc: doc::ConstDoc
-) -> doc::ConstDoc {
+ doc: doc::StaticDoc
+) -> doc::StaticDoc {
let srv = fold.ctxt.clone();
doc::SimpleItemDoc {
}, _) => {
pprust::ty_to_str(ty, extract::interner())
}
- _ => fail!("fold_const: id not bound to a const item")
+ _ => fail!("fold_static: id not bound to a static item")
}
}}),
.. doc
}, _) => {
let bounds = pprust::generics_to_str(generics, extract::interner());
let bounds = if bounds.is_empty() { None } else { Some(bounds) };
- let trait_types = opt_trait_type.map_default(~[], |p| {
+ let trait_types = do opt_trait_type.map_default(~[]) |p| {
~[pprust::path_to_str(&p.path, extract::interner())]
- });
+ };
(bounds,
trait_types,
Some(pprust::ty_to_str(
}
#[test]
- fn should_add_const_types() {
+ fn should_add_static_types() {
let doc = mk_doc(~"static a: bool = true;");
- assert!(doc.cratemod().consts()[0].sig == Some(~"bool"));
+ assert!(doc.cratemod().statics()[0].sig == Some(~"bool"));
}
#[test]
}
}
}
- result = do blk.expr.map_consume |e| {
+ result = do blk.expr.map_move |e| {
do with_pp(intr) |pp, _| { pprust::print_expr(pp, e); }
};
}
}
fn run_program(_: &str) {}
+ #[ignore]
#[test]
fn super_basic() {
run_program("");
}
+ #[ignore]
#[test]
fn regression_5937() {
run_program("use std::hashmap;");
}
+ #[ignore]
#[test]
fn regression_5784() {
run_program("let a = 3;");
");
}
+ #[ignore]
#[test]
fn inferred_integers_usable() {
run_program("let a = 2;\n()\n");
");
}
+ #[ignore]
#[test]
fn local_variables_allow_shadowing() {
run_program("
");
}
+ #[ignore]
#[test]
fn string_usable() {
run_program("
");
}
+ #[ignore]
#[test]
fn vectors_usable() {
run_program("
");
}
+ #[ignore]
#[test]
fn structs_usable() {
run_program("
");
}
+ #[ignore]
#[test]
fn mutable_variables_work() {
run_program("
");
}
+ #[ignore]
#[test]
fn functions_saved() {
run_program("
");
}
+ #[ignore]
#[test]
fn modules_saved() {
run_program("
");
}
+ #[ignore]
#[test]
fn multiple_functions() {
run_program("
");
}
+ #[ignore]
#[test]
fn multiple_items_same_name() {
run_program("
");
}
+ #[ignore]
#[test]
fn simultaneous_definition_and_expression() {
run_program("
");
}
+ #[ignore]
#[test]
fn exit_quits() {
let mut r = repl();
}
#[test]
+#[ignore(reason = "test not yet implemented")]
fn test_uninstall() {
let workspace = create_local_package(&PkgId::new("foo", &os::getcwd()));
let _output = command_line_test([~"info", ~"foo"], &workspace);
use clone::Clone;
use container::Container;
-use iterator::{Iterator, range};
+use iterator::Iterator;
use option::{Option, Some, None};
use sys;
use unstable::raw::Repr;
for x in lhs.iter() {
push((*x).clone());
}
- for i in range(0u, rhs.len()) {
- push(rhs[i].clone());
+ for elt in rhs.iter() {
+ push(elt.clone());
}
}
}
*(*self) > *(*other)
}
}
+
+#[cfg(not(test))]
+impl<'self, T: TotalOrd> TotalOrd for &'self T {
+ #[inline]
+ fn cmp(&self, other: & &'self T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<'self, T: TotalEq> TotalEq for &'self T {
+ #[inline]
+ fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) }
+}
Return `o1` if it is not `Equal`, otherwise `o2`. Simulates the
lexical ordering on a type `(int, int)`.
*/
-// used in deriving code in libsyntax
#[inline]
pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering {
match o1 {
#[allow(non_camel_case_types)]
pub mod oneshot {
- priv use std::kinds::Send;
+ use std::kinds::Send;
use ptr::to_mut_unsafe_ptr;
pub fn init<T: Send>() -> (server::Oneshot<T>, client::Oneshot<T>) {
#[allow(non_camel_case_types)]
pub mod client {
- priv use std::kinds::Send;
+ use std::kinds::Send;
#[allow(non_camel_case_types)]
pub fn try_send<T: Send>(pipe: Oneshot<T>, x_0: T) ->
#[allow(non_camel_case_types)]
pub mod streamp {
- priv use std::kinds::Send;
+ use std::kinds::Send;
pub fn init<T: Send>() -> (server::Open<T>, client::Open<T>) {
pub use std::pipes::HasBuffer;
#[allow(non_camel_case_types)]
pub mod client {
- priv use std::kinds::Send;
+ use std::kinds::Send;
#[allow(non_camel_case_types)]
pub fn try_data<T: Send>(pipe: Open<T>, x_0: T) ->
use vec::{OwnedVector, ImmutableVector};
/// `Either` is a type that represents one of two alternatives
-#[deriving(Clone, Eq)]
+#[deriving(Clone, Eq, IterBytes)]
pub enum Either<L, R> {
Left(L),
Right(R)
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::*;
+
+use cast;
+use int;
+use rt::io::Decorator;
+use rt::io::mem::MemWriter;
+use rt::io;
+use str;
+use sys;
+use uint;
+use util;
+use vec;
+
+pub mod parse;
+pub mod rt;
+
+/// A struct to represent both where to emit formatting strings to and how they
+/// should be formatted. A mutable version of this is passed to all formatting
+/// traits.
+pub struct Formatter<'self> {
+ /// Flags for formatting (packed version of rt::Flag)
+ flags: uint,
+ /// Character used as 'fill' whenever there is alignment
+ fill: char,
+ /// Boolean indication of whether the output should be left-aligned
+ alignleft: bool,
+ /// Optionally specified integer width that the output should be
+ width: Option<uint>,
+ /// Optionally specified precision for numeric types
+ precision: Option<uint>,
+
+ /// Output buffer.
+ buf: &'self mut io::Writer,
+
+ priv curarg: vec::VecIterator<'self, Argument<'self>>,
+ priv args: &'self [Argument<'self>],
+}
+
+/// This struct represents the generic "argument" which is taken by the Xprintf
+/// family of functions. It contains a function to format the given value. At
+/// compile time it is ensured that the function and the value have the correct
+/// types, and then this struct is used to canonicalize arguments to one type.
+pub struct Argument<'self> {
+ priv formatter: extern "Rust" fn(&util::Void, &mut Formatter),
+ priv value: &'self util::Void,
+}
+
+#[allow(missing_doc)]
+pub trait Bool { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait Char { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait Signed { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait Unsigned { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait Octal { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait Binary { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait LowerHex { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait UpperHex { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait String { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait Poly { fn fmt(&Self, &mut Formatter); }
+#[allow(missing_doc)]
+pub trait Pointer { fn fmt(&Self, &mut Formatter); }
+
+/// The sprintf function takes a precompiled format string and a list of
+/// arguments, to return the resulting formatted string.
+///
+/// This is currently an unsafe function because the types of all arguments
+/// aren't verified by immediate callers of this function. This currently does
+/// not validate that the correct types of arguments are specified for each
+/// format specifier, nor that each argument itself contains the right function
+/// for formatting the right type value. Because of this, the function is marked
+/// as `unsafe` if this is being called manually.
+///
+/// Thankfully the rust compiler provides the macro `ifmt!` which will perform
+/// all of this validation at compile-time and provides a safe interface for
+/// invoking this function.
+///
+/// # Arguments
+///
+/// * fmts - the precompiled format string to emit.
+/// * args - the list of arguments to the format string. These are only the
+/// positional arguments (not named)
+///
+/// Note that this function assumes that there are enough arguments for the
+/// format string.
+pub unsafe fn sprintf(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
+ let output = MemWriter::new();
+ {
+ let mut formatter = Formatter {
+ flags: 0,
+ width: None,
+ precision: None,
+ // FIXME(#8248): shouldn't need a transmute
+ buf: cast::transmute(&output as &io::Writer),
+ alignleft: false,
+ fill: ' ',
+ args: args,
+ curarg: args.iter(),
+ };
+ for piece in fmt.iter() {
+ formatter.run(piece, None);
+ }
+ }
+ return str::from_bytes_owned(output.inner());
+}
+
+impl<'self> Formatter<'self> {
+ fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) {
+ let setcount = |slot: &mut Option<uint>, cnt: &parse::Count| {
+ match *cnt {
+ parse::CountIs(n) => { *slot = Some(n); }
+ parse::CountImplied => { *slot = None; }
+ parse::CountIsParam(i) => {
+ let v = self.args[i].value;
+ unsafe { *slot = Some(*(v as *util::Void as *uint)); }
+ }
+ parse::CountIsNextParam => {
+ let v = self.curarg.next().unwrap().value;
+ unsafe { *slot = Some(*(v as *util::Void as *uint)); }
+ }
+ }
+ };
+
+ match *piece {
+ rt::String(s) => { self.buf.write(s.as_bytes()); }
+ rt::CurrentArgument(()) => { self.buf.write(cur.unwrap().as_bytes()); }
+ rt::Argument(ref arg) => {
+ // Fill in the format parameters into the formatter
+ self.fill = arg.format.fill;
+ self.alignleft = arg.format.alignleft;
+ self.flags = arg.format.flags;
+ setcount(&mut self.width, &arg.format.width);
+ setcount(&mut self.precision, &arg.format.precision);
+
+ // Extract the correct argument
+ let value = match arg.position {
+ rt::ArgumentNext => { *self.curarg.next().unwrap() }
+ rt::ArgumentIs(i) => self.args[i],
+ };
+
+ // Then actually do some printing
+ match arg.method {
+ None => { (value.formatter)(value.value, self); }
+ Some(ref method) => { self.execute(*method, value); }
+ }
+ }
+ }
+ }
+
+ fn execute(&mut self, method: &rt::Method, arg: Argument) {
+ match *method {
+ // Pluralization is selection upon a numeric value specified as the
+ // parameter.
+ rt::Plural(offset, ref selectors, ref default) => {
+ // This is validated at compile-time to be a pointer to a
+ // '&uint' value.
+ let value: &uint = unsafe { cast::transmute(arg.value) };
+ let value = *value;
+
+ // First, attempt to match against explicit values without the
+ // offsetted value
+ for s in selectors.iter() {
+ match s.selector {
+ Right(val) if value == val => {
+ return self.runplural(value, s.result);
+ }
+ _ => {}
+ }
+ }
+
+ // Next, offset the value and attempt to match against the
+ // keyword selectors.
+ let value = value - match offset { Some(i) => i, None => 0 };
+ for s in selectors.iter() {
+ let run = match s.selector {
+ Left(parse::Zero) => value == 0,
+ Left(parse::One) => value == 1,
+ Left(parse::Two) => value == 2,
+
+ // XXX: Few/Many should have a user-specified boundary
+ // One possible option would be in the function
+ // pointer of the 'arg: Argument' struct.
+ Left(parse::Few) => value < 8,
+ Left(parse::Many) => value >= 8,
+
+ Right(*) => false
+ };
+ if run {
+ return self.runplural(value, s.result);
+ }
+ }
+
+ self.runplural(value, *default);
+ }
+
+ // Select is just a matching against the string specified.
+ rt::Select(ref selectors, ref default) => {
+ // This is validated at compile-time to be a pointer to a
+ // string slice,
+ let value: & &str = unsafe { cast::transmute(arg.value) };
+ let value = *value;
+
+ for s in selectors.iter() {
+ if s.selector == value {
+ for piece in s.result.iter() {
+ self.run(piece, Some(value));
+ }
+ return;
+ }
+ }
+ for piece in default.iter() {
+ self.run(piece, Some(value));
+ }
+ }
+ }
+ }
+
+ fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) {
+ do uint::to_str_bytes(value, 10) |buf| {
+ let valuestr = str::from_bytes_slice(buf);
+ for piece in pieces.iter() {
+ self.run(piece, Some(valuestr));
+ }
+ }
+ }
+}
+
+/// This is a function which calls are emitted to by the compiler itself to
+/// create the Argument structures that are passed into the `sprintf` function.
+#[doc(hidden)]
+pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter),
+ t: &'a T) -> Argument<'a> {
+ unsafe {
+ Argument {
+ formatter: cast::transmute(f),
+ value: cast::transmute(t)
+ }
+ }
+}
+
+/// When the compiler determines that the type of an argument *must* be a string
+/// (such as for select), then it invokes this method.
+#[doc(hidden)]
+pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> {
+ argument(String::fmt, s)
+}
+
+/// When the compiler determines that the type of an argument *must* be a uint
+/// (such as for plural), then it invokes this method.
+#[doc(hidden)]
+pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
+ argument(Unsigned::fmt, s)
+}
+
+// Implementations of the core formatting traits
+
+impl Bool for bool {
+ fn fmt(b: &bool, f: &mut Formatter) {
+ String::fmt(&(if *b {"true"} else {"false"}), f);
+ }
+}
+
+impl<'self> String for &'self str {
+ fn fmt(s: & &'self str, f: &mut Formatter) {
+ // XXX: formatting args
+ f.buf.write(s.as_bytes())
+ }
+}
+
+impl Char for char {
+ fn fmt(c: &char, f: &mut Formatter) {
+ // XXX: formatting args
+ // XXX: shouldn't require an allocation
+ let mut s = ~"";
+ s.push_char(*c);
+ f.buf.write(s.as_bytes());
+ }
+}
+
+impl Signed for int {
+ fn fmt(c: &int, f: &mut Formatter) {
+ // XXX: formatting args
+ do int::to_str_bytes(*c, 10) |buf| {
+ f.buf.write(buf);
+ }
+ }
+}
+
+impl Unsigned for uint {
+ fn fmt(c: &uint, f: &mut Formatter) {
+ // XXX: formatting args
+ do uint::to_str_bytes(*c, 10) |buf| {
+ f.buf.write(buf);
+ }
+ }
+}
+
+impl Octal for uint {
+ fn fmt(c: &uint, f: &mut Formatter) {
+ // XXX: formatting args
+ do uint::to_str_bytes(*c, 8) |buf| {
+ f.buf.write(buf);
+ }
+ }
+}
+
+impl LowerHex for uint {
+ fn fmt(c: &uint, f: &mut Formatter) {
+ // XXX: formatting args
+ do uint::to_str_bytes(*c, 16) |buf| {
+ f.buf.write(buf);
+ }
+ }
+}
+
+impl UpperHex for uint {
+ fn fmt(c: &uint, f: &mut Formatter) {
+ // XXX: formatting args
+ do uint::to_str_bytes(*c, 16) |buf| {
+ let mut local = [0u8, ..16];
+ for (l, &b) in local.mut_iter().zip(buf.iter()) {
+ *l = match b as char {
+ 'a' .. 'f' => (b - 'a' as u8) + 'A' as u8,
+ _ => b,
+ };
+ }
+ f.buf.write(local.slice_to(buf.len()));
+ }
+ }
+}
+
+impl<T> Poly for T {
+ fn fmt(t: &T, f: &mut Formatter) {
+ // XXX: formatting args
+ let s = sys::log_str(t);
+ f.buf.write(s.as_bytes());
+ }
+}
+
+// n.b. use 'const' to get an implementation for both '*mut' and '*' at the same
+// time.
+impl<T> Pointer for *const T {
+ fn fmt(t: &*const T, f: &mut Formatter) {
+ // XXX: formatting args
+ f.buf.write("0x".as_bytes());
+ LowerHex::fmt(&(*t as uint), f);
+ }
+}
+
+// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
+// it's a lot easier than creating all of the rt::Piece structures here.
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::*;
+
+use char;
+use str;
+use iterator;
+
+condition! { pub parse_error: ~str -> (); }
+
+/// A piece is a portion of the format string which represents the next part to
+/// emit. These are emitted as a stream by the `Parser` class.
+#[deriving(Eq)]
+pub enum Piece<'self> {
+ /// A literal string which should directly be emitted
+ String(&'self str),
+ /// A back-reference to whatever the current argument is. This is used
+ /// inside of a method call to refer back to the original argument.
+ CurrentArgument,
+ /// This describes that formatting should process the next argument (as
+ /// specified inside) for emission.
+ Argument(Argument<'self>),
+}
+
+/// Representation of an argument specification.
+#[deriving(Eq)]
+pub struct Argument<'self> {
+ /// Where to find this argument
+ position: Position<'self>,
+ /// How to format the argument
+ format: FormatSpec<'self>,
+ /// If not `None`, what method to invoke on the argument
+ method: Option<~Method<'self>>
+}
+
+/// Specification for the formatting of an argument in the format string.
+#[deriving(Eq)]
+pub struct FormatSpec<'self> {
+ /// Optionally specified character to fill alignment with
+ fill: Option<char>,
+ /// Optionally specified alignment
+ align: Option<Alignment>,
+ /// Packed version of various flags provided
+ flags: uint,
+ /// The integer precision to use
+ precision: Count,
+ /// The string width requested for the resulting format
+ width: Count,
+ /// The descriptor string representing the name of the format desired for
+ /// this argument, this can be empty or any number of characters, although
+ /// it is required to be one word.
+ ty: &'self str
+}
+
+/// Enum describing where an argument for a format can be located.
+#[deriving(Eq)]
+pub enum Position<'self> {
+ ArgumentNext, ArgumentIs(uint), ArgumentNamed(&'self str)
+}
+
+/// Enum of alignments which are supoprted.
+#[deriving(Eq)]
+pub enum Alignment { AlignLeft, AlignRight }
+
+/// Various flags which can be applied to format strings, the meaning of these
+/// flags is defined by the formatters themselves.
+#[deriving(Eq)]
+pub enum Flag {
+ FlagSignPlus,
+ FlagSignMinus,
+ FlagAlternate,
+}
+
+/// A count is used for the precision and width parameters of an integer, and
+/// can reference either an argument or a literal integer.
+#[deriving(Eq)]
+pub enum Count {
+ CountIs(uint),
+ CountIsParam(uint),
+ CountIsNextParam,
+ CountImplied,
+}
+
+/// Enum describing all of the possible methods which the formatting language
+/// currently supports.
+#[deriving(Eq)]
+pub enum Method<'self> {
+ /// A plural method selects on an integer over a list of either integer or
+ /// keyword-defined clauses. The meaning of the keywords is defined by the
+ /// current locale.
+ ///
+ /// An offset is optionally present at the beginning which is used to match
+ /// against keywords, but it is not matched against the literal integers.
+ ///
+ /// The final element of this enum is the default "other" case which is
+ /// always required to be specified.
+ Plural(Option<uint>, ~[PluralArm<'self>], ~[Piece<'self>]),
+
+ /// A select method selects over a string. Each arm is a different string
+ /// which can be selected for.
+ ///
+ /// As with `Plural`, a default "other" case is required as well.
+ Select(~[SelectArm<'self>], ~[Piece<'self>]),
+}
+
+/// Structure representing one "arm" of the `plural` function.
+#[deriving(Eq)]
+pub struct PluralArm<'self> {
+ /// A selector can either be specified by a keyword or with an integer
+ /// literal.
+ selector: Either<PluralKeyword, uint>,
+ /// Array of pieces which are the format of this arm
+ result: ~[Piece<'self>],
+}
+
+/// Enum of the 5 CLDR plural keywords. There is one more, "other", but that is
+/// specially placed in the `Plural` variant of `Method`
+///
+/// http://www.icu-project.org/apiref/icu4c/classicu_1_1PluralRules.html
+#[deriving(Eq, IterBytes)]
+pub enum PluralKeyword {
+ Zero, One, Two, Few, Many
+}
+
+/// Structure representing one "arm" of the `select` function.
+#[deriving(Eq)]
+pub struct SelectArm<'self> {
+ /// String selector which guards this arm
+ selector: &'self str,
+ /// Array of pieces which are the format of this arm
+ result: ~[Piece<'self>],
+}
+
+/// The parser structure for interpreting the input format string. This is
+/// modelled as an iterator over `Piece` structures to form a stream of tokens
+/// being output.
+///
+/// This is a recursive-descent parser for the sake of simplicity, and if
+/// necessary there's probably lots of room for improvement performance-wise.
+pub struct Parser<'self> {
+ priv input: &'self str,
+ priv cur: str::CharOffsetIterator<'self>,
+}
+
+impl<'self> iterator::Iterator<Piece<'self>> for Parser<'self> {
+ fn next(&mut self) -> Option<Piece<'self>> {
+ match self.cur.clone().next() {
+ Some((_, '#')) => { self.cur.next(); Some(CurrentArgument) }
+ Some((_, '{')) => {
+ self.cur.next();
+ let ret = Some(Argument(self.argument()));
+ if !self.consume('}') {
+ self.err(~"unterminated format string");
+ }
+ ret
+ }
+ Some((pos, '\\')) => {
+ self.cur.next();
+ self.escape(); // ensure it's a valid escape sequence
+ Some(String(self.string(pos + 1))) // skip the '\' character
+ }
+ Some((_, '}')) | None => { None }
+ Some((pos, _)) => {
+ Some(String(self.string(pos)))
+ }
+ }
+ }
+}
+
+impl<'self> Parser<'self> {
+ /// Creates a new parser for the given format string
+ pub fn new<'a>(s: &'a str) -> Parser<'a> {
+ Parser {
+ input: s,
+ cur: s.char_offset_iter(),
+ }
+ }
+
+ /// Notifies of an error. The message doesn't actually need to be of type
+ /// ~str, but I think it does when this eventually uses conditions so it
+ /// might as well start using it now.
+ fn err(&self, msg: ~str) {
+ parse_error::cond.raise(msg);
+ }
+
+ /// Optionally consumes the specified character. If the character is not at
+ /// the current position, then the current iterator isn't moved and false is
+ /// returned, otherwise the character is consumed and true is returned.
+ fn consume(&mut self, c: char) -> bool {
+ match self.cur.clone().next() {
+ Some((_, maybe)) if c == maybe => {
+ self.cur.next();
+ true
+ }
+ Some(*) | None => false,
+ }
+ }
+
+ /// Attempts to consume any amount of whitespace followed by a character
+ fn wsconsume(&mut self, c: char) -> bool {
+ self.ws(); self.consume(c)
+ }
+
+ /// Consumes all whitespace characters until the first non-whitespace
+ /// character
+ fn ws(&mut self) {
+ loop {
+ match self.cur.clone().next() {
+ Some((_, c)) if char::is_whitespace(c) => { self.cur.next(); }
+ Some(*) | None => { return }
+ }
+ }
+ }
+
+ /// Consumes an escape sequence, failing if there is not a valid character
+ /// to be escaped.
+ fn escape(&mut self) -> char {
+ match self.cur.next() {
+ Some((_, c @ '#')) | Some((_, c @ '{')) |
+ Some((_, c @ '\\')) | Some((_, c @ '}')) => { c }
+ Some((_, c)) => {
+ self.err(fmt!("invalid escape character `%c`", c));
+ c
+ }
+ None => {
+ self.err(~"expected an escape sequence, but format string was \
+ terminated");
+ ' '
+ }
+ }
+ }
+
+ /// Parses all of a string which is to be considered a "raw literal" in a
+ /// format string. This is everything outside of the braces.
+ fn string(&mut self, start: uint) -> &'self str {
+ loop {
+ // we may not consume the character, so clone the iterator
+ match self.cur.clone().next() {
+ Some((pos, '\\')) | Some((pos, '#')) |
+ Some((pos, '}')) | Some((pos, '{')) => {
+ return self.input.slice(start, pos);
+ }
+ Some(*) => { self.cur.next(); }
+ None => {
+ self.cur.next();
+ return self.input.slice(start, self.input.len());
+ }
+ }
+ }
+ }
+
+ /// Parses an Argument structure, or what's contained within braces inside
+ /// the format string
+ fn argument(&mut self) -> Argument<'self> {
+ Argument {
+ position: self.position(),
+ format: self.format(),
+ method: self.method(),
+ }
+ }
+
+ /// Parses a positional argument for a format. This could either be an
+ /// integer index of an argument, a named argument, or a blank string.
+ fn position(&mut self) -> Position<'self> {
+ match self.integer() {
+ Some(i) => { ArgumentIs(i) }
+ None => {
+ match self.cur.clone().next() {
+ Some((_, c)) if char::is_alphabetic(c) => {
+ ArgumentNamed(self.word())
+ }
+ _ => ArgumentNext
+ }
+ }
+ }
+ }
+
+ /// Parses a format specifier at the current position, returning all of the
+ /// relevant information in the FormatSpec struct.
+ fn format(&mut self) -> FormatSpec<'self> {
+ let mut spec = FormatSpec {
+ fill: None,
+ align: None,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: self.input.slice(0, 0),
+ };
+ if !self.consume(':') { return spec }
+
+ // fill character
+ match self.cur.clone().next() {
+ Some((_, c)) => {
+ match self.cur.clone().skip(1).next() {
+ Some((_, '>')) | Some((_, '<')) => {
+ spec.fill = Some(c);
+ self.cur.next();
+ }
+ Some(*) | None => {}
+ }
+ }
+ None => {}
+ }
+ // Alignment
+ if self.consume('<') {
+ spec.align = Some(AlignLeft);
+ } else if self.consume('>') {
+ spec.align = Some(AlignRight);
+ }
+ // Sign flags
+ if self.consume('+') {
+ spec.flags |= 1 << (FlagSignPlus as uint);
+ } else if self.consume('-') {
+ spec.flags |= 1 << (FlagSignMinus as uint);
+ }
+ // Alternate marker
+ if self.consume('#') {
+ spec.flags |= 1 << (FlagAlternate as uint);
+ }
+ // Width and precision
+ spec.width = self.count();
+ if self.consume('.') {
+ if self.consume('*') {
+ spec.precision = CountIsNextParam;
+ } else {
+ spec.precision = self.count();
+ }
+ }
+ // Finally the actual format specifier
+ spec.ty = self.word();
+ return spec;
+ }
+
+ /// Parses a method to be applied to the previously specified argument and
+ /// its format. The two current supported methods are 'plural' and 'select'
+ fn method(&mut self) -> Option<~Method<'self>> {
+ if !self.wsconsume(',') {
+ return None;
+ }
+ self.ws();
+ match self.word() {
+ "select" => {
+ if !self.wsconsume(',') {
+ self.err(~"`select` must be followed by `,`");
+ }
+ Some(self.select())
+ }
+ "plural" => {
+ if !self.wsconsume(',') {
+ self.err(~"`plural` must be followed by `,`");
+ }
+ Some(self.plural())
+ }
+ "" => {
+ self.err(~"expected method after comma");
+ return None;
+ }
+ method => {
+ self.err(fmt!("unknown method: `%s`", method));
+ return None;
+ }
+ }
+ }
+
+ /// Parses a 'select' statement (after the initial 'select' word)
+ fn select(&mut self) -> ~Method<'self> {
+ let mut other = None;
+ let mut arms = ~[];
+ // Consume arms one at a time
+ loop {
+ self.ws();
+ let selector = self.word();
+ if selector == "" {
+ self.err(~"cannot have an empty selector");
+ break
+ }
+ if !self.wsconsume('{') {
+ self.err(~"selector must be followed by `{`");
+ }
+ let pieces = self.collect();
+ if !self.wsconsume('}') {
+ self.err(~"selector case must be terminated by `}`");
+ }
+ if selector == "other" {
+ if !other.is_none() {
+ self.err(~"multiple `other` statements in `select");
+ }
+ other = Some(pieces);
+ } else {
+ arms.push(SelectArm { selector: selector, result: pieces });
+ }
+ self.ws();
+ match self.cur.clone().next() {
+ Some((_, '}')) => { break }
+ Some(*) | None => {}
+ }
+ }
+ // The "other" selector must be present
+ let other = match other {
+ Some(arm) => { arm }
+ None => {
+ self.err(~"`select` statement must provide an `other` case");
+ ~[]
+ }
+ };
+ ~Select(arms, other)
+ }
+
+ /// Parses a 'plural' statement (after the initial 'plural' word)
+ fn plural(&mut self) -> ~Method<'self> {
+ let mut offset = None;
+ let mut other = None;
+ let mut arms = ~[];
+
+ // First, attempt to parse the 'offset:' field. We know the set of
+ // selector words which can appear in plural arms, and the only ones
+ // which start with 'o' are "other" and "offset", hence look two
+ // characters deep to see if we can consume the word "offset"
+ self.ws();
+ let mut it = self.cur.clone();
+ match it.next() {
+ Some((_, 'o')) => {
+ match it.next() {
+ Some((_, 'f')) => {
+ let word = self.word();
+ if word != "offset" {
+ self.err(fmt!("expected `offset`, found `%s`",
+ word));
+ } else {
+ if !self.consume(':') {
+ self.err(~"`offset` must be followed by `:`");
+ }
+ match self.integer() {
+ Some(i) => { offset = Some(i); }
+ None => {
+ self.err(~"offset must be an integer");
+ }
+ }
+ }
+ }
+ Some(*) | None => {}
+ }
+ }
+ Some(*) | None => {}
+ }
+
+ // Next, generate all the arms
+ loop {
+ let mut isother = false;
+ let selector = if self.wsconsume('=') {
+ match self.integer() {
+ Some(i) => Right(i),
+ None => {
+ self.err(~"plural `=` selectors must be followed by an \
+ integer");
+ Right(0)
+ }
+ }
+ } else {
+ let word = self.word();
+ match word {
+ "other" => { isother = true; Left(Zero) }
+ "zero" => Left(Zero),
+ "one" => Left(One),
+ "two" => Left(Two),
+ "few" => Left(Few),
+ "many" => Left(Many),
+ word => {
+ self.err(fmt!("unexpected plural selector `%s`", word));
+ if word == "" {
+ break
+ } else {
+ Left(Zero)
+ }
+ }
+ }
+ };
+ if !self.wsconsume('{') {
+ self.err(~"selector must be followed by `{`");
+ }
+ let pieces = self.collect();
+ if !self.wsconsume('}') {
+ self.err(~"selector case must be terminated by `}`");
+ }
+ if isother {
+ if !other.is_none() {
+ self.err(~"multiple `other` statements in `select");
+ }
+ other = Some(pieces);
+ } else {
+ arms.push(PluralArm { selector: selector, result: pieces });
+ }
+ self.ws();
+ match self.cur.clone().next() {
+ Some((_, '}')) => { break }
+ Some(*) | None => {}
+ }
+ }
+
+ let other = match other {
+ Some(arm) => { arm }
+ None => {
+ self.err(~"`plural` statement must provide an `other` case");
+ ~[]
+ }
+ };
+ ~Plural(offset, arms, other)
+ }
+
+ /// Parses a Count parameter at the current position. This does not check
+ /// for 'CountIsNextParam' because that is only used in precision, not
+ /// width.
+ fn count(&mut self) -> Count {
+ match self.integer() {
+ Some(i) => {
+ if self.consume('$') {
+ CountIsParam(i)
+ } else {
+ CountIs(i)
+ }
+ }
+ None => { CountImplied }
+ }
+ }
+
+ /// Parses a word starting at the current position. A word is considered to
+ /// be an alphabetic character followed by any number of alphanumeric
+ /// characters.
+ fn word(&mut self) -> &'self str {
+ let start = match self.cur.clone().next() {
+ Some((pos, c)) if char::is_alphabetic(c) => {
+ self.cur.next();
+ pos
+ }
+ Some(*) | None => { return self.input.slice(0, 0); }
+ };
+ let mut end;
+ loop {
+ match self.cur.clone().next() {
+ Some((_, c)) if char::is_alphanumeric(c) => {
+ self.cur.next();
+ }
+ Some((pos, _)) => { end = pos; break }
+ None => { end = self.input.len(); break }
+ }
+ }
+ self.input.slice(start, end)
+ }
+
+ /// Optionally parses an integer at the current position. This doesn't deal
+ /// with overflow at all, it's just accumulating digits.
+ fn integer(&mut self) -> Option<uint> {
+ let mut cur = 0;
+ let mut found = false;
+ loop {
+ match self.cur.clone().next() {
+ Some((_, c)) => {
+ match char::to_digit(c, 10) {
+ Some(i) => {
+ cur = cur * 10 + i;
+ found = true;
+ self.cur.next();
+ }
+ None => { break }
+ }
+ }
+ None => { break }
+ }
+ }
+ if found {
+ return Some(cur);
+ } else {
+ return None;
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use prelude::*;
+ use realstd::fmt::{String};
+
+ fn same(fmt: &'static str, p: ~[Piece<'static>]) {
+ let mut parser = Parser::new(fmt);
+ assert_eq!(p, parser.collect());
+ }
+
+ fn fmtdflt() -> FormatSpec<'static> {
+ return FormatSpec {
+ fill: None,
+ align: None,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ }
+ }
+
+ fn musterr(s: &str) {
+ Parser::new(s).next();
+ }
+
+ #[test]
+ fn simple() {
+ same("asdf", ~[String("asdf")]);
+ same("a\\{b", ~[String("a"), String("{b")]);
+ same("a\\#b", ~[String("a"), String("#b")]);
+ same("a\\}b", ~[String("a"), String("}b")]);
+ same("a\\}", ~[String("a"), String("}")]);
+ same("\\}", ~[String("}")]);
+ }
+
+ #[test] #[should_fail] fn invalid01() { musterr("{") }
+ #[test] #[should_fail] fn invalid02() { musterr("\\") }
+ #[test] #[should_fail] fn invalid03() { musterr("\\a") }
+ #[test] #[should_fail] fn invalid04() { musterr("{3a}") }
+ #[test] #[should_fail] fn invalid05() { musterr("{:|}") }
+ #[test] #[should_fail] fn invalid06() { musterr("{:>>>}") }
+
+ #[test]
+ fn format_nothing() {
+ same("{}", ~[Argument(Argument {
+ position: ArgumentNext,
+ format: fmtdflt(),
+ method: None,
+ })]);
+ }
+ #[test]
+ fn format_position() {
+ same("{3}", ~[Argument(Argument {
+ position: ArgumentIs(3),
+ format: fmtdflt(),
+ method: None,
+ })]);
+ }
+ #[test]
+ fn format_position_nothing_else() {
+ same("{3:}", ~[Argument(Argument {
+ position: ArgumentIs(3),
+ format: fmtdflt(),
+ method: None,
+ })]);
+ }
+ #[test]
+ fn format_type() {
+ same("{3:a}", ~[Argument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: None,
+ align: None,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "a",
+ },
+ method: None,
+ })]);
+ }
+ #[test]
+ fn format_align_fill() {
+ same("{3:>}", ~[Argument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: None,
+ align: Some(AlignRight),
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ method: None,
+ })]);
+ same("{3:0<}", ~[Argument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: Some('0'),
+ align: Some(AlignLeft),
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ method: None,
+ })]);
+ same("{3:*<abcd}", ~[Argument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: Some('*'),
+ align: Some(AlignLeft),
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "abcd",
+ },
+ method: None,
+ })]);
+ }
+ #[test]
+ fn format_counts() {
+ same("{:10s}", ~[Argument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: None,
+ flags: 0,
+ precision: CountImplied,
+ width: CountIs(10),
+ ty: "s",
+ },
+ method: None,
+ })]);
+ same("{:10$.10s}", ~[Argument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: None,
+ flags: 0,
+ precision: CountIs(10),
+ width: CountIsParam(10),
+ ty: "s",
+ },
+ method: None,
+ })]);
+ same("{:.*s}", ~[Argument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: None,
+ flags: 0,
+ precision: CountIsNextParam,
+ width: CountImplied,
+ ty: "s",
+ },
+ method: None,
+ })]);
+ same("{:.10$s}", ~[Argument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: None,
+ flags: 0,
+ precision: CountIsParam(10),
+ width: CountImplied,
+ ty: "s",
+ },
+ method: None,
+ })]);
+ }
+ #[test]
+ fn format_flags() {
+ same("{:-}", ~[Argument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: None,
+ flags: (1 << FlagSignMinus as uint),
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ method: None,
+ })]);
+ same("{:+#}", ~[Argument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: None,
+ flags: (1 << FlagSignPlus as uint) | (1 << FlagAlternate as uint),
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ method: None,
+ })]);
+ }
+ #[test]
+ fn format_mixture() {
+ same("abcd {3:a} efg", ~[String("abcd "), Argument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: None,
+ align: None,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "a",
+ },
+ method: None,
+ }), String(" efg")]);
+ }
+
+ #[test]
+ fn select_simple() {
+ same("{, select, other { haha } }", ~[Argument(Argument{
+ position: ArgumentNext,
+ format: fmtdflt(),
+ method: Some(~Select(~[], ~[String(" haha ")]))
+ })]);
+ same("{1, select, other { haha } }", ~[Argument(Argument{
+ position: ArgumentIs(1),
+ format: fmtdflt(),
+ method: Some(~Select(~[], ~[String(" haha ")]))
+ })]);
+ same("{1, select, other {#} }", ~[Argument(Argument{
+ position: ArgumentIs(1),
+ format: fmtdflt(),
+ method: Some(~Select(~[], ~[CurrentArgument]))
+ })]);
+ same("{1, select, other {{2, select, other {lol}}} }", ~[Argument(Argument{
+ position: ArgumentIs(1),
+ format: fmtdflt(),
+ method: Some(~Select(~[], ~[Argument(Argument{
+ position: ArgumentIs(2),
+ format: fmtdflt(),
+ method: Some(~Select(~[], ~[String("lol")]))
+ })])) // wat
+ })]);
+ }
+
+ #[test]
+ fn select_cases() {
+ same("{1, select, a{1} b{2} c{3} other{4} }", ~[Argument(Argument{
+ position: ArgumentIs(1),
+ format: fmtdflt(),
+ method: Some(~Select(~[
+ SelectArm{ selector: "a", result: ~[String("1")] },
+ SelectArm{ selector: "b", result: ~[String("2")] },
+ SelectArm{ selector: "c", result: ~[String("3")] },
+ ], ~[String("4")]))
+ })]);
+ }
+
+ #[test] #[should_fail] fn badselect01() {
+ musterr("{select, }")
+ }
+ #[test] #[should_fail] fn badselect02() {
+ musterr("{1, select}")
+ }
+ #[test] #[should_fail] fn badselect03() {
+ musterr("{1, select, }")
+ }
+ #[test] #[should_fail] fn badselect04() {
+ musterr("{1, select, a {}}")
+ }
+ #[test] #[should_fail] fn badselect05() {
+ musterr("{1, select, other }}")
+ }
+ #[test] #[should_fail] fn badselect06() {
+ musterr("{1, select, other {}")
+ }
+ #[test] #[should_fail] fn badselect07() {
+ musterr("{select, other {}")
+ }
+ #[test] #[should_fail] fn badselect08() {
+ musterr("{1 select, other {}")
+ }
+ #[test] #[should_fail] fn badselect09() {
+ musterr("{:d select, other {}")
+ }
+ #[test] #[should_fail] fn badselect10() {
+ musterr("{1:d select, other {}")
+ }
+
+ #[test]
+ fn plural_simple() {
+ same("{, plural, other { haha } }", ~[Argument(Argument{
+ position: ArgumentNext,
+ format: fmtdflt(),
+ method: Some(~Plural(None, ~[], ~[String(" haha ")]))
+ })]);
+ same("{:, plural, other { haha } }", ~[Argument(Argument{
+ position: ArgumentNext,
+ format: fmtdflt(),
+ method: Some(~Plural(None, ~[], ~[String(" haha ")]))
+ })]);
+ same("{, plural, offset:1 =2{2} =3{3} many{yes} other{haha} }",
+ ~[Argument(Argument{
+ position: ArgumentNext,
+ format: fmtdflt(),
+ method: Some(~Plural(Some(1), ~[
+ PluralArm{ selector: Right(2), result: ~[String("2")] },
+ PluralArm{ selector: Right(3), result: ~[String("3")] },
+ PluralArm{ selector: Left(Many), result: ~[String("yes")] }
+ ], ~[String("haha")]))
+ })]);
+ }
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This is an internal module used by the ifmt! runtime. These structures are
+//! emitted to static arrays to precompile format strings ahead of time.
+//!
+//! These definitions are similar to their `ct` equivalents, but differ in that
+//! these can be statically allocated and are slightly optimized for the runtime
+
+#[allow(missing_doc)];
+#[doc(hidden)];
+
+use either::Either;
+use fmt::parse;
+use option::Option;
+
+pub enum Piece<'self> {
+ String(&'self str),
+ // FIXME(#8259): this shouldn't require the unit-value here
+ CurrentArgument(()),
+ Argument(Argument<'self>),
+}
+
+pub struct Argument<'self> {
+ position: Position,
+ format: FormatSpec,
+ method: Option<&'self Method<'self>>
+}
+
+pub struct FormatSpec {
+ fill: char,
+ alignleft: bool,
+ flags: uint,
+ precision: parse::Count,
+ width: parse::Count,
+}
+
+pub enum Position {
+ ArgumentNext, ArgumentIs(uint)
+}
+
+pub enum Method<'self> {
+ Plural(Option<uint>, &'self [PluralArm<'self>], &'self [Piece<'self>]),
+ Select(&'self [SelectArm<'self>], &'self [Piece<'self>]),
+}
+
+pub struct PluralArm<'self> {
+ selector: Either<parse::PluralKeyword, uint>,
+ result: &'self [Piece<'self>],
+}
+
+pub struct SelectArm<'self> {
+ selector: &'self str,
+ result: &'self [Piece<'self>],
+}
use clone::Clone;
use cmp::{Eq, Equiv};
use hash::Hash;
-use iterator::{Iterator, IteratorUtil, FromIterator, Extendable, range};
+use iterator::{Iterator, IteratorUtil, FromIterator, Extendable};
use iterator::{FilterMap, Chain, Repeat, Zip};
use num;
use option::{None, Option, Some};
let len_buckets = self.buckets.len();
let bucket = self.buckets[idx].take();
- let value = do bucket.map_consume |bucket| {
+ let value = do bucket.map_move |bucket| {
bucket.value
};
impl<K:Hash + Eq,V> Mutable for HashMap<K, V> {
/// Clear the map, removing all key-value pairs.
fn clear(&mut self) {
- for idx in range(0u, self.buckets.len()) {
- self.buckets[idx] = None;
+ for bkt in self.buckets.mut_iter() {
+ *bkt = None;
}
self.size = 0;
}
impl<K: Hash + Eq, V: Clone> HashMap<K, V> {
/// Like `find`, but returns a copy of the value.
pub fn find_copy(&self, k: &K) -> Option<V> {
- self.find(k).map_consume(|v| (*v).clone())
+ self.find(k).map_move(|v| (*v).clone())
}
/// Like `get`, but returns a copy of the value.
*/
use cmp;
-use num::{Zero, One};
+use num::{Zero, One, Integer, Saturating};
use option::{Option, Some, None};
-use ops::{Add, Mul};
+use ops::{Add, Mul, Sub};
use cmp::Ord;
use clone::Clone;
use uint;
/// ~~~ {.rust}
/// let xs = [2u, 3];
/// let ys = [0u, 1, 0, 1, 2];
- /// let mut it = xs.iter().flat_map_(|&x| Counter::new(0u, 1).take_(x));
+ /// let mut it = xs.iter().flat_map_(|&x| count(0u, 1).take_(x));
/// // Check that `it` has the same elements as `ys`
/// let mut i = 0;
/// for x: uint in it {
/// ~~~ {.rust}
/// use std::iterator::Counter;
///
- /// for i in Counter::new(0, 10) {
+ /// for i in count(0, 10) {
/// printfln!("%d", i);
/// }
/// ~~~
Some((y, y_val))
}
}
- }).map_consume(|(x, _)| x)
+ }).map_move(|(x, _)| x)
}
#[inline]
Some((y, y_val))
}
}
- }).map_consume(|(x, _)| x)
+ }).map_move(|(x, _)| x)
}
}
/// use std::iterator::Counter;
///
/// fn factorial(n: uint) -> uint {
- /// Counter::new(1u, 1).take_while(|&i| i <= n).product()
+ /// count(1u, 1).take_while(|&i| i <= n).product()
/// }
/// assert!(factorial(0) == 1);
/// assert!(factorial(1) == 1);
/// # Example
///
/// ~~~ {.rust}
- /// let a = Counter::new(1,1).take_(1);
+ /// let a = count(1,1).take_(1);
/// let mut cy = a.cycle();
/// assert_eq!(cy.next(), Some(1));
/// assert_eq!(cy.next(), Some(1));
let (a_lower, a_upper) = self.a.size_hint();
let (b_lower, b_upper) = self.b.size_hint();
- let lower = if uint::max_value - a_lower < b_lower {
- uint::max_value
- } else {
- a_lower + b_lower
- };
+ let lower = a_lower.saturating_add(b_lower);
let upper = match (a_upper, b_upper) {
- (Some(x), Some(y)) if uint::max_value - x < y => Some(uint::max_value),
- (Some(x), Some(y)) => Some(x + y),
+ (Some(x), Some(y)) => Some(x.saturating_add(y)),
_ => None
};
#[inline]
fn indexable(&self) -> uint {
let (a, b) = (self.a.indexable(), self.b.indexable());
- let total = a + b;
- if total < a || total < b {
- uint::max_value
- } else {
- total
- }
+ a.saturating_add(b)
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
let (lower, upper) = self.iter.size_hint();
- let lower = if lower >= self.n { lower - self.n } else { 0 };
+ let lower = lower.saturating_sub(self.n);
let upper = match upper {
- Some(x) if x >= self.n => Some(x - self.n),
- Some(_) => Some(0),
+ Some(x) => Some(x.saturating_sub(self.n)),
None => None
};
impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Skip<T> {
#[inline]
fn indexable(&self) -> uint {
- let N = self.iter.indexable();
- if N < self.n {
- 0
- } else {
- N - self.n
- }
+ self.iter.indexable().saturating_sub(self.n)
}
#[inline]
impl<A, T: Iterator<A>> Iterator<A> for Take<T> {
#[inline]
fn next(&mut self) -> Option<A> {
- let next = self.iter.next();
if self.n != 0 {
self.n -= 1;
- next
+ self.iter.next()
} else {
None
}
return Some(x)
}
}
- match self.iter.next().map_consume(|x| (self.f)(x)) {
+ match self.iter.next().map_move(|x| (self.f)(x)) {
None => return self.backiter.chain_mut_ref(|it| it.next()),
next => self.frontiter = next,
}
fn size_hint(&self) -> (uint, Option<uint>) {
let (flo, fhi) = self.frontiter.map_default((0, Some(0)), |it| it.size_hint());
let (blo, bhi) = self.backiter.map_default((0, Some(0)), |it| it.size_hint());
+ let lo = flo.saturating_add(blo);
match (self.iter.size_hint(), fhi, bhi) {
- ((0, Some(0)), Some(a), Some(b)) => (flo + blo, Some(a + b)),
- _ => (flo + blo, None)
+ ((0, Some(0)), Some(a), Some(b)) => (lo, Some(a.saturating_add(b))),
+ _ => (lo, None)
}
}
}
y => return y
}
}
- match self.iter.next_back().map_consume(|x| (self.f)(x)) {
+ match self.iter.next_back().map_move(|x| (self.f)(x)) {
None => return self.frontiter.chain_mut_ref(|it| it.next_back()),
next => self.backiter = next,
}
step: A
}
-impl<A> Counter<A> {
- /// Creates a new counter with the specified start/step
- #[inline]
- pub fn new(start: A, step: A) -> Counter<A> {
- Counter{state: start, step: step}
- }
+/// Creates a new counter with the specified start/step
+#[inline]
+pub fn count<A>(start: A, step: A) -> Counter<A> {
+ Counter{state: start, step: step}
}
/// A range of numbers from [0, N)
Range{state: start, stop: stop, one: One::one()}
}
-impl<A: Add<A, A> + Ord + Clone + One> Iterator<A> for Range<A> {
+impl<A: Add<A, A> + Ord + Clone> Iterator<A> for Range<A> {
#[inline]
fn next(&mut self) -> Option<A> {
if self.state < self.stop {
}
}
+impl<A: Sub<A, A> + Integer + Ord + Clone> DoubleEndedIterator<A> for Range<A> {
+ #[inline]
+ fn next_back(&mut self) -> Option<A> {
+ if self.stop > self.state {
+ // Integer doesn't technically define this rule, but we're going to assume that every
+ // Integer is reachable from every other one by adding or subtracting enough Ones. This
+ // seems like a reasonable-enough rule that every Integer should conform to, even if it
+ // can't be statically checked.
+ self.stop = self.stop - self.one;
+ Some(self.stop.clone())
+ } else {
+ None
+ }
+ }
+}
+
impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> {
#[inline]
fn next(&mut self) -> Option<A> {
#[test]
fn test_counter_from_iter() {
- let mut it = Counter::new(0, 5).take_(10);
+ let mut it = count(0, 5).take_(10);
let xs: ~[int] = FromIterator::from_iterator(&mut it);
assert_eq!(xs, ~[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]);
}
}
assert_eq!(i, expected.len());
- let ys = Counter::new(30u, 10).take_(4);
+ let ys = count(30u, 10).take_(4);
let mut it = xs.iter().transform(|&x| x).chain_(ys);
let mut i = 0;
for x in it {
#[test]
fn test_filter_map() {
- let mut it = Counter::new(0u, 1u).take_(10)
+ let mut it = count(0u, 1u).take_(10)
.filter_map(|x| if x.is_even() { Some(x*x) } else { None });
assert_eq!(it.collect::<~[uint]>(), ~[0*0, 2*2, 4*4, 6*6, 8*8]);
}
fn test_iterator_flat_map() {
let xs = [0u, 3, 6];
let ys = [0u, 1, 2, 3, 4, 5, 6, 7, 8];
- let mut it = xs.iter().flat_map_(|&x| Counter::new(x, 1).take_(3));
+ let mut it = xs.iter().flat_map_(|&x| count(x, 1).take_(3));
let mut i = 0;
for x in it {
assert_eq!(x, ys[i]);
#[test]
fn test_cycle() {
let cycle_len = 3;
- let it = Counter::new(0u, 1).take_(cycle_len).cycle();
+ let it = count(0u, 1).take_(cycle_len).cycle();
assert_eq!(it.size_hint(), (uint::max_value, None));
for (i, x) in it.take_(100).enumerate() {
assert_eq!(i % cycle_len, x);
}
- let mut it = Counter::new(0u, 1).take_(0).cycle();
+ let mut it = count(0u, 1).take_(0).cycle();
assert_eq!(it.size_hint(), (0, Some(0)));
assert_eq!(it.next(), None);
}
#[test]
fn test_iterator_size_hint() {
- let c = Counter::new(0, 1);
+ let c = count(0, 1);
let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let v2 = &[10, 11, 12];
let vi = v.iter();
check_randacc_iter(xs.iter().cycle().take_(27), 27);
check_randacc_iter(empty.iter().cycle(), 0);
}
+
+ #[test]
+ fn test_double_ended_range() {
+ assert_eq!(range(11i, 14).invert().collect::<~[int]>(), ~[13i, 12, 11]);
+ for _ in range(10i, 0).invert() {
+ fail!("unreachable");
+ }
+
+ assert_eq!(range(11u, 14).invert().collect::<~[uint]>(), ~[13u, 12, 11]);
+ for _ in range(10u, 0).invert() {
+ fail!("unreachable");
+ }
+ }
}
set(my_key, @~"parent data");
do task::spawn {
// TLS shouldn't carry over.
- assert!(get(my_key, |k| k.map(|&k| *k)).is_none());
+ assert!(get(my_key, |k| k.map_move(|k| *k)).is_none());
set(my_key, @~"child data");
- assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) ==
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) ==
~"child data");
// should be cleaned up for us
}
// Must work multiple times
- assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data");
- assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data");
- assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"parent data");
}
#[test]
static my_key: Key<@~str> = &Key;
set(my_key, @~"first data");
set(my_key, @~"next data"); // Shouldn't leak.
- assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"next data");
+ assert!(*(get(my_key, |k| k.map_move(|k| *k)).unwrap()) == ~"next data");
}
#[test]
use ptr::to_unsafe_ptr;
-#[cfg(not(test))] use cmp::{Eq, Ord};
+#[cfg(not(test))] use cmp::*;
pub static RC_MANAGED_UNIQUE : uint = (-2) as uint;
pub static RC_IMMORTAL : uint = 0x77777777;
fn gt(&self, other: &@mut T) -> bool { *(*self) > *(*other) }
}
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for @T {
+ #[inline]
+ fn cmp(&self, other: &@T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for @mut T {
+ #[inline]
+ fn cmp(&self, other: &@mut T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for @T {
+ #[inline]
+ fn equals(&self, other: &@T) -> bool { (**self).equals(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for @mut T {
+ #[inline]
+ fn equals(&self, other: &@mut T) -> bool { (**self).equals(*other) }
+}
#[test]
fn test() {
let x = @3;
#[cfg(not(test))]
impl Add<f64,f64> for f64 {
+ #[inline]
fn add(&self, other: &f64) -> f64 { *self + *other }
}
#[cfg(not(test))]
impl Sub<f64,f64> for f64 {
+ #[inline]
fn sub(&self, other: &f64) -> f64 { *self - *other }
}
#[cfg(not(test))]
impl Mul<f64,f64> for f64 {
+ #[inline]
fn mul(&self, other: &f64) -> f64 { *self * *other }
}
#[cfg(not(test))]
impl Div<f64,f64> for f64 {
+ #[inline]
fn div(&self, other: &f64) -> f64 { *self / *other }
}
#[cfg(not(test))]
range_step_core(start, last, step, Closed, it)
}
-
-#[inline]
-/// Iterate over the range (`hi`..`lo`]
-pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool {
- if hi == min_value { return true; }
- range_step_inclusive(hi-1, lo, -1 as $T, it)
-}
-
impl Num for $T {}
#[cfg(not(test))]
fn test_ranges() {
let mut l = ~[];
- do range_rev(14,11) |i| {
- l.push(i);
- true
- };
do range_step(20,26,2) |i| {
l.push(i);
true
l.push(i);
true
};
- assert_eq!(l, ~[13,12,11,
- 20,22,24,
+ assert_eq!(l, ~[20,22,24,
36,34,32,
max_value-2,
max_value-3,max_value-1,
min_value+3,min_value+1]);
// None of the `fail`s should execute.
- do range_rev(0,10) |_i| {
- fail!(~"unreachable");
- };
do range_step(10,0,1) |_i| {
fail!(~"unreachable");
};
fn is_zero(&self) -> bool { (**self).is_zero() }
}
+/// Saturating math operations
+pub trait Saturating: Int {
+ /// Saturating addition operator.
+ /// Returns a+b, saturating at the numeric bounds instead of overflowing.
+ #[inline]
+ fn saturating_add(self, v: Self) -> Self {
+ let x = self + v;
+ if v >= Zero::zero() {
+ if x < self {
+ // overflow
+ Bounded::max_value::<Self>()
+ } else { x }
+ } else {
+ if x > self {
+ // underflow
+ Bounded::min_value::<Self>()
+ } else { x }
+ }
+ }
+
+ /// Saturating subtraction operator.
+ /// Returns a-b, saturating at the numeric bounds instead of overflowing.
+ #[inline]
+ fn saturating_sub(self, v: Self) -> Self {
+ let x = self - v;
+ if v >= Zero::zero() {
+ if x > self {
+ // underflow
+ Bounded::min_value::<Self>()
+ } else { x }
+ } else {
+ if x < self {
+ // overflow
+ Bounded::max_value::<Self>()
+ } else { x }
+ }
+ }
+}
+
+impl Saturating for int {}
+impl Saturating for i8 {}
+impl Saturating for i16 {}
+impl Saturating for i32 {}
+impl Saturating for i64 {}
+impl Saturating for uint {}
+impl Saturating for u8 {}
+impl Saturating for u16 {}
+impl Saturating for u32 {}
+impl Saturating for u64 {}
+
/// Helper function for testing numeric operations
#[cfg(test)]
pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
assert_eq!(ten.rem(&two), ten % two);
}
-macro_rules! test_cast_20(
- ($_20:expr) => ({
- let _20 = $_20;
-
- assert_eq!(20u, _20.to_uint());
- assert_eq!(20u8, _20.to_u8());
- assert_eq!(20u16, _20.to_u16());
- assert_eq!(20u32, _20.to_u32());
- assert_eq!(20u64, _20.to_u64());
- assert_eq!(20i, _20.to_int());
- assert_eq!(20i8, _20.to_i8());
- assert_eq!(20i16, _20.to_i16());
- assert_eq!(20i32, _20.to_i32());
- assert_eq!(20i64, _20.to_i64());
- assert_eq!(20f, _20.to_float());
- assert_eq!(20f32, _20.to_f32());
- assert_eq!(20f64, _20.to_f64());
-
- assert_eq!(_20, NumCast::from(20u));
- assert_eq!(_20, NumCast::from(20u8));
- assert_eq!(_20, NumCast::from(20u16));
- assert_eq!(_20, NumCast::from(20u32));
- assert_eq!(_20, NumCast::from(20u64));
- assert_eq!(_20, NumCast::from(20i));
- assert_eq!(_20, NumCast::from(20i8));
- assert_eq!(_20, NumCast::from(20i16));
- assert_eq!(_20, NumCast::from(20i32));
- assert_eq!(_20, NumCast::from(20i64));
- assert_eq!(_20, NumCast::from(20f));
- assert_eq!(_20, NumCast::from(20f32));
- assert_eq!(_20, NumCast::from(20f64));
-
- assert_eq!(_20, cast(20u));
- assert_eq!(_20, cast(20u8));
- assert_eq!(_20, cast(20u16));
- assert_eq!(_20, cast(20u32));
- assert_eq!(_20, cast(20u64));
- assert_eq!(_20, cast(20i));
- assert_eq!(_20, cast(20i8));
- assert_eq!(_20, cast(20i16));
- assert_eq!(_20, cast(20i32));
- assert_eq!(_20, cast(20i64));
- assert_eq!(_20, cast(20f));
- assert_eq!(_20, cast(20f32));
- assert_eq!(_20, cast(20f64));
- })
-)
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ macro_rules! test_cast_20(
+ ($_20:expr) => ({
+ let _20 = $_20;
+
+ assert_eq!(20u, _20.to_uint());
+ assert_eq!(20u8, _20.to_u8());
+ assert_eq!(20u16, _20.to_u16());
+ assert_eq!(20u32, _20.to_u32());
+ assert_eq!(20u64, _20.to_u64());
+ assert_eq!(20i, _20.to_int());
+ assert_eq!(20i8, _20.to_i8());
+ assert_eq!(20i16, _20.to_i16());
+ assert_eq!(20i32, _20.to_i32());
+ assert_eq!(20i64, _20.to_i64());
+ assert_eq!(20f, _20.to_float());
+ assert_eq!(20f32, _20.to_f32());
+ assert_eq!(20f64, _20.to_f64());
+
+ assert_eq!(_20, NumCast::from(20u));
+ assert_eq!(_20, NumCast::from(20u8));
+ assert_eq!(_20, NumCast::from(20u16));
+ assert_eq!(_20, NumCast::from(20u32));
+ assert_eq!(_20, NumCast::from(20u64));
+ assert_eq!(_20, NumCast::from(20i));
+ assert_eq!(_20, NumCast::from(20i8));
+ assert_eq!(_20, NumCast::from(20i16));
+ assert_eq!(_20, NumCast::from(20i32));
+ assert_eq!(_20, NumCast::from(20i64));
+ assert_eq!(_20, NumCast::from(20f));
+ assert_eq!(_20, NumCast::from(20f32));
+ assert_eq!(_20, NumCast::from(20f64));
+
+ assert_eq!(_20, cast(20u));
+ assert_eq!(_20, cast(20u8));
+ assert_eq!(_20, cast(20u16));
+ assert_eq!(_20, cast(20u32));
+ assert_eq!(_20, cast(20u64));
+ assert_eq!(_20, cast(20i));
+ assert_eq!(_20, cast(20i8));
+ assert_eq!(_20, cast(20i16));
+ assert_eq!(_20, cast(20i32));
+ assert_eq!(_20, cast(20i64));
+ assert_eq!(_20, cast(20f));
+ assert_eq!(_20, cast(20f32));
+ assert_eq!(_20, cast(20f64));
+ })
+ )
+
+ #[test] fn test_u8_cast() { test_cast_20!(20u8) }
+ #[test] fn test_u16_cast() { test_cast_20!(20u16) }
+ #[test] fn test_u32_cast() { test_cast_20!(20u32) }
+ #[test] fn test_u64_cast() { test_cast_20!(20u64) }
+ #[test] fn test_uint_cast() { test_cast_20!(20u) }
+ #[test] fn test_i8_cast() { test_cast_20!(20i8) }
+ #[test] fn test_i16_cast() { test_cast_20!(20i16) }
+ #[test] fn test_i32_cast() { test_cast_20!(20i32) }
+ #[test] fn test_i64_cast() { test_cast_20!(20i64) }
+ #[test] fn test_int_cast() { test_cast_20!(20i) }
+ #[test] fn test_f32_cast() { test_cast_20!(20f32) }
+ #[test] fn test_f64_cast() { test_cast_20!(20f64) }
+ #[test] fn test_float_cast() { test_cast_20!(20f) }
+
+ #[test]
+ fn test_saturating_add_uint() {
+ use uint::max_value;
+ assert_eq!(3u.saturating_add(5u), 8u);
+ assert_eq!(3u.saturating_add(max_value-1), max_value);
+ assert_eq!(max_value.saturating_add(max_value), max_value);
+ assert_eq!((max_value-2).saturating_add(1), max_value-1);
+ }
+
+ #[test]
+ fn test_saturating_sub_uint() {
+ use uint::max_value;
+ assert_eq!(5u.saturating_sub(3u), 2u);
+ assert_eq!(3u.saturating_sub(5u), 0u);
+ assert_eq!(0u.saturating_sub(1u), 0u);
+ assert_eq!((max_value-1).saturating_sub(max_value), 0);
+ }
-#[test] fn test_u8_cast() { test_cast_20!(20u8) }
-#[test] fn test_u16_cast() { test_cast_20!(20u16) }
-#[test] fn test_u32_cast() { test_cast_20!(20u32) }
-#[test] fn test_u64_cast() { test_cast_20!(20u64) }
-#[test] fn test_uint_cast() { test_cast_20!(20u) }
-#[test] fn test_i8_cast() { test_cast_20!(20i8) }
-#[test] fn test_i16_cast() { test_cast_20!(20i16) }
-#[test] fn test_i32_cast() { test_cast_20!(20i32) }
-#[test] fn test_i64_cast() { test_cast_20!(20i64) }
-#[test] fn test_int_cast() { test_cast_20!(20i) }
-#[test] fn test_f32_cast() { test_cast_20!(20f32) }
-#[test] fn test_f64_cast() { test_cast_20!(20f64) }
-#[test] fn test_float_cast() { test_cast_20!(20f) }
+ #[test]
+ fn test_saturating_add_int() {
+ use int::{min_value,max_value};
+ assert_eq!(3i.saturating_add(5i), 8i);
+ assert_eq!(3i.saturating_add(max_value-1), max_value);
+ assert_eq!(max_value.saturating_add(max_value), max_value);
+ assert_eq!((max_value-2).saturating_add(1), max_value-1);
+ assert_eq!(3i.saturating_add(-5i), -2i);
+ assert_eq!(min_value.saturating_add(-1i), min_value);
+ assert_eq!((-2i).saturating_add(-max_value), min_value);
+ }
+
+ #[test]
+ fn test_saturating_sub_int() {
+ use int::{min_value,max_value};
+ assert_eq!(3i.saturating_sub(5i), -2i);
+ assert_eq!(min_value.saturating_sub(1i), min_value);
+ assert_eq!((-2i).saturating_sub(max_value), min_value);
+ assert_eq!(3i.saturating_sub(-5i), 8i);
+ assert_eq!(3i.saturating_sub(-(max_value-1)), max_value);
+ assert_eq!(max_value.saturating_sub(-max_value), max_value);
+ assert_eq!((max_value-2).saturating_sub(-1), max_value-1);
+ }
+}
// Some constants for from_str_bytes_common's input validation,
// they define minimum radix values for which the character is a valid digit.
-priv static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
-priv static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
-priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
+static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
+static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
+static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
/**
* Parses a byte slice as a number. This is meant to
range_step_core(start, last, step, Closed, it)
}
-#[inline]
-/// Iterate over the range (`hi`..`lo`]
-pub fn range_rev(hi: $T, lo: $T, it: &fn($T) -> bool) -> bool {
- if hi == min_value { return true; }
- range_step_inclusive(hi-1, lo, -1 as $T_SIGNED, it)
-}
-
impl Num for $T {}
#[cfg(not(test))]
pub fn test_ranges() {
let mut l = ~[];
- do range_rev(14,11) |i| {
- l.push(i);
- true
- };
do range_step(20,26,2) |i| {
l.push(i);
true
true
};
- assert_eq!(l, ~[13,12,11,
- 20,22,24,
+ assert_eq!(l, ~[20,22,24,
36,34,32,
max_value-2,
max_value-3,max_value-1,
min_value+3,min_value+1]);
// None of the `fail`s should execute.
- do range_rev(0,0) |_i| {
- fail!("unreachable");
- };
do range_step(10,0,1) |_i| {
fail!("unreachable");
};
match *self { Some(ref mut x) => Some(f(x)), None => None }
}
+ /// Applies a function to the contained value or returns a default
+ #[inline]
+ pub fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U {
+ match *self { None => def, Some(ref t) => f(t) }
+ }
+
/// Maps a `Some` value from one type to another by a mutable reference,
/// or returns a default value.
#[inline]
/// As `map`, but consumes the option and gives `f` ownership to avoid
/// copying.
#[inline]
- pub fn map_consume<U>(self, f: &fn(v: T) -> U) -> Option<U> {
- match self { None => None, Some(v) => Some(f(v)) }
- }
-
- /// Applies a function to the contained value or returns a default
- #[inline]
- pub fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U {
- match *self { None => def, Some(ref t) => f(t) }
+ pub fn map_move<U>(self, f: &fn(T) -> U) -> Option<U> {
+ match self { Some(x) => Some(f(x)), None => None }
}
/// As `map_default`, but consumes the option and gives `f`
/// ownership to avoid copying.
#[inline]
- pub fn map_consume_default<U>(self, def: U, f: &fn(v: T) -> U) -> U {
- match self { None => def, Some(v) => f(v) }
+ pub fn map_move_default<U>(self, def: U, f: &fn(T) -> U) -> U {
+ match self { None => def, Some(t) => f(t) }
}
/// Take the value out of the option, leaving a `None` in its place.
util::replace(self, None)
}
- /// As `map_consume`, but swaps a None into the original option rather
- /// than consuming it by-value.
- #[inline]
- pub fn take_map<U>(&mut self, blk: &fn(T) -> U) -> Option<U> {
- self.take().map_consume(blk)
- }
-
- /// As `map_consume_default`, but swaps a None into the original option
- /// rather than consuming it by-value.
- #[inline]
- pub fn take_map_default<U> (&mut self, def: U, blk: &fn(T) -> U) -> U {
- self.take().map_consume_default(def, blk)
- }
-
/// Apply a function to the contained value or do nothing.
/// Returns true if the contained value was mutated.
pub fn mutate(&mut self, f: &fn(T) -> T) -> bool {
}
}
- do load_self().map |pth| {
- Path(*pth).dir_path()
- }
+ load_self().map_move(|path| Path(path).dir_path())
}
//! Operations on unique pointer types
-#[cfg(not(test))] use cmp::{Eq, Ord};
+#[cfg(not(test))] use cmp::*;
#[cfg(not(test))]
impl<T:Eq> Eq for ~T {
#[inline]
fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) }
}
+
+#[cfg(not(test))]
+impl<T: TotalOrd> TotalOrd for ~T {
+ #[inline]
+ fn cmp(&self, other: &~T) -> Ordering { (**self).cmp(*other) }
+}
+
+#[cfg(not(test))]
+impl<T: TotalEq> TotalEq for ~T {
+ #[inline]
+ fn equals(&self, other: &~T) -> bool { (**self).equals(*other) }
+}
pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
pub use hash::Hash;
pub use iter::Times;
+pub use iterator::Extendable;
pub use iterator::{Iterator, IteratorUtil, DoubleEndedIterator, DoubleEndedIteratorUtil};
pub use iterator::{ClonableIterator, OrdIterator};
pub use num::{Num, NumCast};
pub use ptr::RawPtr;
pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, ToBytesConsume};
pub use str::{Str, StrVector, StrSlice, OwnedStr, NullTerminatedStr};
-pub use from_str::{FromStr};
+pub use from_str::FromStr;
pub use to_bytes::IterBytes;
pub use to_str::{ToStr, ToStrConsume};
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
fn is_not_null(&self) -> bool;
unsafe fn to_option(&self) -> Option<&T>;
fn offset(&self, count: int) -> Self;
+ unsafe fn offset_inbounds(self, count: int) -> Self;
}
/// Extension methods for immutable pointers
/// Calculates the offset from a pointer.
#[inline]
fn offset(&self, count: int) -> *T { offset(*self, count) }
+
+ /// Calculates the offset from a pointer. The offset *must* be in-bounds of
+ /// the object, or one-byte-past-the-end.
+ #[inline]
+ #[cfg(stage0)]
+ unsafe fn offset_inbounds(self, count: int) -> *T {
+ intrinsics::offset(self, count)
+ }
+
+ /// Calculates the offset from a pointer. The offset *must* be in-bounds of
+ /// the object, or one-byte-past-the-end.
+ #[inline]
+ #[cfg(not(stage0))]
+ unsafe fn offset_inbounds(self, count: int) -> *T {
+ intrinsics::offset_inbounds(self, count)
+ }
}
/// Extension methods for mutable pointers
/// Calculates the offset from a mutable pointer.
#[inline]
fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) }
+
+ /// Calculates the offset from a pointer. The offset *must* be in-bounds of
+ /// the object, or one-byte-past-the-end. An arithmetic overflow is also
+ /// undefined behaviour.
+ ///
+ /// This method should be preferred over `offset` when the guarantee can be
+ /// satisfied, to enable better optimization.
+ #[inline]
+ #[cfg(stage0)]
+ unsafe fn offset_inbounds(self, count: int) -> *mut T {
+ intrinsics::offset(self as *T, count) as *mut T
+ }
+
+ /// Calculates the offset from a pointer. The offset *must* be in-bounds of
+ /// the object, or one-byte-past-the-end. An arithmetic overflow is also
+ /// undefined behaviour.
+ ///
+ /// This method should be preferred over `offset` when the guarantee can be
+ /// satisfied, to enable better optimization.
+ #[inline]
+ #[cfg(not(stage0))]
+ unsafe fn offset_inbounds(self, count: int) -> *mut T {
+ intrinsics::offset_inbounds(self as *T, count) as *mut T
+ }
}
// Equality for pointers
}
/// Create a random number generator with a default algorithm and seed.
+///
+/// It returns the cryptographically-safest `Rng` algorithm currently
+/// available in Rust. If you require a specifically seeded `Rng` for
+/// consistency over time you should pick one algorithm and create the
+/// `Rng` yourself.
pub fn rng() -> IsaacRng {
IsaacRng::new()
}
+/// Create a weak random number generator with a default algorithm and seed.
+///
+/// It returns the fatest `Rng` algorithm currently available in Rust without
+/// consideration for cryptography or security. If you require a specifically
+/// seeded `Rng` for consistency over time you should pick one algorithm and
+/// create the `Rng` yourself.
+pub fn weak_rng() -> XorShiftRng {
+ XorShiftRng::new()
+}
+
static RAND_SIZE_LEN: u32 = 8;
static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN;
/// A random number generator that uses the [ISAAC
/// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
+///
+/// The ISAAC algorithm is suitable for cryptographic purposes.
pub struct IsaacRng {
priv cnt: u32,
priv rsl: [u32, .. RAND_SIZE],
}
/// An [Xorshift random number
-/// generator](http://en.wikipedia.org/wiki/Xorshift). Not suitable for
-/// cryptographic purposes.
+/// generator](http://en.wikipedia.org/wiki/Xorshift).
+///
+/// The Xorshift algorithm is not suitable for cryptographic purposes
+/// but is very fast. If you do not know for sure that it fits your
+/// requirements, use a more secure one such as `IsaacRng`.
pub struct XorShiftRng {
priv x: u32,
priv y: u32,
}
}
+ /// Call a method based on a previous result
+ ///
+ /// If `self` is `Ok` then the value is extracted and passed to `op`
+ /// whereupon `op`s result is wrapped in `Ok` and returned. if `self` is
+ /// `Err` then it is immediately returned. This function can be used to
+ /// compose the results of two functions.
+ ///
+ /// Example:
+ ///
+ /// let res = do read_file(file).map_move |buf| {
+ /// parse_bytes(buf)
+ /// }
+ #[inline]
+ pub fn map_move<U>(self, op: &fn(T) -> U) -> Result<U,E> {
+ match self {
+ Ok(t) => Ok(op(t)),
+ Err(e) => Err(e)
+ }
+ }
+
+ /// Call a method based on a previous result
+ ///
+ /// If `self` is `Err` then the value is extracted and passed to `op`
+ /// whereupon `op`s result is wrapped in an `Err` and returned. if `self` is
+ /// `Ok` then it is immediately returned. This function can be used to pass
+ /// through a successful result while handling an error.
+ #[inline]
+ pub fn map_err_move<F>(self, op: &fn(E) -> F) -> Result<T,F> {
+ match self {
+ Ok(t) => Ok(t),
+ Err(e) => Err(op(e))
+ }
+ }
+
/// Call a method based on a previous result
///
/// If `self` is `Ok` then the value is extracted and passed to `op`
#[cfg(test)]
mod tests {
use super::*;
+
use either;
+ use str::OwnedStr;
pub fn op1() -> Result<int, ~str> { Ok(666) }
#[test]
pub fn test_impl_map() {
- assert_eq!(Ok::<~str, ~str>(~"a").map(|_x| ~"b"), Ok(~"b"));
- assert_eq!(Err::<~str, ~str>(~"a").map(|_x| ~"b"), Err(~"a"));
+ assert_eq!(Ok::<~str, ~str>(~"a").map(|x| (~"b").append(*x)), Ok(~"ba"));
+ assert_eq!(Err::<~str, ~str>(~"a").map(|x| (~"b").append(*x)), Err(~"a"));
}
#[test]
pub fn test_impl_map_err() {
- assert_eq!(Ok::<~str, ~str>(~"a").map_err(|_x| ~"b"), Ok(~"a"));
- assert_eq!(Err::<~str, ~str>(~"a").map_err(|_x| ~"b"), Err(~"b"));
+ assert_eq!(Ok::<~str, ~str>(~"a").map_err(|x| (~"b").append(*x)), Ok(~"a"));
+ assert_eq!(Err::<~str, ~str>(~"a").map_err(|x| (~"b").append(*x)), Err(~"ba"));
+ }
+
+ #[test]
+ pub fn test_impl_map_move() {
+ assert_eq!(Ok::<~str, ~str>(~"a").map_move(|x| x + "b"), Ok(~"ab"));
+ assert_eq!(Err::<~str, ~str>(~"a").map_move(|x| x + "b"), Err(~"a"));
+ }
+
+ #[test]
+ pub fn test_impl_map_err_move() {
+ assert_eq!(Ok::<~str, ~str>(~"a").map_err_move(|x| x + "b"), Ok(~"a"));
+ assert_eq!(Err::<~str, ~str>(~"a").map_err_move(|x| x + "b"), Err(~"ab"));
}
#[test]
// Port is blocked. Wake it up.
let recvr = BlockedTask::cast_from_uint(task_as_state);
if do_resched {
- do recvr.wake().map_consume |woken_task| {
+ do recvr.wake().map_move |woken_task| {
Scheduler::run_task(woken_task);
};
} else {
fn optimistic_check(&mut self) -> bool {
// The optimistic check is never necessary for correctness. For testing
// purposes, making it randomly return false simulates a racing sender.
- use rand::{Rand, rng};
- let mut rng = rng();
- let actually_check = Rand::rand(&mut rng);
+ use rand::{Rand};
+ let actually_check = do Local::borrow::<Scheduler, bool> |sched| {
+ Rand::rand(&mut sched.rng)
+ };
if actually_check {
unsafe { (*self.packet()).state.load(Acquire) == STATE_ONE }
} else {
// The port is blocked waiting for a message we will never send. Wake it.
assert!((*this.packet()).payload.is_none());
let recvr = BlockedTask::cast_from_uint(task_as_state);
- do recvr.wake().map_consume |woken_task| {
+ do recvr.wake().map_move |woken_task| {
Scheduler::run_task(woken_task);
};
}
}
}
-impl<T> Select for Port<T> {
+// XXX: Kind of gross. A Port<T> should be selectable so you can make an array
+// of them, but a &Port<T> should also be selectable so you can select2 on it
+// alongside a PortOne<U> without passing the port by value in recv_ready.
+
+impl<'self, T> Select for &'self Port<T> {
#[inline]
fn optimistic_check(&mut self) -> bool {
do self.next.with_mut_ref |pone| { pone.optimistic_check() }
}
}
-impl<T> SelectPort<(T, Port<T>)> for Port<T> {
- fn recv_ready(self) -> Option<(T, Port<T>)> {
+impl<T> Select for Port<T> {
+ #[inline]
+ fn optimistic_check(&mut self) -> bool {
+ (&*self).optimistic_check()
+ }
+
+ #[inline]
+ fn block_on(&mut self, sched: &mut Scheduler, task: BlockedTask) -> bool {
+ (&*self).block_on(sched, task)
+ }
+
+ #[inline]
+ fn unblock_from(&mut self) -> bool {
+ (&*self).unblock_from()
+ }
+}
+
+impl<'self, T> SelectPort<T> for &'self Port<T> {
+ fn recv_ready(self) -> Option<T> {
match self.next.take().recv_ready() {
Some(StreamPayload { val, next }) => {
self.next.put_back(next);
- Some((val, self))
+ Some(val)
}
None => None
}
//! Runtime environment settings
+use from_str::FromStr;
use libc::{size_t, c_char, c_int};
+use option::{Some, None};
+use os;
+
+// OLD RT stuff
pub struct Environment {
/// The number of threads to use by default
extern {
fn rust_get_rt_env() -> &Environment;
}
+
+// NEW RT stuff
+
+// Note that these are all accessed without any synchronization.
+// They are expected to be initialized once then left alone.
+
+static mut MIN_STACK: uint = 2000000;
+
+pub fn init() {
+ unsafe {
+ match os::getenv("RUST_MIN_STACK") {
+ Some(s) => match FromStr::from_str(s) {
+ Some(i) => MIN_STACK = i,
+ None => ()
+ },
+ None => ()
+ }
+ }
+}
+
+pub fn min_stack() -> uint {
+ unsafe { MIN_STACK }
+}
}
impl MemWriter {
- pub fn new() -> MemWriter { MemWriter { buf: ~[] } }
+ pub fn new() -> MemWriter { MemWriter { buf: vec::with_capacity(128) } }
}
impl Writer for MemWriter {
// except according to those terms.
use num::FromStrRadix;
+use vec::MutableCloneableVector;
use to_str::ToStr;
+use from_str::FromStr;
+use option::{Option, None, Some};
+
type Port = u16;
}
}
}
+
+struct Parser<'self> {
+ // parsing as ASCII, so can use byte array
+ s: &'self [u8],
+ pos: uint,
+}
+
+impl<'self> Parser<'self> {
+ fn new(s: &'self str) -> Parser<'self> {
+ Parser {
+ s: s.as_bytes(),
+ pos: 0,
+ }
+ }
+
+ fn is_eof(&self) -> bool {
+ self.pos == self.s.len()
+ }
+
+ // Commit only if parser returns Some
+ fn read_atomically<T>(&mut self, cb: &fn(&mut Parser) -> Option<T>) -> Option<T> {
+ let pos = self.pos;
+ let r = cb(self);
+ if r.is_none() {
+ self.pos = pos;
+ }
+ r
+ }
+
+ // Commit only if parser read till EOF
+ fn read_till_eof<T>(&mut self, cb: &fn(&mut Parser) -> Option<T>) -> Option<T> {
+ do self.read_atomically |p| {
+ cb(p).filtered(|_| p.is_eof())
+ }
+ }
+
+ // Return result of first successful parser
+ fn read_or<T>(&mut self, parsers: &[&fn(&mut Parser) -> Option<T>]) -> Option<T> {
+ for pf in parsers.iter() {
+ match self.read_atomically(|p: &mut Parser| (*pf)(p)) {
+ Some(r) => return Some(r),
+ None => {}
+ }
+ }
+ None
+ }
+
+ // Apply 3 parsers sequentially
+ fn read_seq_3<A, B, C>(&mut self,
+ pa: &fn(&mut Parser) -> Option<A>,
+ pb: &fn(&mut Parser) -> Option<B>,
+ pc: &fn(&mut Parser) -> Option<C>
+ ) -> Option<(A, B, C)>
+ {
+ do self.read_atomically |p| {
+ let a = pa(p);
+ let b = if a.is_some() { pb(p) } else { None };
+ let c = if b.is_some() { pc(p) } else { None };
+ match (a, b, c) {
+ (Some(a), Some(b), Some(c)) => Some((a, b, c)),
+ _ => None
+ }
+ }
+ }
+
+ // Read next char
+ fn read_char(&mut self) -> Option<char> {
+ if self.is_eof() {
+ None
+ } else {
+ let r = self.s[self.pos] as char;
+ self.pos += 1;
+ Some(r)
+ }
+ }
+
+ // Return char and advance iff next char is equal to requested
+ fn read_given_char(&mut self, c: char) -> Option<char> {
+ do self.read_atomically |p| {
+ p.read_char().filtered(|&next| next == c)
+ }
+ }
+
+ // Read digit
+ fn read_digit(&mut self, radix: u8) -> Option<u8> {
+ fn parse_digit(c: char, radix: u8) -> Option<u8> {
+ // assuming radix is either 10 or 16
+ if c >= '0' && c <= '9' {
+ Some((c - '0') as u8)
+ } else if radix > 10 && c >= 'a' && c < 'a' + (radix - 10) as char {
+ Some((c - 'a' + (10 as char)) as u8)
+ } else if radix > 10 && c >= 'A' && c < 'A' + (radix - 10) as char {
+ Some((c - 'A' + (10 as char)) as u8)
+ } else {
+ None
+ }
+ }
+
+ do self.read_atomically |p| {
+ p.read_char().chain(|c| parse_digit(c, radix))
+ }
+ }
+
+ fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+ let mut r = 0u32;
+ let mut digit_count = 0;
+ loop {
+ match self.read_digit(radix) {
+ Some(d) => {
+ r = r * (radix as u32) + (d as u32);
+ digit_count += 1;
+ if digit_count > max_digits || r >= upto {
+ return None
+ }
+ }
+ None => {
+ if digit_count == 0 {
+ return None
+ } else {
+ return Some(r)
+ }
+ }
+ };
+ }
+ }
+
+ // Read number, failing if max_digits of number value exceeded
+ fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+ do self.read_atomically |p| {
+ p.read_number_impl(radix, max_digits, upto)
+ }
+ }
+
+ fn read_ipv4_addr_impl(&mut self) -> Option<IpAddr> {
+ let mut bs = [0u8, ..4];
+ let mut i = 0;
+ while i < 4 {
+ if i != 0 && self.read_given_char('.').is_none() {
+ return None;
+ }
+
+ let octet = self.read_number(10, 3, 0x100).map(|&n| n as u8);
+ match octet {
+ Some(d) => bs[i] = d,
+ None => return None,
+ };
+ i += 1;
+ }
+ Some(Ipv4Addr(bs[0], bs[1], bs[2], bs[3]))
+ }
+
+ // Read IPv4 address
+ fn read_ipv4_addr(&mut self) -> Option<IpAddr> {
+ do self.read_atomically |p| {
+ p.read_ipv4_addr_impl()
+ }
+ }
+
+ fn read_ipv6_addr_impl(&mut self) -> Option<IpAddr> {
+ fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> IpAddr {
+ assert!(head.len() + tail.len() <= 8);
+ let mut gs = [0u16, ..8];
+ gs.copy_from(head);
+ gs.mut_slice(8 - tail.len(), 8).copy_from(tail);
+ Ipv6Addr(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
+ }
+
+ fn read_groups(p: &mut Parser, groups: &mut [u16, ..8], limit: uint) -> (uint, bool) {
+ let mut i = 0;
+ while i < limit {
+ if i < limit - 1 {
+ let ipv4 = do p.read_atomically |p| {
+ if i == 0 || p.read_given_char(':').is_some() {
+ p.read_ipv4_addr()
+ } else {
+ None
+ }
+ };
+ match ipv4 {
+ Some(Ipv4Addr(a, b, c, d)) => {
+ groups[i + 0] = (a as u16 << 8) | (b as u16);
+ groups[i + 1] = (c as u16 << 8) | (d as u16);
+ return (i + 2, true);
+ }
+ _ => {}
+ }
+ }
+
+ let group = do p.read_atomically |p| {
+ if i == 0 || p.read_given_char(':').is_some() {
+ p.read_number(16, 4, 0x10000).map(|&n| n as u16)
+ } else {
+ None
+ }
+ };
+ match group {
+ Some(g) => groups[i] = g,
+ None => return (i, false)
+ }
+ i += 1;
+ }
+ (i, false)
+ }
+
+ let mut head = [0u16, ..8];
+ let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
+
+ if head_size == 8 {
+ return Some(Ipv6Addr(
+ head[0], head[1], head[2], head[3],
+ head[4], head[5], head[6], head[7]))
+ }
+
+ // IPv4 part is not allowed before `::`
+ if head_ipv4 {
+ return None
+ }
+
+ // read `::` if previous code parsed less than 8 groups
+ if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
+ return None;
+ }
+
+ let mut tail = [0u16, ..8];
+ let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
+ Some(ipv6_addr_from_head_tail(head.slice(0, head_size), tail.slice(0, tail_size)))
+ }
+
+ fn read_ipv6_addr(&mut self) -> Option<IpAddr> {
+ do self.read_atomically |p| {
+ p.read_ipv6_addr_impl()
+ }
+ }
+
+ fn read_ip_addr(&mut self) -> Option<IpAddr> {
+ let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr();
+ let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr();
+ self.read_or([ipv4_addr, ipv6_addr])
+ }
+
+ fn read_socket_addr(&mut self) -> Option<SocketAddr> {
+ let ip_addr = |p: &mut Parser| {
+ let ipv4_p = |p: &mut Parser| p.read_ip_addr();
+ let ipv6_p = |p: &mut Parser| {
+ let open_br = |p: &mut Parser| p.read_given_char('[');
+ let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
+ let clos_br = |p: &mut Parser| p.read_given_char(']');
+ p.read_seq_3::<char, IpAddr, char>(open_br, ip_addr, clos_br)
+ .map(|&t| match t { (_, ip, _) => ip })
+ };
+ p.read_or([ipv4_p, ipv6_p])
+ };
+ let colon = |p: &mut Parser| p.read_given_char(':');
+ let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|&n| n as u16);
+
+ // host, colon, port
+ self.read_seq_3::<IpAddr, char, u16>(ip_addr, colon, port)
+ .map(|&t| match t { (ip, _, port) => SocketAddr { ip: ip, port: port } })
+ }
+}
+
+impl FromStr for IpAddr {
+ fn from_str(s: &str) -> Option<IpAddr> {
+ do Parser::new(s).read_till_eof |p| {
+ p.read_ip_addr()
+ }
+ }
+}
+
+impl FromStr for SocketAddr {
+ fn from_str(s: &str) -> Option<SocketAddr> {
+ do Parser::new(s).read_till_eof |p| {
+ p.read_socket_addr()
+ }
+ }
+}
+
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use from_str::FromStr;
+ use option::{Some, None};
+
+ #[test]
+ fn test_from_str_ipv4() {
+ assert_eq!(Some(Ipv4Addr(127, 0, 0, 1)), FromStr::from_str("127.0.0.1"));
+ assert_eq!(Some(Ipv4Addr(255, 255, 255, 255)), FromStr::from_str("255.255.255.255"));
+ assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0"));
+
+ // out of range
+ assert_eq!(None, FromStr::from_str::<IpAddr>("256.0.0.1"));
+ // too short
+ assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0"));
+ // too long
+ assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0.1.2"));
+ // no number between dots
+ assert_eq!(None, FromStr::from_str::<IpAddr>("255.0..1"));
+ }
+
+ #[test]
+ fn test_from_str_ipv6() {
+ assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("0:0:0:0:0:0:0:0"));
+ assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("0:0:0:0:0:0:0:1"));
+
+ assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("::1"));
+ assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("::"));
+
+ assert_eq!(Some(Ipv6Addr(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)),
+ FromStr::from_str("2a02:6b8::11:11"));
+
+ // too long group
+ assert_eq!(None, FromStr::from_str::<IpAddr>("::00000"));
+ // too short
+ assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7"));
+ // too long
+ assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7:8:9"));
+ // triple colon
+ assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:::6:7:8"));
+ // two double colons
+ assert_eq!(None, FromStr::from_str::<IpAddr>("1:2::6::8"));
+ }
+
+ #[test]
+ fn test_from_str_ipv4_in_ipv6() {
+ assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 49152, 545)),
+ FromStr::from_str("::192.0.2.33"));
+ assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)),
+ FromStr::from_str("::FFFF:192.0.2.33"));
+ assert_eq!(Some(Ipv6Addr(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
+ FromStr::from_str("64:ff9b::192.0.2.33"));
+ assert_eq!(Some(Ipv6Addr(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
+ FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33"));
+
+ // colon after v4
+ assert_eq!(None, FromStr::from_str::<IpAddr>("::127.0.0.1:"));
+ // not enought groups
+ assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:127.0.0.1"));
+ // too many groups
+ assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:6:7:127.0.0.1"));
+ }
+
+ #[test]
+ fn test_from_str_socket_addr() {
+ assert_eq!(Some(SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 80 }),
+ FromStr::from_str("77.88.21.11:80"));
+ assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }),
+ FromStr::from_str("[2a02:6b8:0:1::1]:53"));
+ assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0x7F00, 1), port: 22 }),
+ FromStr::from_str("[::127.0.0.1]:22"));
+
+ // without port
+ assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1"));
+ // without port
+ assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:"));
+ // wrong brackets around v4
+ assert_eq!(None, FromStr::from_str::<SocketAddr>("[127.0.0.1]:22"));
+ // port out of range
+ assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:123456"));
+ }
+}
|| {
// Prefer to check tombstones that were there first,
// being "more fair" at the expense of tail-recursion.
- others.take().map_consume_default(true, |f| f()) && {
+ others.take().map_move_default(true, |f| f()) && {
let mut inner = this.take().unwrap();
(!inner.any_child_failed) &&
- inner.child_tombstones.take_map_default(true, |f| f())
+ inner.child_tombstones.take().map_move_default(true, |f| f())
}
}
}
let others = Cell::new(other_tombstones); // :(
|| {
// Prefer fairness to tail-recursion, as in above case.
- others.take().map_consume_default(true, |f| f()) &&
+ others.take().map_move_default(true, |f| f()) &&
f.take()()
}
}
{ use util; util::ignore(group); }
// Step 1. Decide if we need to collect child failures synchronously.
- do self.on_exit.take_map |on_exit| {
+ do self.on_exit.take().map_move |on_exit| {
if success {
// We succeeded, but our children might not. Need to wait for them.
let mut inner = self.kill_handle.take_unwrap().unwrap();
success = false;
} else {
// Lockless access to tombstones protected by unwrap barrier.
- success = inner.child_tombstones.take_map_default(true, |f| f());
+ success = inner.child_tombstones.take().map_move_default(true, |f| f());
}
}
on_exit(success);
// Step 2. Possibly alert possibly-watching parent to failure status.
// Note that as soon as parent_handle goes out of scope, the parent
// can successfully unwrap its handle and collect our reported status.
- do self.watching_parent.take_map |mut parent_handle| {
+ do self.watching_parent.take().map_move |mut parent_handle| {
if success {
// Our handle might be None if we had an exit callback, and
// already unwrapped it. But 'success' being true means no
// child failed, so there's nothing to do (see below case).
- do self.kill_handle.take_map |own_handle| {
+ do self.kill_handle.take().map_move |own_handle| {
own_handle.reparent_children_to(&mut parent_handle);
};
} else {
#[inline]
pub fn assert_may_sleep(&self) {
if self.wont_sleep != 0 {
- rtabort!("illegal atomic-sleep: can't deschedule inside atomically()");
+ rtabort!("illegal atomic-sleep: attempt to reschedule while \
+ using an Exclusive or LittleLock");
}
}
}
// Test cases don't care about the spare killed flag.
fn make_kill_handle() -> KillHandle { let (h,_) = KillHandle::new(); h }
+ #[ignore(reason = "linked failure")]
#[test]
fn no_tombstone_success() {
do run_in_newsched_task {
}
}
+ #[ignore(reason = "linked failure")]
#[test]
fn block_and_get_killed() {
do with_test_task |mut task| {
}
}
+ #[ignore(reason = "linked failure")]
#[test]
fn block_already_killed() {
do with_test_task |mut task| {
}
}
+ #[ignore(reason = "linked failure")]
#[test]
fn block_unkillably_and_get_killed() {
do with_test_task |mut task| {
}
}
+ #[ignore(reason = "linked failure")]
#[test]
fn block_on_pipe() {
// Tests the "killable" path of casting to/from uint.
}
}
+ #[ignore(reason = "linked failure")]
#[test]
fn block_unkillably_on_pipe() {
// Tests the "indestructible" path of casting to/from uint.
#[cfg(test)]
mod test {
+ use option::None;
use unstable::run_in_bare_thread;
use rt::test::*;
use super::*;
do run_in_bare_thread {
local_ptr::init_tls_key();
let mut sched = ~new_test_uv_sched();
- let task = ~Task::new_root(&mut sched.stack_pool, || {});
+ let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
Local::put(task);
let task: ~Task = Local::take();
cleanup_task(task);
do run_in_bare_thread {
local_ptr::init_tls_key();
let mut sched = ~new_test_uv_sched();
- let task = ~Task::new_root(&mut sched.stack_pool, || {});
+ let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
Local::put(task);
let task: ~Task = Local::take();
cleanup_task(task);
- let task = ~Task::new_root(&mut sched.stack_pool, || {});
+ let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
Local::put(task);
let task: ~Task = Local::take();
cleanup_task(task);
do run_in_bare_thread {
local_ptr::init_tls_key();
let mut sched = ~new_test_uv_sched();
- let task = ~Task::new_root(&mut sched.stack_pool, || {});
+ let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
Local::put(task);
unsafe {
do run_in_bare_thread {
local_ptr::init_tls_key();
let mut sched = ~new_test_uv_sched();
- let task = ~Task::new_root(&mut sched.stack_pool, || {});
+ let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
Local::put(task);
let res = do Local::borrow::<Task,bool> |_task| {
use cell::Cell;
use clone::Clone;
use container::Container;
-use iter::Times;
-use iterator::{Iterator, IteratorUtil};
+use iterator::{Iterator, IteratorUtil, range};
use option::{Some, None};
use ptr::RawPtr;
use rt::local::Local;
// Need to propagate the unsafety to `start`.
unsafe {
args::init(argc, argv);
+ env::init();
logging::init(crate_map);
rust_update_gc_metadata(crate_map);
}
let main = Cell::new(main);
- // The shared list of sleeping schedulers. Schedulers wake each other
- // occassionally to do new work.
+ // The shared list of sleeping schedulers.
let sleepers = SleeperList::new();
- // The shared work queue. Temporary until work stealing is implemented.
- let work_queue = WorkQueue::new();
+
+ // Create a work queue for each scheduler, ntimes. Create an extra
+ // for the main thread if that flag is set. We won't steal from it.
+ let mut work_queues = ~[];
+ for _ in range(0u, nscheds) {
+ let work_queue: WorkQueue<~Task> = WorkQueue::new();
+ work_queues.push(work_queue);
+ }
// The schedulers.
let mut scheds = ~[];
// sent the Shutdown message to terminate the schedulers.
let mut handles = ~[];
- do nscheds.times {
+ for i in range(0u, nscheds) {
rtdebug!("inserting a regular scheduler");
// Every scheduler is driven by an I/O event loop.
let loop_ = ~UvEventLoop::new();
- let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
+ let mut sched = ~Scheduler::new(loop_,
+ work_queues[i].clone(),
+ work_queues.clone(),
+ sleepers.clone());
let handle = sched.make_handle();
scheds.push(sched);
let friend_handle = friend_sched.make_handle();
scheds.push(friend_sched);
+ // This scheduler needs a queue that isn't part of the stealee
+ // set.
+ let work_queue = WorkQueue::new();
+
let main_loop = ~UvEventLoop::new();
let mut main_sched = ~Scheduler::new_special(main_loop,
- work_queue.clone(),
+ work_queue,
+ work_queues.clone(),
sleepers.clone(),
false,
Some(friend_handle));
// In the case where we do not use a main_thread scheduler we
// run the main task in one of our threads.
- let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
- main.take());
+ let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, main.take());
main_task.death.on_exit = Some(on_exit.take());
let main_task_cell = Cell::new(main_task);
let sched_cell = Cell::new(sched);
let thread = do Thread::start {
let mut sched = sched_cell.take();
- let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || {
+ let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
rtdebug!("boostraping a non-primary scheduler");
};
sched.bootstrap(bootstrap_task);
let mut main_sched = main_sched.unwrap();
let home = Sched(main_sched.make_handle());
- let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool,
+ let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None,
home, main.take());
main_task.death.on_exit = Some(on_exit.take());
- rtdebug!("boostrapping main_task");
+ rtdebug!("bootstrapping main_task");
main_sched.bootstrap(main_task);
}
use cast::{transmute, transmute_mut_region, transmute_mut_unsafe};
use clone::Clone;
use unstable::raw;
-
use super::sleeper_list::SleeperList;
use super::work_queue::WorkQueue;
use super::stack::{StackPool};
use rt::metrics::SchedMetrics;
use borrow::{to_uint};
use cell::Cell;
+use rand::{XorShiftRng, RngUtil};
+use iterator::{range};
+use vec::{OwnedVector};
/// The Scheduler is responsible for coordinating execution of Coroutines
/// on a single thread. When the scheduler is running it is owned by
/// XXX: This creates too many callbacks to run_sched_once, resulting
/// in too much allocation and too many events.
pub struct Scheduler {
- /// A queue of available work. Under a work-stealing policy there
- /// is one per Scheduler.
- work_queue: WorkQueue<~Task>,
+ /// There are N work queues, one per scheduler.
+ priv work_queue: WorkQueue<~Task>,
+ /// Work queues for the other schedulers. These are created by
+ /// cloning the core work queues.
+ work_queues: ~[WorkQueue<~Task>],
/// The queue of incoming messages from other schedulers.
/// These are enqueued by SchedHandles after which a remote callback
/// is triggered to handle the message.
run_anything: bool,
/// If the scheduler shouldn't run some tasks, a friend to send
/// them to.
- friend_handle: Option<SchedHandle>
+ friend_handle: Option<SchedHandle>,
+ /// A fast XorShift rng for scheduler use
+ rng: XorShiftRng
+
}
pub struct SchedHandle {
pub fn new(event_loop: ~EventLoopObject,
work_queue: WorkQueue<~Task>,
+ work_queues: ~[WorkQueue<~Task>],
sleeper_list: SleeperList)
-> Scheduler {
- Scheduler::new_special(event_loop, work_queue, sleeper_list, true, None)
+ Scheduler::new_special(event_loop, work_queue,
+ work_queues,
+ sleeper_list, true, None)
}
// task field is None.
pub fn new_special(event_loop: ~EventLoopObject,
work_queue: WorkQueue<~Task>,
+ work_queues: ~[WorkQueue<~Task>],
sleeper_list: SleeperList,
run_anything: bool,
friend: Option<SchedHandle>)
no_sleep: false,
event_loop: event_loop,
work_queue: work_queue,
+ work_queues: work_queues,
stack_pool: StackPool::new(),
sched_task: None,
cleanup_job: None,
metrics: SchedMetrics::new(),
run_anything: run_anything,
- friend_handle: friend
+ friend_handle: friend,
+ rng: XorShiftRng::new()
}
}
// Second activity is to try resuming a task from the queue.
- let result = sched.resume_task_from_queue();
+ let result = sched.do_work();
let mut sched = match result {
Some(sched) => {
// Failed to dequeue a task, so we return.
/// As enqueue_task, but with the possibility for the blocked task to
/// already have been killed.
pub fn enqueue_blocked_task(&mut self, blocked_task: BlockedTask) {
- do blocked_task.wake().map_consume |task| {
+ do blocked_task.wake().map_move |task| {
self.enqueue_task(task);
};
}
}
}
- // Resume a task from the queue - but also take into account that
- // it might not belong here.
+ // Workstealing: In this iteration of the runtime each scheduler
+ // thread has a distinct work queue. When no work is available
+ // locally, make a few attempts to steal work from the queues of
+ // other scheduler threads. If a few steals fail we end up in the
+ // old "no work" path which is fine.
+
+ // First step in the process is to find a task. This function does
+ // that by first checking the local queue, and if there is no work
+ // there, trying to steal from the remote work queues.
+ fn find_work(&mut self) -> Option<~Task> {
+ rtdebug!("scheduler looking for work");
+ match self.work_queue.pop() {
+ Some(task) => {
+ rtdebug!("found a task locally");
+ return Some(task)
+ }
+ None => {
+ // Our naive stealing, try kinda hard.
+ rtdebug!("scheduler trying to steal");
+ let _len = self.work_queues.len();
+ return self.try_steals(2);
+ }
+ }
+ }
+
+ // With no backoff try stealing n times from the queues the
+ // scheduler knows about. This naive implementation can steal from
+ // our own queue or from other special schedulers.
+ fn try_steals(&mut self, n: uint) -> Option<~Task> {
+ for _ in range(0, n) {
+ let index = self.rng.gen_uint_range(0, self.work_queues.len());
+ let work_queues = &mut self.work_queues;
+ match work_queues[index].steal() {
+ Some(task) => {
+ rtdebug!("found task by stealing"); return Some(task)
+ }
+ None => ()
+ }
+ };
+ rtdebug!("giving up on stealing");
+ return None;
+ }
- // If we perform a scheduler action we give away the scheduler ~
- // pointer, if it is still available we return it.
+ // Given a task, execute it correctly.
+ fn process_task(~self, task: ~Task) -> Option<~Scheduler> {
+ let mut this = self;
+ let mut task = task;
- fn resume_task_from_queue(~self) -> Option<~Scheduler> {
+ rtdebug!("processing a task");
+ let home = task.take_unwrap_home();
+ match home {
+ Sched(home_handle) => {
+ if home_handle.sched_id != this.sched_id() {
+ rtdebug!("sending task home");
+ task.give_home(Sched(home_handle));
+ Scheduler::send_task_home(task);
+ return Some(this);
+ } else {
+ rtdebug!("running task here");
+ task.give_home(Sched(home_handle));
+ this.resume_task_immediately(task);
+ return None;
+ }
+ }
+ AnySched if this.run_anything => {
+ rtdebug!("running anysched task here");
+ task.give_home(AnySched);
+ this.resume_task_immediately(task);
+ return None;
+ }
+ AnySched => {
+ rtdebug!("sending task to friend");
+ task.give_home(AnySched);
+ this.send_to_friend(task);
+ return Some(this);
+ }
+ }
+ }
+
+ // Bundle the helpers together.
+ fn do_work(~self) -> Option<~Scheduler> {
let mut this = self;
- match this.work_queue.pop() {
+ rtdebug!("scheduler calling do work");
+ match this.find_work() {
Some(task) => {
- let mut task = task;
- let home = task.take_unwrap_home();
- match home {
- Sched(home_handle) => {
- if home_handle.sched_id != this.sched_id() {
- task.give_home(Sched(home_handle));
- Scheduler::send_task_home(task);
- return Some(this);
- } else {
- this.event_loop.callback(Scheduler::run_sched_once);
- task.give_home(Sched(home_handle));
- this.resume_task_immediately(task);
- return None;
- }
- }
- AnySched if this.run_anything => {
- this.event_loop.callback(Scheduler::run_sched_once);
- task.give_home(AnySched);
- this.resume_task_immediately(task);
- return None;
- }
- AnySched => {
- task.give_home(AnySched);
- this.send_to_friend(task);
- return Some(this);
- }
- }
+ rtdebug!("found some work! processing the task");
+ return this.process_task(task);
}
None => {
+ rtdebug!("no work was found, returning the scheduler struct");
return Some(this);
}
}
sched.enqueue_blocked_task(last_task);
}
};
- opt.map_consume(Local::put);
+ opt.map_move(Local::put);
}
// The primary function for changing contexts. In the current
GiveTask(task, f) => f.to_fn()(self, task)
}
}
-
}
// The cases for the below function.
#[cfg(test)]
mod test {
+ extern mod extra;
+
use prelude::*;
use rt::test::*;
use unstable::run_in_bare_thread;
let mut sched = ~new_test_uv_sched();
let sched_handle = sched.make_handle();
- let mut task = ~do Task::new_root_homed(&mut sched.stack_pool,
+ let mut task = ~do Task::new_root_homed(&mut sched.stack_pool, None,
Sched(sched_handle)) {
unsafe { *task_ran_ptr = true };
assert!(Task::on_appropriate_sched());
do run_in_bare_thread {
let sleepers = SleeperList::new();
- let work_queue = WorkQueue::new();
+ let normal_queue = WorkQueue::new();
+ let special_queue = WorkQueue::new();
+ let queues = ~[normal_queue.clone(), special_queue.clone()];
// Our normal scheduler
let mut normal_sched = ~Scheduler::new(
~UvEventLoop::new(),
- work_queue.clone(),
+ normal_queue,
+ queues.clone(),
sleepers.clone());
let normal_handle = Cell::new(normal_sched.make_handle());
// Our special scheduler
let mut special_sched = ~Scheduler::new_special(
~UvEventLoop::new(),
- work_queue.clone(),
+ special_queue.clone(),
+ queues.clone(),
sleepers.clone(),
false,
Some(friend_handle));
// 3) task not homed, sched requeues
// 4) task not home, send home
- let task1 = ~do Task::new_root_homed(&mut special_sched.stack_pool,
+ let task1 = ~do Task::new_root_homed(&mut special_sched.stack_pool, None,
Sched(t1_handle)) || {
rtassert!(Task::on_appropriate_sched());
};
rtdebug!("task1 id: **%u**", borrow::to_uint(task1));
- let task2 = ~do Task::new_root(&mut normal_sched.stack_pool) {
+ let task2 = ~do Task::new_root(&mut normal_sched.stack_pool, None) {
rtassert!(Task::on_appropriate_sched());
};
- let task3 = ~do Task::new_root(&mut normal_sched.stack_pool) {
+ let task3 = ~do Task::new_root(&mut normal_sched.stack_pool, None) {
rtassert!(Task::on_appropriate_sched());
};
- let task4 = ~do Task::new_root_homed(&mut special_sched.stack_pool,
+ let task4 = ~do Task::new_root_homed(&mut special_sched.stack_pool, None,
Sched(t4_handle)) {
rtassert!(Task::on_appropriate_sched());
};
let port = Cell::new(port);
let chan = Cell::new(chan);
- let normal_task = ~do Task::new_root(&mut normal_sched.stack_pool) {
+ let normal_task = ~do Task::new_root(&mut normal_sched.stack_pool, None) {
rtdebug!("*about to submit task2*");
Scheduler::run_task(task2.take());
rtdebug!("*about to submit task4*");
rtdebug!("normal task: %u", borrow::to_uint(normal_task));
- let special_task = ~do Task::new_root(&mut special_sched.stack_pool) {
+ let special_task = ~do Task::new_root(&mut special_sched.stack_pool, None) {
rtdebug!("*about to submit task1*");
Scheduler::run_task(task1.take());
rtdebug!("*about to submit task3*");
fn select_stream() {
use util;
use comm::GenericChan;
+ use iter::Times;
// Sends 10 buffered packets, and uses select to retrieve them all.
// Puts the port in a different spot in the vector each time.
// get it back out
util::swap(port.get_mut_ref(), &mut ports[index]);
// NB. Not recv(), because optimistic_check randomly fails.
- let (data, new_port) = port.take_unwrap().recv_ready().unwrap();
- assert!(data == 31337);
- port = Some(new_port);
+ assert!(port.get_ref().recv_ready().unwrap() == 31337);
}
}
}
fn select_racing_senders_helper(killable: bool, send_on_chans: ~[uint]) {
use rt::test::spawntask_random;
+ use iter::Times;
do run_in_newsched_task {
// A bit of stress, since ordinarily this is just smoke and mirrors.
use ptr;
use prelude::*;
use option::{Option, Some, None};
+use rt::env;
use rt::kill::Death;
use rt::local::Local;
use rt::logging::StdErrLogger;
// A helper to build a new task using the dynamically found
// scheduler and task. Only works in GreenTask context.
- pub fn build_homed_child(f: ~fn(), home: SchedHome) -> ~Task {
+ pub fn build_homed_child(stack_size: Option<uint>, f: ~fn(), home: SchedHome) -> ~Task {
let f = Cell::new(f);
let home = Cell::new(home);
do Local::borrow::<Task, ~Task> |running_task| {
let mut sched = running_task.sched.take_unwrap();
let new_task = ~running_task.new_child_homed(&mut sched.stack_pool,
+ stack_size,
home.take(),
f.take());
running_task.sched = Some(sched);
}
}
- pub fn build_child(f: ~fn()) -> ~Task {
- Task::build_homed_child(f, AnySched)
+ pub fn build_child(stack_size: Option<uint>, f: ~fn()) -> ~Task {
+ Task::build_homed_child(stack_size, f, AnySched)
}
- pub fn build_homed_root(f: ~fn(), home: SchedHome) -> ~Task {
+ pub fn build_homed_root(stack_size: Option<uint>, f: ~fn(), home: SchedHome) -> ~Task {
let f = Cell::new(f);
let home = Cell::new(home);
do Local::borrow::<Task, ~Task> |running_task| {
let mut sched = running_task.sched.take_unwrap();
let new_task = ~Task::new_root_homed(&mut sched.stack_pool,
- home.take(),
- f.take());
+ stack_size,
+ home.take(),
+ f.take());
running_task.sched = Some(sched);
new_task
}
}
- pub fn build_root(f: ~fn()) -> ~Task {
- Task::build_homed_root(f, AnySched)
+ pub fn build_root(stack_size: Option<uint>, f: ~fn()) -> ~Task {
+ Task::build_homed_root(stack_size, f, AnySched)
}
pub fn new_sched_task() -> Task {
}
pub fn new_root(stack_pool: &mut StackPool,
+ stack_size: Option<uint>,
start: ~fn()) -> Task {
- Task::new_root_homed(stack_pool, AnySched, start)
+ Task::new_root_homed(stack_pool, stack_size, AnySched, start)
}
pub fn new_child(&mut self,
stack_pool: &mut StackPool,
+ stack_size: Option<uint>,
start: ~fn()) -> Task {
- self.new_child_homed(stack_pool, AnySched, start)
+ self.new_child_homed(stack_pool, stack_size, AnySched, start)
}
pub fn new_root_homed(stack_pool: &mut StackPool,
+ stack_size: Option<uint>,
home: SchedHome,
start: ~fn()) -> Task {
Task {
death: Death::new(),
destroyed: false,
name: None,
- coroutine: Some(Coroutine::new(stack_pool, start)),
+ coroutine: Some(Coroutine::new(stack_pool, stack_size, start)),
sched: None,
task_type: GreenTask(Some(~home))
}
pub fn new_child_homed(&mut self,
stack_pool: &mut StackPool,
+ stack_size: Option<uint>,
home: SchedHome,
start: ~fn()) -> Task {
Task {
death: self.death.new_child(),
destroyed: false,
name: None,
- coroutine: Some(Coroutine::new(stack_pool, start)),
+ coroutine: Some(Coroutine::new(stack_pool, stack_size, start)),
sched: None,
task_type: GreenTask(Some(~home))
}
impl Coroutine {
- pub fn new(stack_pool: &mut StackPool, start: ~fn()) -> Coroutine {
- static MIN_STACK_SIZE: uint = 3000000; // XXX: Too much stack
-
+ pub fn new(stack_pool: &mut StackPool, stack_size: Option<uint>, start: ~fn()) -> Coroutine {
+ let stack_size = match stack_size {
+ Some(size) => size,
+ None => env::min_stack()
+ };
let start = Coroutine::build_start_wrapper(start);
- let mut stack = stack_pool.take_segment(MIN_STACK_SIZE);
+ let mut stack = stack_pool.take_segment(stack_size);
let initial_context = Context::new(start, &mut stack);
Coroutine {
current_stack_segment: stack,
do run_in_newsched_task() {
static key: local_data::Key<@~str> = &local_data::Key;
local_data::set(key, @~"data");
- assert!(*local_data::get(key, |k| k.map(|&k| *k)).unwrap() == ~"data");
+ assert!(*local_data::get(key, |k| k.map_move(|k| *k)).unwrap() == ~"data");
static key2: local_data::Key<@~str> = &local_data::Key;
local_data::set(key2, @~"data");
- assert!(*local_data::get(key2, |k| k.map(|&k| *k)).unwrap() == ~"data");
+ assert!(*local_data::get(key2, |k| k.map_move(|k| *k)).unwrap() == ~"data");
}
}
use clone::Clone;
use container::Container;
use iterator::{Iterator, range};
-use vec::{OwnedVector, MutableVector};
use super::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
+use vec::{OwnedVector, MutableVector, ImmutableVector};
use rt::sched::Scheduler;
use unstable::run_in_bare_thread;
use rt::thread::Thread;
pub fn new_test_uv_sched() -> Scheduler {
+ let queue = WorkQueue::new();
+ let queues = ~[queue.clone()];
+
let mut sched = Scheduler::new(~UvEventLoop::new(),
- WorkQueue::new(),
+ queue,
+ queues,
SleeperList::new());
// Don't wait for the Shutdown message
exit_handle.take().send(Shutdown);
rtassert!(exit_status);
};
- let mut task = ~Task::new_root(&mut sched.stack_pool, f);
+ let mut task = ~Task::new_root(&mut sched.stack_pool, None, f);
task.death.on_exit = Some(on_exit);
sched.bootstrap(task);
};
let sleepers = SleeperList::new();
- let work_queue = WorkQueue::new();
let mut handles = ~[];
let mut scheds = ~[];
+ let mut work_queues = ~[];
for _ in range(0u, nthreads) {
+ let work_queue = WorkQueue::new();
+ work_queues.push(work_queue);
+ }
+
+ for i in range(0u, nthreads) {
let loop_ = ~UvEventLoop::new();
let mut sched = ~Scheduler::new(loop_,
- work_queue.clone(),
+ work_queues[i].clone(),
+ work_queues.clone(),
sleepers.clone());
let handle = sched.make_handle();
rtassert!(exit_status);
};
- let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
- f.take());
+ let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, f.take());
main_task.death.on_exit = Some(on_exit);
let mut threads = ~[];
while !scheds.is_empty() {
let mut sched = scheds.pop();
- let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || {
+ let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
rtdebug!("bootstrapping non-primary scheduler");
};
let bootstrap_task_cell = Cell::new(bootstrap_task);
/// Test tasks will abort on failure instead of unwinding
pub fn spawntask(f: ~fn()) {
- Scheduler::run_task(Task::build_child(f));
+ Scheduler::run_task(Task::build_child(None, f));
}
/// Create a new task and run it right now. Aborts on failure
pub fn spawntask_later(f: ~fn()) {
- Scheduler::run_task_later(Task::build_child(f));
+ Scheduler::run_task_later(Task::build_child(None, f));
}
pub fn spawntask_random(f: ~fn()) {
let chan = Cell::new(chan);
let on_exit: ~fn(bool) = |exit_status| chan.take().send(exit_status);
- let mut new_task = Task::build_root(f);
+ let mut new_task = Task::build_root(None, f);
new_task.death.on_exit = Some(on_exit);
Scheduler::run_task(new_task);
pub fn with_test_task(blk: ~fn(~Task) -> ~Task) {
do run_in_bare_thread {
let mut sched = ~new_test_uv_sched();
- let task = blk(~Task::new_root(&mut sched.stack_pool, ||{}));
+ let task = blk(~Task::new_root(&mut sched.stack_pool, None, ||{}));
cleanup_task(task);
}
}
use vec;
use str;
use from_str::{FromStr};
-use num;
pub enum UvSocketAddr {
UvIpv4SocketAddr(*sockaddr_in),
port as u16
};
let ip_str = str::from_bytes_slice(ip_name).trim_right_chars(&'\x00');
- let ip = match addr {
- UvIpv4SocketAddr(*) => {
- let ip: ~[u8] =
- ip_str.split_iter('.')
- .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() })
- .collect();
- assert_eq!(ip.len(), 4);
- SocketAddr {
- ip: Ipv4Addr(ip[0], ip[1], ip[2], ip[3]),
- port: ip_port
- }
- },
- UvIpv6SocketAddr(*) => {
- let ip: ~[u16] = {
- let expand_shorthand_and_convert = |s: &str| -> ~[~[u16]] {
- let convert_each_segment = |s: &str| -> ~[u16] {
- let read_hex_segment = |s: &str| -> u16 {
- num::FromStrRadix::from_str_radix(s, 16u).unwrap()
- };
- match s {
- "" => ~[],
- // IPv4-Mapped/Compatible IPv6 Address?
- s if s.find('.').is_some() => {
- let i = s.rfind(':').unwrap_or_default(-1);
-
- let b = s.slice(i + 1, s.len()); // the ipv4 part
-
- let h = b.split_iter('.')
- .transform(|s: &str| -> u8 { FromStr::from_str(s).unwrap() })
- .transform(|s: u8| -> ~str { fmt!("%02x", s as uint) })
- .collect::<~[~str]>();
-
- if i == -1 {
- // Ipv4 Compatible Address (::x.x.x.x)
- // first 96 bits are zero leaving 32 bits
- // for the ipv4 part
- // (i.e ::127.0.0.1 == ::7F00:1)
- ~[num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(),
- num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()]
- } else {
- // Ipv4-Mapped Address (::FFFF:x.x.x.x)
- // first 80 bits are zero, followed by all ones
- // for the next 16 bits, leaving 32 bits for
- // the ipv4 part
- // (i.e ::FFFF:127.0.0.1 == ::FFFF:7F00:1)
- ~[1,
- num::FromStrRadix::from_str_radix(h[0] + h[1], 16).unwrap(),
- num::FromStrRadix::from_str_radix(h[2] + h[3], 16).unwrap()]
- }
- },
- s => s.split_iter(':').transform(read_hex_segment).collect()
- }
- };
- s.split_str_iter("::").transform(convert_each_segment).collect()
- };
- match expand_shorthand_and_convert(ip_str) {
- [x] => x, // no shorthand found
- [l, r] => l + vec::from_elem(8 - l.len() - r.len(), 0u16) + r, // fill the gap
- _ => fail!(), // impossible. only one shorthand allowed.
- }
- };
- assert_eq!(ip.len(), 8);
- SocketAddr {
- ip: Ipv6Addr(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]),
- port: ip_port
- }
- },
- };
+ let ip_addr = FromStr::from_str(ip_str).unwrap();
// finally run the closure
- f(ip)
+ f(SocketAddr { ip: ip_addr, port: ip_port })
}
pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr {
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
use libc::funcs::bsd44::getdtablesize;
- use int;
mod rustrt {
use libc::c_void;
fail!("failure in dup3(err_fd, 2): %s", os::last_os_error());
}
// close all other fds
- do int::range_rev(getdtablesize() as int, 3) |fd| {
+ for fd in range(3, getdtablesize()).invert() {
close(fd as c_int);
- true
- };
+ }
do with_dirp(dir) |dirp| {
if !dirp.is_null() && chdir(dirp) == -1 {
}
#[cfg(windows)]
-priv fn free_handle(handle: *()) {
+fn free_handle(handle: *()) {
unsafe {
libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
}
}
#[cfg(unix)]
-priv fn free_handle(_handle: *()) {
+fn free_handle(_handle: *()) {
// unix has no process handle object, just a pid
}
* operate on a none-existant process or, even worse, on a newer process
* with the same id.
*/
-priv fn waitpid(pid: pid_t) -> int {
+fn waitpid(pid: pid_t) -> int {
return waitpid_os(pid);
#[cfg(windows)]
pub mod run;
pub mod sys;
pub mod cast;
+pub mod fmt;
pub mod repr;
pub mod cleanup;
pub mod reflect;
pub use unstable;
pub use str;
pub use os;
+ pub use fmt;
+ pub use to_bytes;
}
}
// https://tools.ietf.org/html/rfc3629
-priv static UTF8_CHAR_WIDTH: [u8, ..256] = [
+static UTF8_CHAR_WIDTH: [u8, ..256] = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
)
// UTF-8 tags and ranges
-priv static TAG_CONT_U8: u8 = 128u8;
-priv static TAG_CONT: uint = 128u;
-priv static MAX_ONE_B: uint = 128u;
-priv static TAG_TWO_B: uint = 192u;
-priv static MAX_TWO_B: uint = 2048u;
-priv static TAG_THREE_B: uint = 224u;
-priv static MAX_THREE_B: uint = 65536u;
-priv static TAG_FOUR_B: uint = 240u;
-priv static MAX_UNICODE: uint = 1114112u;
+static TAG_CONT_U8: u8 = 128u8;
+static TAG_CONT: uint = 128u;
+static MAX_ONE_B: uint = 128u;
+static TAG_TWO_B: uint = 192u;
+static MAX_TWO_B: uint = 2048u;
+static TAG_THREE_B: uint = 224u;
+static MAX_THREE_B: uint = 65536u;
+static TAG_FOUR_B: uint = 240u;
+static MAX_UNICODE: uint = 1114112u;
/// Unsafe operations
pub mod raw {
} else {
self.matches_index_iter(needle)
.next()
- .map_consume(|(start, _end)| start)
+ .map_move(|(start, _end)| start)
}
}
fn test_add() {
#[allow(unnecessary_allocation)];
macro_rules! t (
- ($s1:expr, $s2:expr, $e:expr) => {
- assert_eq!($s1 + $s2, $e);
- assert_eq!($s1.to_owned() + $s2, $e);
- assert_eq!($s1.to_managed() + $s2, $e);
- }
+ ($s1:expr, $s2:expr, $e:expr) => { {
+ let s1 = $s1;
+ let s2 = $s2;
+ let e = $e;
+ assert_eq!(s1 + s2, e.to_owned());
+ assert_eq!(s1.to_owned() + s2, e.to_owned());
+ assert_eq!(s1.to_managed() + s2, e.to_owned());
+ } }
);
- t!("foo", "bar", ~"foobar");
- t!("foo", @"bar", ~"foobar");
- t!("foo", ~"bar", ~"foobar");
- t!("ศไทย中", "华Việt Nam", ~"ศไทย中华Việt Nam");
- t!("ศไทย中", @"华Việt Nam", ~"ศไทย中华Việt Nam");
- t!("ศไทย中", ~"华Việt Nam", ~"ศไทย中华Việt Nam");
+ t!("foo", "bar", "foobar");
+ t!("foo", @"bar", "foobar");
+ t!("foo", ~"bar", "foobar");
+ t!("ศไทย中", "华Việt Nam", "ศไทย中华Việt Nam");
+ t!("ศไทย中", @"华Việt Nam", "ศไทย中华Việt Nam");
+ t!("ศไทย中", ~"华Việt Nam", "ศไทย中华Việt Nam");
}
#[test]
use to_str::{ToStr,ToStrConsume};
use str;
use str::StrSlice;
+use str::OwnedStr;
+use container::Container;
use cast;
+use ptr;
use iterator::{Iterator, IteratorUtil};
use vec::{CopyableVector, ImmutableVector, OwnedVector};
use to_bytes::IterBytes;
/// Convert to lowercase.
#[inline]
pub fn to_lower(self) -> Ascii {
- if self.chr >= 65 && self.chr <= 90 {
- Ascii{chr: self.chr | 0x20 }
- } else {
- self
- }
+ Ascii{chr: ASCII_LOWER_MAP[self.chr]}
}
/// Convert to uppercase.
#[inline]
pub fn to_upper(self) -> Ascii {
- if self.chr >= 97 && self.chr <= 122 {
- Ascii{chr: self.chr & !0x20 }
- } else {
- self
- }
+ Ascii{chr: ASCII_UPPER_MAP[self.chr]}
}
/// Compares two ascii characters of equality, ignoring case.
#[inline]
pub fn eq_ignore_case(self, other: Ascii) -> bool {
- self.to_lower().chr == other.to_lower().chr
+ ASCII_LOWER_MAP[self.chr] == ASCII_LOWER_MAP[other.chr]
}
}
}
}
+
+/// Convert the string to ASCII upper case:
+/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+/// but non-ASCII letters are unchanged.
+#[inline]
+pub fn to_ascii_upper(string: &str) -> ~str {
+ map_bytes(string, ASCII_UPPER_MAP)
+}
+
+/// Convert the string to ASCII lower case:
+/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+/// but non-ASCII letters are unchanged.
+#[inline]
+pub fn to_ascii_lower(string: &str) -> ~str {
+ map_bytes(string, ASCII_LOWER_MAP)
+}
+
+#[inline]
+fn map_bytes(string: &str, map: &'static [u8]) -> ~str {
+ let len = string.len();
+ let mut result = str::with_capacity(len);
+ unsafe {
+ do result.as_mut_buf |mut buf, _| {
+ for c in string.as_bytes().iter() {
+ *buf = map[*c];
+ buf = ptr::mut_offset(buf, 1)
+ }
+ }
+ str::raw::set_len(&mut result, len);
+ }
+ result
+}
+
+/// Check that two strings are an ASCII case-insensitive match.
+/// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
+/// but without allocating and copying temporary strings.
+#[inline]
+pub fn eq_ignore_ascii_case(a: &str, b: &str) -> bool {
+ a.len() == b.len() && a.as_bytes().iter().zip(b.as_bytes().iter()).all(
+ |(byte_a, byte_b)| ASCII_LOWER_MAP[*byte_a] == ASCII_LOWER_MAP[*byte_b])
+}
+
+static ASCII_LOWER_MAP: &'static [u8] = &[
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+static ASCII_UPPER_MAP: &'static [u8] = &[
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+
#[cfg(test)]
mod tests {
use super::*;
use to_bytes::ToBytes;
+ use str::from_char;
macro_rules! v2ascii (
( [$($e:expr),*]) => ( [$(Ascii{chr:$e}),*]);
#[test] #[should_fail]
fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
+
+ #[test]
+ fn test_to_ascii_upper() {
+ assert_eq!(to_ascii_upper("url()URL()uRl()ürl"), ~"URL()URL()URL()üRL");
+ assert_eq!(to_ascii_upper("hıKß"), ~"HıKß");
+
+ let mut i = 0;
+ while i <= 500 {
+ let c = i as char;
+ let upper = if 'a' <= c && c <= 'z' { c + 'A' - 'a' } else { c };
+ assert_eq!(to_ascii_upper(from_char(i as char)), from_char(upper))
+ i += 1;
+ }
+ }
+
+ #[test]
+ fn test_to_ascii_lower() {
+ assert_eq!(to_ascii_lower("url()URL()uRl()Ürl"), ~"url()url()url()Ürl");
+ // Dotted capital I, Kelvin sign, Sharp S.
+ assert_eq!(to_ascii_lower("HİKß"), ~"hİKß");
+
+ let mut i = 0;
+ while i <= 500 {
+ let c = i as char;
+ let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c };
+ assert_eq!(to_ascii_lower(from_char(i as char)), from_char(lower))
+ i += 1;
+ }
+ }
+
+
+ #[test]
+ fn test_eq_ignore_ascii_case() {
+ assert!(eq_ignore_ascii_case("url()URL()uRl()Ürl", "url()url()url()Ürl"));
+ assert!(!eq_ignore_ascii_case("Ürl", "ürl"));
+ // Dotted capital I, Kelvin sign, Sharp S.
+ assert!(eq_ignore_ascii_case("HİKß", "hİKß"));
+ assert!(!eq_ignore_ascii_case("İ", "i"));
+ assert!(!eq_ignore_ascii_case("K", "k"));
+ assert!(!eq_ignore_ascii_case("ß", "s"));
+
+ let mut i = 0;
+ while i <= 500 {
+ let c = i as char;
+ let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c };
+ assert!(eq_ignore_ascii_case(from_char(i as char), from_char(lower)));
+ i += 1;
+ }
+ }
}
indestructible: bool,
notify_chan: Option<Chan<TaskResult>>,
name: Option<~str>,
- sched: SchedOpts
+ sched: SchedOpts,
+ stack_size: Option<uint>
}
/**
indestructible: self.opts.indestructible,
notify_chan: notify_chan,
name: name,
- sched: self.opts.sched
+ sched: self.opts.sched,
+ stack_size: self.opts.stack_size
},
gen_body: gen_body,
can_not_copy: None,
indestructible: x.opts.indestructible,
notify_chan: notify_chan,
name: name,
- sched: x.opts.sched
+ sched: x.opts.sched,
+ stack_size: x.opts.stack_size
};
let f = match gen_body {
Some(gen) => {
name: None,
sched: SchedOpts {
mode: DefaultScheduler,
- }
+ },
+ stack_size: None
}
}
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_kill_unkillable_task() {
use rt::test::*;
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_kill_rekillable_task() {
use rt::test::*;
#[cfg(test)]
fn block_forever() { let (po, _ch) = stream::<()>(); po.recv(); }
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_unlinked_unsup_no_fail_down() { // grandchild sends on a port
use rt::test::run_in_newsched_task;
po.recv();
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_unlinked_unsup_no_fail_up() { // child unlinked fails
use rt::test::run_in_newsched_task;
do spawn_unlinked { fail!(); }
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_unlinked_sup_no_fail_up() { // child unlinked fails
use rt::test::run_in_newsched_task;
do 16.times { task::yield(); }
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_unlinked_sup_fail_down() {
use rt::test::run_in_newsched_task;
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_linked_sup_fail_up() { // child fails; parent fails
use rt::test::run_in_newsched_task;
assert!(result.is_err());
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_linked_sup_fail_down() { // parent fails; child fails
use rt::test::run_in_newsched_task;
assert!(result.is_err());
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_linked_unsup_fail_up() { // child fails; parent fails
use rt::test::run_in_newsched_task;
assert!(result.is_err());
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_linked_unsup_fail_down() { // parent fails; child fails
use rt::test::run_in_newsched_task;
assert!(result.is_err());
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_linked_unsup_default_opts() { // parent fails; child fails
use rt::test::run_in_newsched_task;
// A couple bonus linked failure tests - testing for failure propagation even
// when the middle task exits successfully early before kill signals are sent.
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_failure_propagate_grandchild() {
use rt::test::run_in_newsched_task;
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_failure_propagate_secondborn() {
use rt::test::run_in_newsched_task;
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_failure_propagate_nephew_or_niece() {
use rt::test::run_in_newsched_task;
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_linked_sup_propagate_sibling() {
use rt::test::run_in_newsched_task;
}
}
+#[ignore(reason = "linked failure")]
#[test]
#[ignore(cfg(windows))]
#[should_fail]
po.recv();
}
+#[ignore(reason = "linked failure")]
#[test]
#[ignore(cfg(windows))]
#[should_fail]
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_spawn_watched() {
use rt::test::run_in_newsched_task;
}
}
+#[ignore(reason = "linked failure")]
#[test] #[ignore(cfg(windows))]
fn test_indestructible() {
use rt::test::run_in_newsched_task;
use rt::sched::Scheduler;
use rt::uv::uvio::UvEventLoop;
use rt::thread::Thread;
+use rt::work_queue::WorkQueue;
#[cfg(test)] use task::default_task_opts;
#[cfg(test)] use comm;
OldTask(ptr) => rt::rust_task_kill_other(ptr),
NewTask(handle) => {
let mut handle = handle;
- do handle.kill().map_consume |killed_task| {
+ do handle.kill().map_move |killed_task| {
let killed_task = Cell::new(killed_task);
do Local::borrow::<Scheduler, ()> |sched| {
sched.enqueue_task(killed_task.take());
// Child task runs this code.
// If child data is 'None', the enlist is vacuously successful.
- let enlist_success = do child_data.take().map_consume_default(true) |child_data| {
+ let enlist_success = do child_data.take().map_move_default(true) |child_data| {
let child_data = Cell::new(child_data); // :(
do Local::borrow::<Task, bool> |me| {
let (child_tg, ancestors, is_main) = child_data.take();
let mut task = unsafe {
if opts.sched.mode != SingleThreaded {
if opts.watched {
- Task::build_child(child_wrapper)
+ Task::build_child(opts.stack_size, child_wrapper)
} else {
- Task::build_root(child_wrapper)
+ Task::build_root(opts.stack_size, child_wrapper)
}
} else {
// Creating a 1:1 task:thread ...
let sched = Local::unsafe_borrow::<Scheduler>();
let sched_handle = (*sched).make_handle();
+ // Since this is a 1:1 scheduler we create a queue not in
+ // the stealee set. The run_anything flag is set false
+ // which will disable stealing.
+ let work_queue = WorkQueue::new();
+
// Create a new scheduler to hold the new task
let new_loop = ~UvEventLoop::new();
let mut new_sched = ~Scheduler::new_special(new_loop,
- (*sched).work_queue.clone(),
+ work_queue,
+ (*sched).work_queues.clone(),
(*sched).sleeper_list.clone(),
false,
Some(sched_handle));
// Pin the new task to the new scheduler
let new_task = if opts.watched {
- Task::build_homed_child(child_wrapper, Sched(new_sched_handle))
+ Task::build_homed_child(opts.stack_size, child_wrapper, Sched(new_sched_handle))
} else {
- Task::build_homed_root(child_wrapper, Sched(new_sched_handle))
+ Task::build_homed_root(opts.stack_size, child_wrapper, Sched(new_sched_handle))
};
// Create a task that will later be used to join with the new scheduler
// thread when it is ready to terminate
let (thread_port, thread_chan) = oneshot();
let thread_port_cell = Cell::new(thread_port);
- let join_task = do Task::build_child() {
+ let join_task = do Task::build_child(None) {
rtdebug!("running join task");
let thread_port = thread_port_cell.take();
let thread: Thread = thread_port.recv();
let mut orig_sched_handle = orig_sched_handle_cell.take();
let join_task = join_task_cell.take();
- let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool) || {
- rtdebug!("bootstrapping a 1:1 scheduler");
+ let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool, None) || {
+ rtdebug!("boostrapping a 1:1 scheduler");
};
new_sched.bootstrap(bootstrap_task);
// Even if the below code fails to kick the child off, we must
// send Something on the notify channel.
- let notifier = notify_chan.map_consume(|c| AutoNotify(c));
+ let notifier = notify_chan.map_move(|c| AutoNotify(c));
if enlist_many(OldTask(child), &child_arc, &mut ancestors) {
let group = @@mut Taskgroup(child_arc, ancestors, is_main, notifier);
impl<T> TrieNode<T> {
fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool {
- for idx in range(0u, self.children.len()) {
- match self.children[idx] {
+ for elt in self.children.iter() {
+ match *elt {
Internal(ref x) => if !x.each(|i,t| f(i,t)) { return false },
External(k, ref v) => if !f(&k, v) { return false },
Nothing => ()
}
fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool {
- do uint::range_rev(self.children.len(), 0) |idx| {
- match self.children[idx] {
- Internal(ref x) => x.each_reverse(|i,t| f(i,t)),
- External(k, ref v) => f(&k, v),
- Nothing => true
+ for elt in self.children.rev_iter() {
+ match *elt {
+ Internal(ref x) => if !x.each_reverse(|i,t| f(i,t)) { return false },
+ External(k, ref v) => if !f(&k, v) { return false },
+ Nothing => ()
}
}
+ true
}
fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool {
fn test_each_break() {
let mut m = TrieMap::new();
- do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| {
+ for x in range(uint::max_value - 10000, uint::max_value).invert() {
m.insert(x, x / 2);
- true
- };
+ }
let mut n = uint::max_value - 10000;
do m.each |k, v| {
fn test_each_reverse_break() {
let mut m = TrieMap::new();
- do uint::range_rev(uint::max_value, uint::max_value - 10000) |x| {
+ for x in range(uint::max_value - 10000, uint::max_value).invert() {
m.insert(x, x / 2);
- true
- };
+ }
let mut n = uint::max_value - 1;
do m.each_reverse |k, v| {
let last = uint::max_value;
let mut map = TrieMap::new();
- do uint::range_rev(last, first) |x| {
+ for x in range(first, last).invert() {
map.insert(x, x / 2);
- true
- };
+ }
let mut i = 0;
for (k, &v) in map.iter() {
/// Get the address of the `__morestack` stack growth function.
pub fn morestack_addr() -> *();
- /// Adjust a pointer by an offset.
+ /// Calculates the offset from a pointer.
///
/// This is implemented as an intrinsic to avoid converting to and from an
/// integer, since the conversion would throw away aliasing information.
pub fn offset<T>(dst: *T, offset: int) -> *T;
+ /// Calculates the offset from a pointer. The offset *must* be in-bounds of
+ /// the object, or one-byte-past-the-end. An arithmetic overflow is also
+ /// undefined behaviour.
+ ///
+ /// This intrinsic should be preferred over `offset` when the guarantee can
+ /// be satisfied, to enable better optimization.
+ #[cfg(not(stage0))]
+ pub fn offset_inbounds<T>(dst: *T, offset: int) -> *T;
+
/// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of
/// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
pub fn memcpy32<T>(dst: *mut T, src: *T, count: u32);
use os;
unsafe {
- let use_old_rt = os::getenv("RUST_NEWRT").is_none();
+ let use_old_rt = os::getenv("RUST_OLDRT").is_some();
if use_old_rt {
return rust_start(main as *c_void, argc as c_int, argv,
crate_map as *c_void) as int;
fn iter(self) -> VecIterator<'self, T> {
unsafe {
let p = vec::raw::to_ptr(self);
- VecIterator{ptr: p,
- end: (p as uint + self.len() *
- sys::nonzero_size_of::<T>()) as *T,
- lifetime: cast::transmute(p)}
+ if sys::size_of::<T>() == 0 {
+ VecIterator{ptr: p,
+ end: (p as uint + self.len()) as *T,
+ lifetime: cast::transmute(p)}
+ } else {
+ VecIterator{ptr: p,
+ end: p.offset_inbounds(self.len() as int),
+ lifetime: cast::transmute(p)}
+ }
}
}
let new_len = self.len() + rhs.len();
self.reserve(new_len);
- for i in range(0u, rhs.len()) {
- self.push(unsafe { raw::get(rhs, i) })
+ for elt in rhs.iter() {
+ self.push((*elt).clone())
}
}
fn mut_iter(self) -> VecMutIterator<'self, T> {
unsafe {
let p = vec::raw::to_mut_ptr(self);
- VecMutIterator{ptr: p,
- end: (p as uint + self.len() *
- sys::nonzero_size_of::<T>()) as *mut T,
- lifetime: cast::transmute(p)}
+ if sys::size_of::<T>() == 0 {
+ VecMutIterator{ptr: p,
+ end: (p as uint + self.len()) as *mut T,
+ lifetime: cast::transmute(p)}
+ } else {
+ VecMutIterator{ptr: p,
+ end: p.offset_inbounds(self.len() as int),
+ lifetime: cast::transmute(p)}
+ }
}
}
// same pointer.
cast::transmute(self.ptr as uint + 1)
} else {
- self.ptr.offset(1)
+ self.ptr.offset_inbounds(1)
};
Some(cast::transmute(old))
// See above for why 'ptr.offset' isn't used
cast::transmute(self.end as uint - 1)
} else {
- self.end.offset(-1)
+ self.end.offset_inbounds(-1)
};
Some(cast::transmute(self.end))
}
// fetch the SCTable from TLS, create one if it doesn't yet exist.
pub fn get_sctable() -> @mut SCTable {
static sctable_key: local_data::Key<@@mut SCTable> = &local_data::Key;
- match local_data::get(sctable_key, |k| k.map(|&k| *k)) {
+ match local_data::get(sctable_key, |k| k.map_move(|k| *k)) {
None => {
let new_table = @@mut new_sctable_internal();
local_data::set(sctable_key,new_table);
}
pub fn name_str_pair(&self) -> Option<(@str, @str)> {
- self.value_str().map_consume(|s| (self.name(), s))
+ self.value_str().map_move(|s| (self.name(), s))
}
}
let stderr = io::stderr();
if stderr.get_type() == io::Screen {
- let t = match local_data::get(tls_terminal, |v| v.map_consume(|&k|k)) {
+ let t = match local_data::get(tls_terminal, |v| v.map_move(|k| *k)) {
None => {
let t = term::Terminal::new(stderr);
let tls = @match t {
ext::tt::macro_rules::add_new_extension));
syntax_expanders.insert(intern(&"fmt"),
builtin_normal_tt(ext::fmt::expand_syntax_ext));
+ syntax_expanders.insert(intern(&"ifmt"),
+ builtin_normal_tt(ext::ifmt::expand_syntax_ext));
syntax_expanders.insert(
intern(&"auto_encode"),
@SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
ConsMapChain(ref map,_) => map
};
// strip one layer of indirection off the pointer.
- map.find(key).map(|r| {**r})
+ map.find(key).map_move(|r| {*r})
}
// insert the binding into the top-level map
fn expr_if(&self, span: span,
cond: @ast::expr, then: @ast::expr, els: Option<@ast::expr>) -> @ast::expr {
- let els = els.map(|x| self.expr_block(self.block_expr(*x)));
+ let els = els.map_move(|x| self.expr_block(self.block_expr(x)));
self.expr(span, ast::expr_if(cond, self.block_expr(then), els))
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use ast;
use ast::{MetaItem, item, expr};
use codemap::span;
use ext::base::ExtCtxt;
}
-pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> @expr {
+pub fn ordering_const(cx: @ExtCtxt, span: span, cnst: Ordering) -> ast::Path {
let cnst = match cnst {
Less => "Less",
Equal => "Equal",
Greater => "Greater"
};
- cx.expr_path(
- cx.path_global(span,
- ~[cx.ident_of("std"),
- cx.ident_of("cmp"),
- cx.ident_of(cnst)]))
+ cx.path_global(span,
+ ~[cx.ident_of("std"),
+ cx.ident_of("cmp"),
+ cx.ident_of(cnst)])
}
pub fn cs_cmp(cx: @ExtCtxt, span: span,
substr: &Substructure) -> @expr {
+ let test_id = cx.ident_of("__test");
+ let equals_path = ordering_const(cx, span, Equal);
+ /*
+ Builds:
+
+ let __test = self_field1.cmp(&other_field2);
+ if other == ::std::cmp::Equal {
+ let __test = self_field2.cmp(&other_field2);
+ if __test == ::std::cmp::Equal {
+ ...
+ } else {
+ __test
+ }
+ } else {
+ __test
+ }
+
+ FIXME #6449: These `if`s could/should be `match`es.
+ */
cs_same_method_fold(
- // foldr (possibly) nests the matches in lexical_ordering better
+ // foldr nests the if-elses correctly, leaving the first field
+ // as the outermost one, and the last as the innermost.
false,
|cx, span, old, new| {
- cx.expr_call_global(span,
- ~[cx.ident_of("std"),
- cx.ident_of("cmp"),
- cx.ident_of("lexical_ordering")],
- ~[old, new])
+ // let __test = new;
+ // if __test == ::std::cmp::Equal {
+ // old
+ // } else {
+ // __test
+ // }
+
+ let assign = cx.stmt_let(span, false, test_id, new);
+
+ let cond = cx.expr_binary(span, ast::eq,
+ cx.expr_ident(span, test_id),
+ cx.expr_path(equals_path.clone()));
+ let if_ = cx.expr_if(span,
+ cond,
+ old, Some(cx.expr_ident(span, test_id)));
+ cx.expr_block(cx.block(span, ~[assign], Some(if_)))
},
- ordering_const(cx, span, Equal),
+ cx.expr_path(equals_path.clone()),
|cx, span, list, _| {
match list {
// an earlier nonmatching variant is Less than a
- // later one
+ // later one.
[(self_var, _, _),
- (other_var, _, _)] => ordering_const(cx, span,
- self_var.cmp(&other_var)),
+ (other_var, _, _)] => cx.expr_path(ordering_const(cx, span,
+ self_var.cmp(&other_var))),
_ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(TotalOrd)`")
}
},
.. *afp};
let f = make_fold(f_pre);
- @f.fold_crate(c)
+ let ret = @f.fold_crate(c);
+ parse_sess.span_diagnostic.handler().abort_if_errors();
+ return ret;
}
// given a function from idents to idents, produce
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ast;
+use codemap::{span, respan};
+use ext::base::*;
+use ext::base;
+use ext::build::AstBuilder;
+use rsparse = parse;
+use parse::token;
+
+use std::fmt::parse;
+use std::hashmap::{HashMap, HashSet};
+use std::vec;
+
+#[deriving(Eq)]
+enum ArgumentType {
+ Unknown,
+ Known(@str),
+ Unsigned,
+ String,
+}
+
+struct Context {
+ ecx: @ExtCtxt,
+ fmtsp: span,
+
+ // Parsed argument expressions and the types that we've found so far for
+ // them.
+ args: ~[@ast::expr],
+ arg_types: ~[Option<ArgumentType>],
+ // Parsed named expressions and the types that we've found for them so far
+ names: HashMap<@str, @ast::expr>,
+ name_types: HashMap<@str, ArgumentType>,
+
+ // Collection of the compiled `rt::Piece` structures
+ pieces: ~[@ast::expr],
+ name_positions: HashMap<@str, uint>,
+ method_statics: ~[@ast::item],
+
+ // Updated as arguments are consumed or methods are entered
+ nest_level: uint,
+ next_arg: uint,
+}
+
+impl Context {
+ /// Parses the arguments from the given list of tokens, returning None if
+ /// there's a parse error so we can continue parsing other fmt! expressions.
+ fn parse_args(&mut self, sp: span,
+ tts: &[ast::token_tree]) -> Option<@ast::expr> {
+ let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(),
+ self.ecx.cfg(),
+ tts.to_owned());
+ if *p.token == token::EOF {
+ self.ecx.span_err(sp, "ifmt! expects at least one argument");
+ return None;
+ }
+ let fmtstr = p.parse_expr();
+ let mut named = false;
+ while *p.token != token::EOF {
+ if !p.eat(&token::COMMA) {
+ self.ecx.span_err(sp, "expected token: `,`");
+ return None;
+ }
+ if named || (token::is_ident(p.token) &&
+ p.look_ahead(1, |t| *t == token::EQ)) {
+ named = true;
+ let ident = match *p.token {
+ token::IDENT(i, _) => {
+ p.bump();
+ i
+ }
+ _ if named => {
+ self.ecx.span_err(*p.span,
+ "expected ident, positional arguments \
+ cannot follow named arguments");
+ return None;
+ }
+ _ => {
+ self.ecx.span_err(*p.span,
+ fmt!("expected ident for named \
+ argument, but found `%s`",
+ p.this_token_to_str()));
+ return None;
+ }
+ };
+ let name = self.ecx.str_of(ident);
+ p.expect(&token::EQ);
+ let e = p.parse_expr();
+ match self.names.find(&name) {
+ None => {}
+ Some(prev) => {
+ self.ecx.span_err(e.span, fmt!("duplicate argument \
+ named `%s`", name));
+ self.ecx.parse_sess.span_diagnostic.span_note(
+ prev.span, "previously here");
+ loop
+ }
+ }
+ self.names.insert(name, e);
+ } else {
+ self.args.push(p.parse_expr());
+ self.arg_types.push(None);
+ }
+ }
+ return Some(fmtstr);
+ }
+
+ /// Verifies one piece of a parse string. All errors are not emitted as
+ /// fatal so we can continue giving errors about this and possibly other
+ /// format strings.
+ fn verify_piece(&mut self, p: &parse::Piece) {
+ match *p {
+ parse::String(*) => {}
+ parse::CurrentArgument => {
+ if self.nest_level == 0 {
+ self.ecx.span_err(self.fmtsp,
+ "`#` reference used with nothing to \
+ reference back to");
+ }
+ }
+ parse::Argument(ref arg) => {
+ // argument first (it's first in the format string)
+ let pos = match arg.position {
+ parse::ArgumentNext => {
+ let i = self.next_arg;
+ if self.check_positional_ok() {
+ self.next_arg += 1;
+ }
+ Left(i)
+ }
+ parse::ArgumentIs(i) => Left(i),
+ parse::ArgumentNamed(s) => Right(s.to_managed()),
+ };
+ let ty = if arg.format.ty == "" {
+ Unknown
+ } else { Known(arg.format.ty.to_managed()) };
+ self.verify_arg_type(pos, ty);
+
+ // width/precision next
+ self.verify_count(arg.format.width);
+ self.verify_count(arg.format.precision);
+
+ // and finally the method being applied
+ match arg.method {
+ None => {}
+ Some(ref method) => { self.verify_method(pos, *method); }
+ }
+ }
+ }
+ }
+
+ fn verify_pieces(&mut self, pieces: &[parse::Piece]) {
+ for piece in pieces.iter() {
+ self.verify_piece(piece);
+ }
+ }
+
+ fn verify_count(&mut self, c: parse::Count) {
+ match c {
+ parse::CountImplied | parse::CountIs(*) => {}
+ parse::CountIsParam(i) => {
+ self.verify_arg_type(Left(i), Unsigned);
+ }
+ parse::CountIsNextParam => {
+ if self.check_positional_ok() {
+ self.verify_arg_type(Left(self.next_arg), Unsigned);
+ self.next_arg += 1;
+ }
+ }
+ }
+ }
+
+ fn check_positional_ok(&mut self) -> bool {
+ if self.nest_level != 0 {
+ self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
+ arguments nested inside methods");
+ false
+ } else {
+ true
+ }
+ }
+
+ fn verify_method(&mut self, pos: Either<uint, @str>, m: &parse::Method) {
+ self.nest_level += 1;
+ match *m {
+ parse::Plural(_, ref arms, ref default) => {
+ let mut seen_cases = HashSet::new();
+ self.verify_arg_type(pos, Unsigned);
+ for arm in arms.iter() {
+ if !seen_cases.insert(arm.selector) {
+ match arm.selector {
+ Left(name) => {
+ self.ecx.span_err(self.fmtsp,
+ fmt!("duplicate selector \
+ `%?`", name));
+ }
+ Right(idx) => {
+ self.ecx.span_err(self.fmtsp,
+ fmt!("duplicate selector \
+ `=%u`", idx));
+ }
+ }
+ }
+ self.verify_pieces(arm.result);
+ }
+ self.verify_pieces(*default);
+ }
+ parse::Select(ref arms, ref default) => {
+ self.verify_arg_type(pos, String);
+ let mut seen_cases = HashSet::new();
+ for arm in arms.iter() {
+ if !seen_cases.insert(arm.selector) {
+ self.ecx.span_err(self.fmtsp,
+ fmt!("duplicate selector `%s`",
+ arm.selector));
+ } else if arm.selector == "" {
+ self.ecx.span_err(self.fmtsp,
+ "empty selector in `select`");
+ }
+ self.verify_pieces(arm.result);
+ }
+ self.verify_pieces(*default);
+ }
+ }
+ self.nest_level -= 1;
+ }
+
+ fn verify_arg_type(&mut self, arg: Either<uint, @str>, ty: ArgumentType) {
+ match arg {
+ Left(arg) => {
+ if arg < 0 || self.args.len() <= arg {
+ let msg = fmt!("invalid reference to argument `%u` (there \
+ are %u arguments)", arg, self.args.len());
+ self.ecx.span_err(self.fmtsp, msg);
+ return;
+ }
+ self.verify_same(self.args[arg].span, ty, self.arg_types[arg]);
+ if ty != Unknown || self.arg_types[arg].is_none() {
+ self.arg_types[arg] = Some(ty);
+ }
+ }
+
+ Right(name) => {
+ let span = match self.names.find(&name) {
+ Some(e) => e.span,
+ None => {
+ let msg = fmt!("There is no argument named `%s`", name);
+ self.ecx.span_err(self.fmtsp, msg);
+ return;
+ }
+ };
+ self.verify_same(span, ty,
+ self.name_types.find(&name).map(|&x| *x));
+ if ty != Unknown || !self.name_types.contains_key(&name) {
+ self.name_types.insert(name, ty);
+ }
+ // Assign this named argument a slot in the arguments array if
+ // it hasn't already been assigned a slot.
+ if !self.name_positions.contains_key(&name) {
+ let slot = self.name_positions.len();
+ self.name_positions.insert(name, slot);
+ }
+ }
+ }
+ }
+
+ /// When we're keeping track of the types that are declared for certain
+ /// arguments, we assume that `None` means we haven't seen this argument
+ /// yet, `Some(None)` means that we've seen the argument, but no format was
+ /// specified, and `Some(Some(x))` means that the argument was declared to
+ /// have type `x`.
+ ///
+ /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
+ /// that: `Some(None) == Some(Some(x))`
+ fn verify_same(&self, sp: span, ty: ArgumentType,
+ before: Option<ArgumentType>) {
+ if ty == Unknown { return }
+ let cur = match before {
+ Some(Unknown) | None => return,
+ Some(t) => t,
+ };
+ if ty == cur { return }
+ match (cur, ty) {
+ (Known(cur), Known(ty)) => {
+ self.ecx.span_err(sp,
+ fmt!("argument redeclared with type `%s` when \
+ it was previously `%s`", ty, cur));
+ }
+ (Known(cur), _) => {
+ self.ecx.span_err(sp,
+ fmt!("argument used to format with `%s` was \
+ attempted to not be used for formatting",
+ cur));
+ }
+ (_, Known(ty)) => {
+ self.ecx.span_err(sp,
+ fmt!("argument previously used as a format \
+ argument attempted to be used as `%s`",
+ ty));
+ }
+ (_, _) => {
+ self.ecx.span_err(sp, "argument declared with multiple formats");
+ }
+ }
+ }
+
+ /// Translate a `parse::Piece` to a static `rt::Piece`
+ fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::expr {
+ let sp = self.fmtsp;
+ let rtpath = |s: &str| {
+ ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
+ };
+ let ctpath = |s: &str| {
+ ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
+ };
+ let none = || {
+ let p = self.ecx.path(sp, ~[self.ecx.ident_of("None")]);
+ self.ecx.expr_path(p)
+ };
+ let some = |e: @ast::expr| {
+ self.ecx.expr_call_ident(sp, self.ecx.ident_of("Some"), ~[e])
+ };
+ let trans_count = |c: parse::Count| {
+ match c {
+ parse::CountIs(i) => {
+ self.ecx.expr_call_global(sp, ctpath("CountIs"),
+ ~[self.ecx.expr_uint(sp, i)])
+ }
+ parse::CountIsParam(i) => {
+ self.ecx.expr_call_global(sp, ctpath("CountIsParam"),
+ ~[self.ecx.expr_uint(sp, i)])
+ }
+ parse::CountImplied => {
+ let path = self.ecx.path_global(sp, ctpath("CountImplied"));
+ self.ecx.expr_path(path)
+ }
+ parse::CountIsNextParam => {
+ let path = self.ecx.path_global(sp, ctpath("CountIsNextParam"));
+ self.ecx.expr_path(path)
+ }
+ }
+ };
+ let trans_method = |method: &parse::Method| {
+ let method = match *method {
+ parse::Select(ref arms, ref default) => {
+ let arms = arms.iter().transform(|arm| {
+ let p = self.ecx.path_global(sp, rtpath("SelectArm"));
+ let result = arm.result.iter().transform(|p| {
+ self.trans_piece(p)
+ }).collect();
+ let s = arm.selector.to_managed();
+ let selector = self.ecx.expr_str(sp, s);
+ self.ecx.expr_struct(sp, p, ~[
+ self.ecx.field_imm(sp,
+ self.ecx.ident_of("selector"),
+ selector),
+ self.ecx.field_imm(sp, self.ecx.ident_of("result"),
+ self.ecx.expr_vec_slice(sp, result)),
+ ])
+ }).collect();
+ let default = default.iter().transform(|p| {
+ self.trans_piece(p)
+ }).collect();
+ self.ecx.expr_call_global(sp, rtpath("Select"), ~[
+ self.ecx.expr_vec_slice(sp, arms),
+ self.ecx.expr_vec_slice(sp, default),
+ ])
+ }
+ parse::Plural(offset, ref arms, ref default) => {
+ let offset = match offset {
+ Some(i) => { some(self.ecx.expr_uint(sp, i)) }
+ None => { none() }
+ };
+ let arms = arms.iter().transform(|arm| {
+ let p = self.ecx.path_global(sp, rtpath("PluralArm"));
+ let result = arm.result.iter().transform(|p| {
+ self.trans_piece(p)
+ }).collect();
+ let (lr, selarg) = match arm.selector {
+ Left(t) => {
+ let p = ctpath(fmt!("%?", t));
+ let p = self.ecx.path_global(sp, p);
+ (self.ecx.ident_of("Left"),
+ self.ecx.expr_path(p))
+ }
+ Right(i) => {
+ (self.ecx.ident_of("Right"),
+ self.ecx.expr_uint(sp, i))
+ }
+ };
+ let selector = self.ecx.expr_call_ident(sp,
+ lr, ~[selarg]);
+ self.ecx.expr_struct(sp, p, ~[
+ self.ecx.field_imm(sp,
+ self.ecx.ident_of("selector"),
+ selector),
+ self.ecx.field_imm(sp, self.ecx.ident_of("result"),
+ self.ecx.expr_vec_slice(sp, result)),
+ ])
+ }).collect();
+ let default = default.iter().transform(|p| {
+ self.trans_piece(p)
+ }).collect();
+ self.ecx.expr_call_global(sp, rtpath("Plural"), ~[
+ offset,
+ self.ecx.expr_vec_slice(sp, arms),
+ self.ecx.expr_vec_slice(sp, default),
+ ])
+ }
+ };
+ let life = self.ecx.lifetime(sp, self.ecx.ident_of("static"));
+ let ty = self.ecx.ty_path(self.ecx.path_all(
+ sp,
+ true,
+ rtpath("Method"),
+ Some(life),
+ ~[]
+ ), None);
+ let st = ast::item_static(ty, ast::m_imm, method);
+ let static_name = self.ecx.ident_of(fmt!("__static_method_%u",
+ self.method_statics.len()));
+ let item = self.ecx.item(sp, static_name, ~[], st);
+ self.method_statics.push(item);
+ self.ecx.expr_ident(sp, static_name)
+ };
+
+ match *piece {
+ parse::String(s) => {
+ self.ecx.expr_call_global(sp, rtpath("String"),
+ ~[self.ecx.expr_str(sp, s.to_managed())])
+ }
+ parse::CurrentArgument => {
+ let nil = self.ecx.expr_lit(sp, ast::lit_nil);
+ self.ecx.expr_call_global(sp, rtpath("CurrentArgument"), ~[nil])
+ }
+ parse::Argument(ref arg) => {
+ // Translate the position
+ let pos = match arg.position {
+ // These two have a direct mapping
+ parse::ArgumentNext => {
+ let path = self.ecx.path_global(sp,
+ rtpath("ArgumentNext"));
+ self.ecx.expr_path(path)
+ }
+ parse::ArgumentIs(i) => {
+ self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
+ ~[self.ecx.expr_uint(sp, i)])
+ }
+ // Named arguments are converted to positional arguments at
+ // the end of the list of arguments
+ parse::ArgumentNamed(n) => {
+ let n = n.to_managed();
+ let i = match self.name_positions.find_copy(&n) {
+ Some(i) => i,
+ None => 0, // error already emitted elsewhere
+ };
+ let i = i + self.args.len();
+ self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
+ ~[self.ecx.expr_uint(sp, i)])
+ }
+ };
+
+ // Translate the format
+ let fill = match arg.format.fill { Some(c) => c, None => ' ' };
+ let fill = self.ecx.expr_lit(sp, ast::lit_int(fill as i64,
+ ast::ty_char));
+ let align = match arg.format.align {
+ None | Some(parse::AlignLeft) => {
+ self.ecx.expr_bool(sp, true)
+ }
+ Some(parse::AlignRight) => {
+ self.ecx.expr_bool(sp, false)
+ }
+ };
+ let flags = self.ecx.expr_uint(sp, arg.format.flags);
+ let prec = trans_count(arg.format.precision);
+ let width = trans_count(arg.format.width);
+ let path = self.ecx.path_global(sp, rtpath("FormatSpec"));
+ let fmt = self.ecx.expr_struct(sp, path, ~[
+ self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
+ self.ecx.field_imm(sp, self.ecx.ident_of("alignleft"), align),
+ self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
+ self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
+ self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),
+ ]);
+
+ // Translate the method (if any)
+ let method = match arg.method {
+ None => { none() }
+ Some(ref m) => {
+ let m = trans_method(*m);
+ some(self.ecx.expr_addr_of(sp, m))
+ }
+ };
+ let path = self.ecx.path_global(sp, rtpath("Argument"));
+ let s = self.ecx.expr_struct(sp, path, ~[
+ self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
+ self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
+ self.ecx.field_imm(sp, self.ecx.ident_of("method"), method),
+ ]);
+ self.ecx.expr_call_global(sp, rtpath("Argument"), ~[s])
+ }
+ }
+ }
+
+ /// Actually builds the expression which the ifmt! block will be expanded
+ /// to
+ fn to_expr(&self) -> @ast::expr {
+ let mut lets = ~[];
+ let mut locals = ~[];
+ let mut names = vec::from_fn(self.name_positions.len(), |_| None);
+
+ // First, declare all of our methods that are statics
+ for &method in self.method_statics.iter() {
+ let decl = respan(self.fmtsp, ast::decl_item(method));
+ lets.push(@respan(self.fmtsp,
+ ast::stmt_decl(@decl, self.ecx.next_id())));
+ }
+
+ // Next, build up the static array which will become our precompiled
+ // format "string"
+ let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
+ let ty = ast::ty_fixed_length_vec(
+ self.ecx.ty_mt(
+ self.ecx.ty_path(self.ecx.path_all(
+ self.fmtsp,
+ true, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("rt"),
+ self.ecx.ident_of("Piece"),
+ ],
+ Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))),
+ ~[]
+ ), None),
+ ast::m_imm
+ ),
+ self.ecx.expr_uint(self.fmtsp, self.pieces.len())
+ );
+ let ty = self.ecx.ty(self.fmtsp, ty);
+ let st = ast::item_static(ty, ast::m_imm, fmt);
+ let static_name = self.ecx.ident_of("__static_fmtstr");
+ let item = self.ecx.item(self.fmtsp, static_name, ~[], st);
+ let decl = respan(self.fmtsp, ast::decl_item(item));
+ lets.push(@respan(self.fmtsp, ast::stmt_decl(@decl, self.ecx.next_id())));
+
+ // Right now there is a bug such that for the expression:
+ // foo(bar(&1))
+ // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
+ // vald for the call to `foo`. To work around this all arguments to the
+ // fmt! string are shoved into locals.
+ for (i, &e) in self.args.iter().enumerate() {
+ if self.arg_types[i].is_none() { loop } // error already generated
+
+ let name = self.ecx.ident_of(fmt!("__arg%u", i));
+ lets.push(self.ecx.stmt_let(e.span, false, name, e));
+ locals.push(self.format_arg(e.span, Left(i), name));
+ }
+ for (&name, &e) in self.names.iter() {
+ if !self.name_types.contains_key(&name) { loop }
+
+ let lname = self.ecx.ident_of(fmt!("__arg%s", name));
+ lets.push(self.ecx.stmt_let(e.span, false, lname, e));
+ names[*self.name_positions.get(&name)] =
+ Some(self.format_arg(e.span, Right(name), lname));
+ }
+
+ let args = names.consume_iter().transform(|a| a.unwrap());
+ let mut args = locals.consume_iter().chain_(args);
+
+ // Next, build up the actual call to the sprintf function.
+ let result = self.ecx.expr_call_global(self.fmtsp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("sprintf"),
+ ], ~[
+ self.ecx.expr_ident(self.fmtsp, static_name),
+ self.ecx.expr_vec(self.fmtsp, args.collect()),
+ ]);
+
+ // sprintf is unsafe, but we just went through a lot of work to
+ // validate that our call is save, so inject the unsafe block for the
+ // user.
+ let result = self.ecx.expr_block(ast::Block {
+ view_items: ~[],
+ stmts: ~[],
+ expr: Some(result),
+ id: self.ecx.next_id(),
+ rules: ast::UnsafeBlock,
+ span: self.fmtsp,
+ });
+
+ self.ecx.expr_block(self.ecx.block(self.fmtsp, lets, Some(result)))
+ }
+
+ fn format_arg(&self, sp: span, arg: Either<uint, @str>,
+ ident: ast::ident) -> @ast::expr {
+ let mut ty = match arg {
+ Left(i) => self.arg_types[i].unwrap(),
+ Right(s) => *self.name_types.get(&s)
+ };
+ // Default types to '?' if nothing else is specified.
+ if ty == Unknown {
+ ty = Known(@"?");
+ }
+ let argptr = self.ecx.expr_addr_of(sp, self.ecx.expr_ident(sp, ident));
+ match ty {
+ Known(tyname) => {
+ let fmt_trait = match tyname.as_slice() {
+ "?" => "Poly",
+ "d" | "i" => "Signed",
+ "u" => "Unsigned",
+ "b" => "Bool",
+ "c" => "Char",
+ "o" => "Octal",
+ "x" => "LowerHex",
+ "X" => "UpperHex",
+ "s" => "String",
+ "p" => "Pointer",
+ _ => {
+ self.ecx.span_err(sp, fmt!("unknown format trait \
+ `%s`", tyname));
+ "Dummy"
+ }
+ };
+ let format_fn = self.ecx.path_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of(fmt_trait),
+ self.ecx.ident_of("fmt"),
+ ]);
+ self.ecx.expr_call_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("argument"),
+ ], ~[self.ecx.expr_path(format_fn), argptr])
+ }
+ String => {
+ self.ecx.expr_call_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("argumentstr"),
+ ], ~[argptr])
+ }
+ Unsigned => {
+ self.ecx.expr_call_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("argumentuint"),
+ ], ~[argptr])
+ }
+ Unknown => { fail!() }
+ }
+ }
+}
+
+pub fn expand_syntax_ext(ecx: @ExtCtxt, sp: span,
+ tts: &[ast::token_tree]) -> base::MacResult {
+ let mut cx = Context {
+ ecx: ecx,
+ args: ~[],
+ arg_types: ~[],
+ names: HashMap::new(),
+ name_positions: HashMap::new(),
+ name_types: HashMap::new(),
+ nest_level: 0,
+ next_arg: 0,
+ pieces: ~[],
+ method_statics: ~[],
+ fmtsp: sp,
+ };
+ let efmt = match cx.parse_args(sp, tts) {
+ Some(e) => e,
+ None => { return MRExpr(ecx.expr_uint(sp, 2)); }
+ };
+ cx.fmtsp = efmt.span;
+ let fmt = expr_to_str(ecx, efmt,
+ ~"first argument to ifmt! must be a string literal.");
+
+ let mut err = false;
+ do parse::parse_error::cond.trap(|m| {
+ if !err {
+ err = true;
+ ecx.span_err(efmt.span, m);
+ }
+ }).inside {
+ for piece in parse::Parser::new(fmt) {
+ if !err {
+ cx.verify_piece(&piece);
+ let piece = cx.trans_piece(&piece);
+ cx.pieces.push(piece);
+ }
+ }
+ }
+ if err { return MRExpr(efmt) }
+
+ // Make sure that all arguments were used and all arguments have types.
+ for (i, ty) in cx.arg_types.iter().enumerate() {
+ if ty.is_none() {
+ ecx.span_err(cx.args[i].span, "argument never used");
+ }
+ }
+ for (name, e) in cx.names.iter() {
+ if !cx.name_types.contains_key(name) {
+ ecx.span_err(e.span, "named argument never used");
+ }
+ }
+
+ MRExpr(cx.to_expr())
+}
fn noop_fold_arm(a: &arm, fld: @ast_fold) -> arm {
arm {
pats: a.pats.map(|x| fld.fold_pat(*x)),
- guard: a.guard.map(|x| fld.fold_expr(*x)),
+ guard: a.guard.map_move(|x| fld.fold_expr(x)),
body: fld.fold_block(&a.body),
}
}
pat_ident(
binding_mode,
fld.fold_path(pth),
- sub.map(|x| fld.fold_pat(*x))
+ sub.map_move(|x| fld.fold_pat(x))
)
}
pat_lit(e) => pat_lit(fld.fold_expr(e)),
pat_vec(ref before, ref slice, ref after) => {
pat_vec(
before.map(|x| fld.fold_pat(*x)),
- slice.map(|x| fld.fold_pat(*x)),
+ slice.map_move(|x| fld.fold_pat(x)),
after.map(|x| fld.fold_pat(*x))
)
}
expr_if(
fld.fold_expr(cond),
fld.fold_block(tr),
- fl.map(|x| fld.fold_expr(*x))
+ fl.map_move(|x| fld.fold_expr(x))
)
}
expr_while(cond, ref body) => {
expr_loop(ref body, opt_ident) => {
expr_loop(
fld.fold_block(body),
- opt_ident.map(|x| fld.fold_ident(*x))
+ opt_ident.map_move(|x| fld.fold_ident(x))
)
}
expr_match(expr, ref arms) => {
expr_path(ref pth) => expr_path(fld.fold_path(pth)),
expr_self => expr_self,
expr_break(ref opt_ident) => {
- expr_break(opt_ident.map(|x| fld.fold_ident(*x)))
+ expr_break(opt_ident.map_move(|x| fld.fold_ident(x)))
}
expr_again(ref opt_ident) => {
- expr_again(opt_ident.map(|x| fld.fold_ident(*x)))
+ expr_again(opt_ident.map_move(|x| fld.fold_ident(x)))
}
expr_ret(ref e) => {
- expr_ret(e.map(|x| fld.fold_expr(*x)))
+ expr_ret(e.map_move(|x| fld.fold_expr(x)))
}
expr_log(lv, e) => {
expr_log(
expr_struct(
fld.fold_path(path),
fields.map(|x| fold_field(*x)),
- maybe_expr.map(|x| fld.fold_expr(*x))
+ maybe_expr.map_move(|x| fld.fold_expr(x))
)
},
expr_paren(ex) => expr_paren(fld.fold_expr(ex))
fold_variant_arg(/*bad*/ (*x).clone())
})
}
- struct_variant_kind(struct_def) => {
+ struct_variant_kind(ref struct_def) => {
kind = struct_variant_kind(@ast::struct_def {
fields: struct_def.fields.iter()
.transform(|f| fld.fold_struct_field(*f)).collect(),
is_mutbl: l.is_mutbl,
ty: fld.fold_ty(&l.ty),
pat: fld.fold_pat(l.pat),
- init: l.init.map(|e| fld.fold_expr(*e)),
+ init: l.init.map_move(|e| fld.fold_expr(e)),
id: fld.new_id(l.id),
span: fld.new_span(l.span),
}
ObsoleteMutWithMultipleBindings,
ObsoleteExternVisibility,
ObsoleteUnsafeExternFn,
+ ObsoletePrivVisibility,
}
impl to_bytes::IterBytes for ObsoleteSyntax {
"external functions are always unsafe; remove the `unsafe` \
keyword"
),
+ ObsoletePrivVisibility => (
+ "`priv` not necessary",
+ "an item without a visibility qualifier is private by default"
+ ),
};
self.report(sp, kind, kind_str, desc);
use parse::obsolete::{ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl};
use parse::obsolete::{ObsoleteMutWithMultipleBindings};
use parse::obsolete::{ObsoleteExternVisibility, ObsoleteUnsafeExternFn};
-use parse::obsolete::{ParserObsoleteMethods};
+use parse::obsolete::{ParserObsoleteMethods, ObsoletePrivVisibility};
use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident};
use parse::token::{is_ident_or_path};
use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents};
let attrs = p.parse_outer_attributes();
let lo = p.span.lo;
- let vis = p.parse_visibility();
+ let vis = p.parse_non_priv_visibility();
let pur = p.parse_fn_purity();
// NB: at the moment, trait methods are public by default; this
// could change.
// If the path might have bounds on it, they should be parsed before
// the parameters, e.g. module::TraitName:B1+B2<T>
- before_tps.map_consume(|callback| callback());
+ before_tps.map_move(|callback| callback());
// Parse the (obsolete) trailing region parameter, if any, which will
// be written "foo/&x"
let attrs = self.parse_outer_attributes();
let lo = self.span.lo;
- let visa = self.parse_visibility();
+ let visa = self.parse_non_priv_visibility();
let pur = self.parse_fn_purity();
let ident = self.parse_ident();
let generics = self.parse_generics();
else { inherited }
}
+ // parse visibility, but emits an obsolete error if it's private
+ fn parse_non_priv_visibility(&self) -> visibility {
+ match self.parse_visibility() {
+ public => public,
+ inherited => inherited,
+ private => {
+ self.obsolete(*self.last_span, ObsoletePrivVisibility);
+ inherited
+ }
+ }
+ }
+
fn parse_staticness(&self) -> bool {
if self.eat_keyword(keywords::Static) {
self.obsolete(*self.last_span, ObsoleteStaticMethod);
// parse a function declaration from a foreign module
fn parse_item_foreign_fn(&self, attrs: ~[Attribute]) -> @foreign_item {
let lo = self.span.lo;
- let vis = self.parse_visibility();
+ let vis = self.parse_non_priv_visibility();
// Parse obsolete purity.
let purity = self.parse_fn_purity();
maybe_whole!(iovi self, nt_item);
let lo = self.span.lo;
- let visibility = self.parse_visibility();
+ let visibility = self.parse_non_priv_visibility();
// must be a view item:
if self.eat_keyword(keywords::Use) {
maybe_whole!(iovi self, nt_item);
let lo = self.span.lo;
- let visibility = self.parse_visibility();
+ let visibility = self.parse_non_priv_visibility();
if (self.is_keyword(keywords::Const) || self.is_keyword(keywords::Static)) {
// FOREIGN CONST ITEM
pub fn get_ident_interner() -> @ident_interner {
static key: local_data::Key<@@::parse::token::ident_interner> =
&local_data::Key;
- match local_data::get(key, |k| k.map(|&k| *k)) {
+ match local_data::get(key, |k| k.map_move(|k| *k)) {
Some(interner) => *interner,
None => {
let interner = mk_fresh_ident_interner();
pub mod cfg;
pub mod fmt;
+ pub mod ifmt;
pub mod env;
pub mod bytes;
pub mod concat_idents;
}
impl cat {
- priv fn nap(&self) {}
+ fn nap(&self) {}
}
pub fn cat(in_x : uint, in_y : int) -> cat {
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[crate_type = "lib"];
+
+// used by the rpass test
+
+pub struct Struct;
+
+pub enum Unit {
+ Unit,
+ Argument(Struct)
+}
+
+// used by the cfail test
+
+pub struct StructWithFields {
+ foo: int,
+}
+
+pub enum EnumWithVariants {
+ EnumVariant,
+ EnumVariantArg(int)
+}
io::println(" Descending integers:");
do timed("insert") {
- do uint::range_rev(n_keys, 0) |i| {
+ for i in range(0, n_keys).invert() {
map.insert(i, i + 1);
- true
- };
+ }
}
do timed("search") {
- do uint::range_rev(n_keys, 0) |i| {
+ for i in range(0, n_keys).invert() {
assert_eq!(map.find(&i).unwrap(), &(i + 1));
- true
- };
+ }
}
do timed("remove") {
- do uint::range_rev(n_keys, 0) |i| {
+ for i in range(0, n_keys) {
assert!(map.remove(&i));
- true
- };
+ }
}
}
{
let mut set = f();
do timed(&mut self.random_ints) {
- do num_keys.times {
+ for _ in range(0, num_keys) {
set.insert((rng.next() as uint) % rand_cap);
}
}
{
let mut set = f();
do timed(&mut self.random_strings) {
- do num_keys.times {
+ for _ in range(0, num_keys) {
let s = uint::to_str(rng.next() as uint);
set.insert(s);
}
let symbols = [" ", "░", "▒", "▓", "█", "█"];
let mut pixels = [0f32, ..256*256];
let n2d = ~Noise2DContext::new();
- do 100.times {
+ for _ in range(0, 100u) {
for y in range(0, 256) {
for x in range(0, 256) {
let v = n2d.get(
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern mod extra;
+
+use std::task::spawn;
+use std::os;
+use std::uint;
+use std::rt::test::spawntask_later;
+use std::cell::Cell;
+
+// This is a simple bench that creates M pairs of of tasks. These
+// tasks ping-pong back and forth over a pair of streams. This is a
+// cannonical message-passing benchmark as it heavily strains message
+// passing and almost nothing else.
+
+fn ping_pong_bench(n: uint, m: uint) {
+
+ // Create pairs of tasks that pingpong back and forth.
+ fn run_pair(n: uint) {
+ // Create a stream A->B
+ let (pa,ca) = stream::<()>();
+ // Create a stream B->A
+ let (pb,cb) = stream::<()>();
+
+ let pa = Cell::new(pa);
+ let ca = Cell::new(ca);
+ let pb = Cell::new(pb);
+ let cb = Cell::new(cb);
+
+ do spawntask_later() || {
+ let chan = ca.take();
+ let port = pb.take();
+ do n.times {
+ chan.send(());
+ port.recv();
+ }
+ }
+
+ do spawntask_later() || {
+ let chan = cb.take();
+ let port = pa.take();
+ do n.times {
+ port.recv();
+ chan.send(());
+ }
+ }
+ }
+
+ do m.times {
+ run_pair(n)
+ }
+
+}
+
+
+
+fn main() {
+
+ let args = os::args();
+ let n = if args.len() == 3 {
+ uint::from_str(args[1]).unwrap()
+ } else {
+ 10000
+ };
+
+ let m = if args.len() == 3 {
+ uint::from_str(args[2]).unwrap()
+ } else {
+ 4
+ };
+
+ ping_pong_bench(n, m);
+
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern mod extra;
+
+use std::task::spawn;
+use std::os;
+use std::uint;
+use std::rt::test::spawntask_later;
+use std::cell::Cell;
+use std::comm::*;
+
+// A simple implementation of parfib. One subtree is found in a new
+// task and communicated over a oneshot pipe, the other is found
+// locally. There is no sequential-mode threshold.
+
+fn parfib(n: uint) -> uint {
+ if(n == 0 || n == 1) {
+ return 1;
+ }
+
+ let (port,chan) = oneshot::<uint>();
+ let chan = Cell::new(chan);
+ do spawntask_later {
+ chan.take().send(parfib(n-1));
+ };
+ let m2 = parfib(n-2);
+ return (port.recv() + m2);
+}
+
+fn main() {
+
+ let args = os::args();
+ let n = if args.len() == 2 {
+ uint::from_str(args[1]).unwrap()
+ } else {
+ 10
+ };
+
+ parfib(n);
+
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern mod extra;
+
+use std::task::spawn;
+use std::os;
+use std::uint;
+
+// Very simple spawn rate test. Spawn N tasks that do nothing and
+// return.
+
+fn main() {
+
+ let args = os::args();
+ let n = if args.len() == 2 {
+ uint::from_str(args[1]).unwrap()
+ } else {
+ 100000
+ };
+
+ do n.times {
+ do spawn || {};
+ }
+
+}
let mut creatures_met = 0;
// set up meetings...
- do nn.times {
+ for _ in range(0, nn) {
let fst_creature: CreatureInfo = from_creatures.recv();
let snd_creature: CreatureInfo = from_creatures.recv();
+// xfail-test reading from os::args()[1] - bogus!
+
use std::from_str::FromStr;
use std::os;
use std::vec::MutableVector;
+// xfail-test reading from os::args()[1] - bogus!
+
use std::cast::transmute;
use std::from_str::FromStr;
use std::libc::{FILE, STDOUT_FILENO, c_int, fdopen, fputc, fputs, fwrite, size_t};
let chars_left = n % LINE_LEN;
let mut buf = [0, ..LINE_LEN + 1];
- do lines.times {
+ for _ in range(0, lines) {
for i in range(0u, LINE_LEN) {
buf[i] = self.nextc();
}
fn unpack(&self, frame: i32) -> ~str {
let mut key = **self;
let mut result = ~[];
- do (frame as uint).times {
+ for _ in range(0, frame) {
result.push(unpack_symbol((key as u8) & 3));
key >>= 2;
}
let mut code = Code(0);
// Pull first frame.
- do (frame as uint).times {
+ for _ in range(0, frame) {
code = code.push_char(input[0]);
input = next_char(input);
}
+// xfail-test reading from os::args()[1] - bogus!
+
use std::cast::transmute;
use std::from_str::FromStr;
use std::libc::{STDOUT_FILENO, c_int, fdopen, fputc};
+// xfail-test reading from os::args()[1] - bogus!
+
use std::from_str::FromStr;
use std::os;
fn advance(bodies: &mut [Planet, ..N_BODIES], dt: f64, steps: i32) {
let mut d = [ 0.0, ..3 ];
- do (steps as uint).times {
+ for _ in range(0, steps) {
for i in range(0u, N_BODIES) {
for j in range(i + 1, N_BODIES) {
d[0] = bodies[i].x[0] - bodies[j].x[0];
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test reading from os::args()[1] - bogus!
+
use std::from_str::FromStr;
use std::os;
use std::vec;
let mut u = vec::from_elem(n, 1f64);
let mut v = u.clone();
let mut tmp = u.clone();
- do 8.times {
+ for _ in range(0, 8u) {
mult_AtAv(u, v, tmp);
mult_AtAv(v, u, tmp);
}
}
fn run(repeat: int, depth: int) {
- do (repeat as uint).times {
+ for _ in range(0, repeat) {
info!("starting %.4f", precise_time_s());
do task::try {
recurse_or_fail(depth, None)
let (po, ch) = stream();
let ch = SharedChan::new(ch);
- do num_tasks.times {
+ for _ in range(0, num_tasks) {
let ch = ch.clone();
- do task::spawn { // linked
+ let mut t = task::task();
+ t.linked();
+ t.unwatched();
+ do t.spawn { // linked
ch.send(());
let (p, _c) = stream::<()>();
p.recv(); // block forever
}
}
error!("Grandchild group getting started");
- do num_tasks.times {
+ for _ in range(0, num_tasks) {
// Make sure all above children are fully spawned; i.e., enlisted in
// their ancestor groups.
po.recv();
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ // bad arguments to the ifmt! call
+
+ ifmt!(); //~ ERROR: expects at least one
+ ifmt!("{}"); //~ ERROR: invalid reference to argument
+
+ ifmt!("{1}", 1); //~ ERROR: invalid reference to argument `1`
+ //~^ ERROR: argument never used
+ ifmt!("{foo}"); //~ ERROR: no argument named `foo`
+
+ ifmt!("{}", 1, 2); //~ ERROR: argument never used
+ ifmt!("{1}", 1, 2); //~ ERROR: argument never used
+ ifmt!("{}", 1, foo=2); //~ ERROR: named argument never used
+ ifmt!("{foo}", 1, foo=2); //~ ERROR: argument never used
+ ifmt!("", foo=2); //~ ERROR: named argument never used
+
+ ifmt!("{0:d} {0:s}", 1); //~ ERROR: redeclared with type `s`
+ ifmt!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s`
+
+ ifmt!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument
+ ifmt!("#"); //~ ERROR: `#` reference used
+ ifmt!("", foo=1, 2); //~ ERROR: positional arguments cannot follow
+ ifmt!("" 1); //~ ERROR: expected token: `,`
+ ifmt!("", 1 1); //~ ERROR: expected token: `,`
+
+ ifmt!("{0, select, a{} a{} other{}}", "a"); //~ ERROR: duplicate selector
+ ifmt!("{0, plural, =1{} =1{} other{}}", 1u); //~ ERROR: duplicate selector
+ ifmt!("{0, plural, one{} one{} other{}}", 1u); //~ ERROR: duplicate selector
+
+ // bad syntax of the format string
+
+ ifmt!("{"); //~ ERROR: unterminated format string
+ ifmt!("\\ "); //~ ERROR: invalid escape
+ ifmt!("\\"); //~ ERROR: expected an escape
+
+ ifmt!("{0, }", 1); //~ ERROR: expected method
+ ifmt!("{0, foo}", 1); //~ ERROR: unknown method
+ ifmt!("{0, select}", "a"); //~ ERROR: must be followed by
+ ifmt!("{0, plural}", 1); //~ ERROR: must be followed by
+
+ ifmt!("{0, select, a{{}", 1); //~ ERROR: must be terminated
+ ifmt!("{0, select, {} other{}}", "a"); //~ ERROR: empty selector
+ ifmt!("{0, select, other{} other{}}", "a"); //~ ERROR: multiple `other`
+ ifmt!("{0, plural, offset: other{}}", "a"); //~ ERROR: must be an integer
+ ifmt!("{0, plural, offset 1 other{}}", "a"); //~ ERROR: be followed by `:`
+ ifmt!("{0, plural, =a{} other{}}", "a"); //~ ERROR: followed by an integer
+ ifmt!("{0, plural, a{} other{}}", "a"); //~ ERROR: unexpected plural
+ ifmt!("{0, select, a{}}", "a"); //~ ERROR: must provide an `other`
+ ifmt!("{0, plural, =1{}}", "a"); //~ ERROR: must provide an `other`
+
+ ifmt!("{0, plural, other{{0:s}}}", "a"); //~ ERROR: previously used as
+ ifmt!("{:s} {0, plural, other{}}", "a"); //~ ERROR: argument used to
+ ifmt!("{0, select, other{}} \
+ {0, plural, other{}}", "a");
+ //~^ ERROR: declared with multiple formats
+
+ // It should be illegal to use implicit placement arguments nested inside of
+ // format strings because otherwise the "internal pointer of which argument
+ // is next" would be invalidated if different cases had different numbers of
+ // arguments.
+ ifmt!("{0, select, other{{}}}", "a"); //~ ERROR: cannot use implicit
+ ifmt!("{0, plural, other{{}}}", 1); //~ ERROR: cannot use implicit
+ ifmt!("{0, plural, other{{1:.*d}}}", 1, 2); //~ ERROR: cannot use implicit
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ ifmt!("{0, plural, other{}}", "a");
+ //~^ ERROR: expected uint but found
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ ifmt!("{0, select, other{}}", 2);
+ //~^ ERROR: expected &str but found integral
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ ifmt!("{:d}", "3");
+ //~^ ERROR: failed to find an implementation of trait std::fmt::Signed
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ ifmt!("{:notimplemented}", "3");
+ //~^ ERROR: unknown format trait `notimplemented`
+}
MyStruct {priv_field: 4}
}
impl MyStruct {
- priv fn happyfun(&self) {}
+ fn happyfun(&self) {}
}
}
//~^ ERROR unresolved import: found `fly` in `zoo` but it is private
mod zoo {
- priv type fly = ();
- priv fn fly() {}
+ type fly = ();
+ fn fly() {}
}
//~^ ERROR unresolved import: found `fly` in `zoo` but it is private
mod zoo {
- priv fn fly() {}
+ fn fly() {}
}
}
impl Foo {
- priv fn foo(&self) {}
+ fn foo(&self) {}
}
}
// except according to those terms.
mod a {
- priv fn f() {}
+ fn f() {}
}
fn main() {
}
impl cat {
- priv fn nap(&self) {}
+ fn nap(&self) {}
}
pub fn cat(in_x : uint, in_y : int) -> cat {
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:xcrate_unit_struct.rs
+
+// Make sure that when we have cross-crate unit structs we don't accidentally
+// make values out of cross-crate structs that aren't unit.
+
+extern mod xcrate_unit_struct;
+
+fn main() {
+ let _ = xcrate_unit_struct::StructWithFields; //~ ERROR: unresolved name
+ let _ = xcrate_unit_struct::Struct;
+}
// except according to those terms.
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
+// xfail-test broken in newrt?
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test linked failure
// error-pattern:explicit failure
// Testing that runtime failure doesn't cause callbacks to abort abnormally.
// Instead the failure will be delivered after the callbacks return.
// except according to those terms.
+// xfail-test linked failure
// error-pattern:1 == 2
extern mod extra;
// except according to those terms.
+// xfail-test linked failure
// error-pattern:fail
use std::comm;
// except according to those terms.
+// xfail-test linked failure
// error-pattern:fail
use std::comm;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test linked failure
// error-pattern:1 == 2
use std::comm;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test linked failure
// xfail-win32
// error-pattern:explicit
extern mod extra;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test linked failure
// error-pattern:goodfail
use std::comm;
}
impl dog {
- priv fn bark(&self) -> int {
+ fn bark(&self) -> int {
info!("Woof %u %d", *self.barks, *self.volume);
*self.barks += 1u;
if *self.barks % 3u == 0u {
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// xfail-test FIXME #7307
-// xfail-fast
-
-extern mod extra;
-use extra::oldmap::*;
-
-class cat : map<int, bool> {
- priv {
- // Yes, you can have negative meows
- let mut meows : int;
- fn meow() {
- self.meows += 1;
- error!("Meow %d", self.meows);
- if self.meows % 5 == 0 {
- self.how_hungry += 1;
- }
- }
- }
-
- let mut how_hungry : int;
- let name : str;
-
- new(in_x : int, in_y : int, in_name: str)
- { self.meows = in_x; self.how_hungry = in_y; self.name = in_name; }
-
- fn speak() { self.meow(); }
-
- fn eat() -> bool {
- if self.how_hungry > 0 {
- error!("OM NOM NOM");
- self.how_hungry -= 2;
- return true;
- }
- else {
- error!("Not hungry!");
- return false;
- }
- }
-
- fn size() -> uint { self.meows as uint }
- fn insert(+k: int, +v: bool) -> bool {
- if v { self.meows += k; } else { self.meows -= k; };
- true
- }
- fn contains_key(&&k: int) -> bool { k <= self.meows }
- fn get(&&k:int) -> bool { k <= self.meows }
- fn [](&&k:int) -> bool { k <= self.meows }
- fn find(&&k:int) -> Option<bool> { Some(self.get(k)) }
- fn remove(&&k:int) -> Option<bool> { self.meows -= k; Some(true) }
- fn each(f: &fn(&&int, &&bool) -> bool) {
- let mut n = num::abs(self.meows);
- while n > 0 {
- if !f(n, true) { break; }
- n -= 1;
- }
- }
- fn each_key(&&f: &fn(&&int) -> bool) {
- for self.each |k, _v| { if !f(k) { break; } again;};
- }
- fn each_value(&&f: &fn(&&bool) -> bool) {
- for self.each |_k, v| { if !f(v) { break; } again;};
- }
- fn clear() { }
-}
-
-pub fn main() {
- let nyan : cat = cat(0, 2, "nyan");
- for _ in range(1u, 5u) { nyan.speak(); }
- // cat returns true if uint input is greater than
- // the number of meows so far
- assert!((nyan.get(1)));
- assert!((!nyan.get(10)));
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// xfail-test FIXME #7305
-
-extern mod extra;
-use extra::oldmap::*;
-use vec::*;
-use dvec::{dvec, extensions};
-
-enum furniture { chair, couch, bed }
-enum body_part { finger, toe, nose, ear }
-
-trait noisy {
- fn speak() -> int;
-}
-
-trait scratchy {
- fn scratch() -> Option<furniture>;
-}
-
-trait bitey {
- fn bite() -> body_part;
-}
-
-fn vec_includes<T>(xs: ~[T], x: T) -> bool {
- for each(xs) |y| { if y == x { return true; }}
- return false;
-}
-
-// vtables other than the 1st one don't seem to work
-class cat : noisy, scratchy, bitey {
- priv {
- let meows : @mut uint;
- let scratched : dvec<furniture>;
- let bite_counts : hashmap<body_part, uint>;
-
- fn meow() -> uint {
- info!("Meow: %u", *self.meows);
- *self.meows += 1u;
- if *self.meows % 5u == 0u {
- *self.how_hungry += 1;
- }
- *self.meows
- }
- }
-
- let how_hungry : @mut int;
- let name : str;
-
- new(in_x : uint, in_y : int, in_name: str)
- { self.meows = @mut in_x; self.how_hungry = @mut in_y;
- self.name = in_name; self.scratched = dvec();
- let hsher: hashfn<body_part> = |p| int::hash(p as int);
- let eqer : eqfn<body_part> = |p, q| p == q;
- let t : hashmap<body_part, uint> =
- hashmap::<body_part, uint>(hsher, eqer);
- self.bite_counts = t;
- do iter(~[finger, toe, nose, ear]) |p| {
- self.bite_counts.insert(p, 0u);
- };
- }
-
- fn speak() -> int { self.meow() as int }
- fn meow_count() -> uint { *self.meows }
- fn scratch() -> Option<furniture> {
- let all = ~[chair, couch, bed];
- log(error, self.scratched);
- let mut rslt = None;
- for each(all) |thing| { if !self.scratched.contains(thing) {
- self.scratched.push(thing);
- return Some(thing); }}
- rslt
- }
- fn bite() -> body_part {
- error!("In bite()");
- let all = ~[toe, nose, ear];
- let mut min = finger;
- do iter(all) |next| {
- info!("min = %?", min);
- if self.bite_counts.get(next) < self.bite_counts.get(min) {
- min = next;
- }};
- self.bite_counts.insert(min, self.bite_counts.get(min) + 1u);
- info!("Bit %?", min);
- min
- }
-}
-
-fn annoy_neighbors<T:noisy>(critter: T) {
- for i in range(0u, 10u) {
- let what = critter.speak();
- info!("%u %d", i, what);
- }
-}
-
-fn bite_everything<T:bitey>(critter: T) -> bool {
- let mut left : ~[body_part] = ~[finger, toe, nose, ear];
- while left.len() > 0u {
- let part = critter.bite();
- info!("%? %?", left, part);
- if vec_includes(left, part) {
- left = vec::filter(left, |p| p != part );
- }
- else {
- return false;
- }
- }
- true
-}
-
-fn scratched_something<T:scratchy>(critter: T) -> bool {
- option::is_some(critter.scratch())
-}
-
-pub fn main() {
- let nyan : cat = cat(0u, 2, "nyan");
- annoy_neighbors(nyan as noisy);
- assert_eq!(nyan.meow_count(), 10u);
- assert!((bite_everything(nyan as bitey)));
- assert!((scratched_something(nyan as scratchy)));
-}
sum(y)
}
-/* FIXME #7304
-fn sum_const(y: &const [int]) -> int {
- sum(y)
-}
-*/
-
pub fn main() {}
-/* FIXME #7302
-fn foo(v: &const [uint]) -> ~[uint] {
- v.to_owned()
-}
-*/
-
fn bar(v: &mut [uint]) -> ~[uint] {
v.to_owned()
}
pub fn main() {
let mut the_vec = ~[1u, 2, 3, 100];
-// assert_eq!(the_vec.clone(), foo(the_vec));
assert_eq!(the_vec.clone(), bar(the_vec));
assert_eq!(the_vec.clone(), bip(the_vec));
}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that the derived impls for the comparison traits shortcircuit
+// where possible, by having a type that fails when compared as the
+// second element, so this passes iff the instances shortcircuit.
+
+pub struct FailCmp;
+impl Eq for FailCmp {
+ fn eq(&self, _: &FailCmp) -> bool { fail!("eq") }
+}
+
+impl Ord for FailCmp {
+ fn lt(&self, _: &FailCmp) -> bool { fail!("lt") }
+}
+
+impl TotalEq for FailCmp {
+ fn equals(&self, _: &FailCmp) -> bool { fail!("equals") }
+}
+
+impl TotalOrd for FailCmp {
+ fn cmp(&self, _: &FailCmp) -> Ordering { fail!("cmp") }
+}
+
+#[deriving(Eq,Ord,TotalEq,TotalOrd)]
+struct ShortCircuit {
+ x: int,
+ y: FailCmp
+}
+
+fn main() {
+ let a = ShortCircuit { x: 1, y: FailCmp };
+ let b = ShortCircuit { x: 2, y: FailCmp };
+
+ assert!(a != b);
+ assert!(a < b);
+ assert!(!a.equals(&b));
+ assert_eq!(a.cmp(&b), ::std::cmp::Less);
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::fmt;
+
+struct A;
+struct B;
+
+#[fmt="foo"]
+impl fmt::Signed for A {
+ fn fmt(_: &A, f: &mut fmt::Formatter) { f.buf.write("aloha".as_bytes()); }
+}
+impl fmt::Signed for B {
+ fn fmt(_: &B, f: &mut fmt::Formatter) { f.buf.write("adios".as_bytes()); }
+}
+
+pub fn main() {
+ fn t(a: ~str, b: &str) { assert_eq!(a, b.to_owned()); }
+
+ // Make sure there's a poly formatter that takes anything
+ t(ifmt!("{}", 1), "1");
+ t(ifmt!("{}", A), "{}");
+ t(ifmt!("{}", ()), "()");
+ t(ifmt!("{}", @(~1, "foo")), "@(~1, \"foo\")");
+
+ // Various edge cases without formats
+ t(ifmt!(""), "");
+ t(ifmt!("hello"), "hello");
+ t(ifmt!("hello \\{"), "hello {");
+
+ // At least exercise all the formats
+ t(ifmt!("{:b}", true), "true");
+ t(ifmt!("{:c}", '☃'), "☃");
+ t(ifmt!("{:d}", 10), "10");
+ t(ifmt!("{:i}", 10), "10");
+ t(ifmt!("{:u}", 10u), "10");
+ t(ifmt!("{:o}", 10u), "12");
+ t(ifmt!("{:x}", 10u), "a");
+ t(ifmt!("{:X}", 10u), "A");
+ t(ifmt!("{:s}", "foo"), "foo");
+ t(ifmt!("{:p}", 0x1234 as *int), "0x1234");
+ t(ifmt!("{:p}", 0x1234 as *mut int), "0x1234");
+ t(ifmt!("{:d}", A), "aloha");
+ t(ifmt!("{:d}", B), "adios");
+ t(ifmt!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
+ t(ifmt!("{1} {0}", 0, 1), "1 0");
+ t(ifmt!("{foo} {bar}", foo=0, bar=1), "0 1");
+ t(ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
+ t(ifmt!("{} {0:s}", "a"), "a a");
+ t(ifmt!("{} {0}", "a"), "\"a\" \"a\"");
+
+ // Methods should probably work
+ t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
+ t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 1u), "a1");
+ t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 2u), "b2");
+ t(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 3u), "d3");
+ t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "a"), "aa");
+ t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "b"), "bb");
+ t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "c"), "cc");
+ t(ifmt!("{0, select, a{a#} b{b#} c{c#} other{d#}}", "d"), "dd");
+ t(ifmt!("{1, select, a{#{0:s}} other{#{1}}}", "b", "a"), "ab");
+ t(ifmt!("{1, select, a{#{0}} other{#{1}}}", "c", "b"), "bb");
+}
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test linked failure
// xfail-fast
// xfail-win32 #7999
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test linked failure
// xfail-win32 leaks
extern mod extra;
}
fn uint_range_rev(hi: uint, lo: uint, it: &fn(uint) -> bool) -> bool {
- uint::range_rev(hi, lo, it)
+ range(lo, hi).invert().advance(it)
}
fn int_range_rev(hi: int, lo: int, it: &fn(int) -> bool) -> bool {
- int::range_rev(hi, lo, it)
+ range(lo, hi).invert().advance(it)
}
fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool {
fn get(self) -> int;
}
-// FIXME #7302: Note: impl on a slice
+// Note: impl on a slice; we're checking that the pointers below
+// correctly get borrowed to `&`. (similar to impling for `int`, with
+// `&self` instead of `self`.)
impl<'self> get for &'self int {
fn get(self) -> int {
return *self;
info!("y=%d", y);
assert_eq!(y, 6);
- let x = ~6;
- let y = x.get();
- info!("y=%d", y);
- assert_eq!(y, 6);
-
let x = &6;
let y = x.get();
info!("y=%d", y);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test linked failure
// xfail-win32
extern mod extra;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test linked failure
// xfail-win32
// A port of task-killjoin to use a class with a dtor to manage
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// xfail-test linked failure
// xfail-win32
// Create a task that is supervised by another task, join the supervised task
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:xcrate_unit_struct.rs
+// xfail-fast
+extern mod xcrate_unit_struct;
+
+use std::util;
+
+static s1: xcrate_unit_struct::Struct = xcrate_unit_struct::Struct;
+static s2: xcrate_unit_struct::Unit = xcrate_unit_struct::Unit;
+static s3: xcrate_unit_struct::Unit =
+ xcrate_unit_struct::Argument(xcrate_unit_struct::Struct);
+static s4: xcrate_unit_struct::Unit = xcrate_unit_struct::Argument(s1);
+
+fn f1(_: xcrate_unit_struct::Struct) {}
+fn f2(_: xcrate_unit_struct::Unit) {}
+
+fn main() {
+ f1(xcrate_unit_struct::Struct);
+ f2(xcrate_unit_struct::Unit);
+ f2(xcrate_unit_struct::Argument(xcrate_unit_struct::Struct));
+
+ f1(s1);
+ f2(s2);
+ f2(s3);
+ f2(s4);
+}