diff --git a/doc/tutorial-conditions.md b/doc/tutorial-conditions.md index 726b8bb2b8001..056d967ae6ca8 100644 --- a/doc/tutorial-conditions.md +++ b/doc/tutorial-conditions.md @@ -43,7 +43,7 @@ $ ./example numbers.txt An example program that does this task reads like this: -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; @@ -430,7 +430,7 @@ To trap a condition, use `Condition::trap` in some caller of the site that calls For example, this version of the program traps the `malformed_line` condition and replaces bad input lines with the pair `(-1,-1)`: -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; @@ -507,7 +507,7 @@ In the example program, the first form of the `malformed_line` API implicitly as This assumption may not be correct; some callers may wish to skip malformed lines, for example. Changing the condition's return type from `(int,int)` to `Option<(int,int)>` will suffice to support this type of recovery: -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; @@ -594,7 +594,7 @@ until all relevant combinations encountered in practice are encoded. In the example, suppose a third possible recovery form arose: reusing the previous value read. This can be encoded in the handler API by introducing a helper type: `enum MalformedLineFix`. -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; @@ -720,7 +720,7 @@ task failed at 'called `Option::unwrap()` on a `None` value', .../libs To make the program robust -- or at least flexible -- in the face of this potential failure, a second condition and a helper function will suffice: -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 767f712a8d8c1..4983a5af3e5ab 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -69,7 +69,6 @@ calling the `spawn` function with a closure argument. `spawn` executes the closure in the new task. ~~~~ -# use std::io::println; # use std::task::spawn; // Print something profound in a different task using a named function diff --git a/doc/tutorial.md b/doc/tutorial.md index 7451919c5becf..f9f110c122b28 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -2907,12 +2907,12 @@ you just have to import it with an `use` statement. For example, it re-exports `println` which is defined in `std::io::println`: ~~~ -use puts = std::io::println; +use puts = std::rt::io::stdio::println; fn main() { println("println is imported per default."); puts("Doesn't hinder you from importing it under an different name yourself."); - ::std::io::println("Or from not using the automatic import."); + ::std::rt::io::stdio::println("Or from not using the automatic import."); } ~~~ diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index d02b88ae74e5f..4ae9ad81daff6 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -21,7 +21,10 @@ use util; use util::logv; use std::cell::Cell; -use std::io; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::file::FileInfo; use std::os; use std::str; use std::task::{spawn_sched, SingleThreaded}; @@ -60,7 +63,7 @@ pub fn run(config: config, testfile: ~str) { pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) { if config.verbose { // We're going to be dumping a lot of info. Start on a new line. - io::stdout().write_str("\n\n"); + print!("\n\n"); } let testfile = Path::new(testfile); debug!("running {}", testfile.display()); @@ -170,7 +173,9 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { let rounds = match props.pp_exact { Some(_) => 1, None => 2 }; - let mut srcs = ~[io::read_whole_file_str(testfile).unwrap()]; + let src = testfile.open_reader(io::Open).read_to_end(); + let src = str::from_utf8_owned(src); + let mut srcs = ~[src]; let mut round = 0; while round < rounds { @@ -190,7 +195,8 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { let mut expected = match props.pp_exact { Some(ref file) => { let filepath = testfile.dir_path().join(file); - io::read_whole_file_str(&filepath).unwrap() + let s = filepath.open_reader(io::Open).read_to_end(); + str::from_utf8_owned(s) } None => { srcs[srcs.len() - 2u].clone() } }; @@ -228,8 +234,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { fn compare_source(expected: &str, actual: &str) { if expected != actual { error(~"pretty-printed source does not match expected source"); - let msg = - format!("\n\ + println!("\n\ expected:\n\ ------------------------------------------\n\ {}\n\ @@ -240,7 +245,6 @@ actual:\n\ ------------------------------------------\n\ \n", expected, actual); - io::stdout().write_str(msg); fail!(); } } @@ -741,9 +745,7 @@ fn dump_output(config: &config, testfile: &Path, out: &str, err: &str) { fn dump_output_file(config: &config, testfile: &Path, out: &str, extension: &str) { let outfile = make_out_name(config, testfile, extension); - let writer = - io::file_writer(&outfile, [io::Create, io::Truncate]).unwrap(); - writer.write_str(out); + outfile.open_writer(io::CreateOrTruncate).write(out.as_bytes()); } fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path { @@ -771,24 +773,20 @@ fn output_base_name(config: &config, testfile: &Path) -> Path { fn maybe_dump_to_stdout(config: &config, out: &str, err: &str) { if config.verbose { - let sep1 = format!("------{}------------------------------", "stdout"); - let sep2 = format!("------{}------------------------------", "stderr"); - let sep3 = ~"------------------------------------------"; - io::stdout().write_line(sep1); - io::stdout().write_line(out); - io::stdout().write_line(sep2); - io::stdout().write_line(err); - io::stdout().write_line(sep3); + println!("------{}------------------------------", "stdout"); + println!("{}", out); + println!("------{}------------------------------", "stderr"); + println!("{}", err); + println!("------------------------------------------"); } } -fn error(err: ~str) { io::stdout().write_line(format!("\nerror: {}", err)); } +fn error(err: ~str) { println!("\nerror: {}", err); } fn fatal(err: ~str) -> ! { error(err); fail!(); } fn fatal_ProcRes(err: ~str, ProcRes: &ProcRes) -> ! { - let msg = - format!("\n\ + print!("\n\ error: {}\n\ command: {}\n\ stdout:\n\ @@ -801,7 +799,6 @@ stderr:\n\ ------------------------------------------\n\ \n", err, ProcRes.cmdline, ProcRes.stdout, ProcRes.stderr); - io::stdout().write_str(msg); fail!(); } @@ -821,9 +818,9 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps, ~[(~"",~"")], Some(~"")); if config.verbose { - io::stdout().write_str(format!("push ({}) {} {} {}", + println!("push ({}) {} {} {}", config.target, args.prog, - copy_result.out, copy_result.err)); + copy_result.out, copy_result.err); } logv(config, format!("executing ({}) {}", config.target, cmdline)); @@ -913,9 +910,9 @@ fn _arm_push_aux_shared_library(config: &config, testfile: &Path) { ~[(~"",~"")], Some(~"")); if config.verbose { - io::stdout().write_str(format!("push ({}) {} {} {}", + println!("push ({}) {} {} {}", config.target, file.display(), - copy_result.out, copy_result.err)); + copy_result.out, copy_result.err); } } } @@ -999,7 +996,8 @@ fn disassemble_extract(config: &config, _props: &TestProps, fn count_extracted_lines(p: &Path) -> uint { - let x = io::read_whole_file_str(&p.with_extension("ll")).unwrap(); + let x = p.with_extension("ll").open_reader(io::Open).read_to_end(); + let x = str::from_utf8_owned(x); x.line_iter().len() } diff --git a/src/compiletest/util.rs b/src/compiletest/util.rs index 04ef180299daf..ae4a25b80084c 100644 --- a/src/compiletest/util.rs +++ b/src/compiletest/util.rs @@ -10,7 +10,6 @@ use common::config; -use std::io; use std::os::getenv; /// Conversion table from triple OS name to Rust SYSNAME @@ -64,5 +63,5 @@ pub fn path_div() -> ~str { ~";" } pub fn logv(config: &config, s: ~str) { debug!("{}", s); - if config.verbose { io::println(s); } + if config.verbose { println(s); } } diff --git a/src/etc/combine-tests.py b/src/etc/combine-tests.py index 25976410c7c9c..dc5e11dabdf68 100755 --- a/src/etc/combine-tests.py +++ b/src/etc/combine-tests.py @@ -56,15 +56,15 @@ def scrub(b): d.write("extern mod extra;\n") d.write("extern mod run_pass_stage2;\n") d.write("use run_pass_stage2::*;\n") -d.write("use std::io::WriterUtil;\n"); -d.write("use std::io;\n"); +d.write("use std::rt::io;\n"); +d.write("use std::rt::io::Writer;\n"); d.write("fn main() {\n"); -d.write(" let out = io::stdout();\n"); +d.write(" let mut out = io::stdout();\n"); i = 0 for t in stage2_tests: p = os.path.join("test", "run-pass", t) p = p.replace("\\", "\\\\") - d.write(" out.write_str(\"run-pass [stage2]: %s\\n\");\n" % p) + d.write(" out.write(\"run-pass [stage2]: %s\\n\".as_bytes());\n" % p) d.write(" t_%d::main();\n" % i) i += 1 d.write("}\n") diff --git a/src/libextra/ebml.rs b/src/libextra/ebml.rs index 34515a2b955cb..f577ed55f9750 100644 --- a/src/libextra/ebml.rs +++ b/src/libextra/ebml.rs @@ -96,16 +96,8 @@ pub mod reader { use std::cast::transmute; use std::int; - use std::io; use std::option::{None, Option, Some}; - - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "x86_64")] - use std::ptr::offset; - - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "x86_64")] - use std::unstable::intrinsics::bswap32; + use std::rt::io::extensions::u64_from_be_bytes; // ebml reading @@ -144,6 +136,9 @@ pub mod reader { #[cfg(target_arch = "x86")] #[cfg(target_arch = "x86_64")] pub fn vuint_at(data: &[u8], start: uint) -> Res { + use std::ptr::offset; + use std::unstable::intrinsics::bswap32; + if data.len() - start < 4 { return vuint_at_slow(data, start); } @@ -178,8 +173,7 @@ pub mod reader { } } - #[cfg(target_arch = "arm")] - #[cfg(target_arch = "mips")] + #[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))] pub fn vuint_at(data: &[u8], start: uint) -> Res { vuint_at_slow(data, start) } @@ -265,17 +259,17 @@ pub mod reader { pub fn doc_as_u16(d: Doc) -> u16 { assert_eq!(d.end, d.start + 2u); - io::u64_from_be_bytes(*d.data, d.start, 2u) as u16 + u64_from_be_bytes(*d.data, d.start, 2u) as u16 } pub fn doc_as_u32(d: Doc) -> u32 { assert_eq!(d.end, d.start + 4u); - io::u64_from_be_bytes(*d.data, d.start, 4u) as u32 + u64_from_be_bytes(*d.data, d.start, 4u) as u32 } pub fn doc_as_u64(d: Doc) -> u64 { assert_eq!(d.end, d.start + 8u); - io::u64_from_be_bytes(*d.data, d.start, 8u) + u64_from_be_bytes(*d.data, d.start, 8u) } pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } @@ -614,11 +608,15 @@ pub mod writer { use std::cast; use std::clone::Clone; - use std::io; + use std::rt::io; + use std::rt::io::{Writer, Seek}; + use std::rt::io::mem::MemWriter; + use std::rt::io::extensions::u64_to_be_bytes; // ebml writing pub struct Encoder { - writer: @io::Writer, + // FIXME(#5665): this should take a trait object + writer: @mut MemWriter, priv size_positions: ~[uint], } @@ -631,7 +629,7 @@ pub mod writer { } } - fn write_sized_vuint(w: @io::Writer, n: uint, size: uint) { + fn write_sized_vuint(w: @mut MemWriter, n: uint, size: uint) { match size { 1u => w.write(&[0x80u8 | (n as u8)]), 2u => w.write(&[0x40u8 | ((n >> 8_u) as u8), n as u8]), @@ -643,7 +641,7 @@ pub mod writer { }; } - fn write_vuint(w: @io::Writer, n: uint) { + fn write_vuint(w: @mut MemWriter, n: uint) { if n < 0x7f_u { write_sized_vuint(w, n, 1u); return; } if n < 0x4000_u { write_sized_vuint(w, n, 2u); return; } if n < 0x200000_u { write_sized_vuint(w, n, 3u); return; } @@ -651,7 +649,7 @@ pub mod writer { fail!("vint to write too big: {}", n); } - pub fn Encoder(w: @io::Writer) -> Encoder { + pub fn Encoder(w: @mut MemWriter) -> Encoder { let size_positions: ~[uint] = ~[]; Encoder { writer: w, @@ -668,7 +666,7 @@ pub mod writer { write_vuint(self.writer, tag_id); // Write a placeholder four-byte size. - self.size_positions.push(self.writer.tell()); + self.size_positions.push(self.writer.tell() as uint); let zeroes: &[u8] = &[0u8, 0u8, 0u8, 0u8]; self.writer.write(zeroes); } @@ -676,10 +674,10 @@ pub mod writer { pub fn end_tag(&mut self) { let last_size_pos = self.size_positions.pop(); let cur_pos = self.writer.tell(); - self.writer.seek(last_size_pos as int, io::SeekSet); - let size = (cur_pos - last_size_pos - 4u); - write_sized_vuint(self.writer, size, 4u); - self.writer.seek(cur_pos as int, io::SeekSet); + self.writer.seek(last_size_pos as i64, io::SeekSet); + let size = (cur_pos as uint - last_size_pos - 4); + write_sized_vuint(self.writer, size as uint, 4u); + self.writer.seek(cur_pos as i64, io::SeekSet); debug!("End tag (size = {})", size); } @@ -697,19 +695,19 @@ pub mod writer { } pub fn wr_tagged_u64(&mut self, tag_id: uint, v: u64) { - do io::u64_to_be_bytes(v, 8u) |v| { + do u64_to_be_bytes(v, 8u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_u32(&mut self, tag_id: uint, v: u32) { - do io::u64_to_be_bytes(v as u64, 4u) |v| { + do u64_to_be_bytes(v as u64, 4u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_u16(&mut self, tag_id: uint, v: u16) { - do io::u64_to_be_bytes(v as u64, 2u) |v| { + do u64_to_be_bytes(v as u64, 2u) |v| { self.wr_tagged_bytes(tag_id, v); } } @@ -719,19 +717,19 @@ pub mod writer { } pub fn wr_tagged_i64(&mut self, tag_id: uint, v: i64) { - do io::u64_to_be_bytes(v as u64, 8u) |v| { + do u64_to_be_bytes(v as u64, 8u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_i32(&mut self, tag_id: uint, v: i32) { - do io::u64_to_be_bytes(v as u64, 4u) |v| { + do u64_to_be_bytes(v as u64, 4u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_i16(&mut self, tag_id: uint, v: i16) { - do io::u64_to_be_bytes(v as u64, 2u) |v| { + do u64_to_be_bytes(v as u64, 2u) |v| { self.wr_tagged_bytes(tag_id, v); } } @@ -963,18 +961,18 @@ mod tests { use serialize::Encodable; use serialize; - use std::io; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; use std::option::{None, Option, Some}; #[test] fn test_option_int() { fn test_v(v: Option) { debug!("v == {:?}", v); - let bytes = do io::with_bytes_writer |wr| { - let mut ebml_w = writer::Encoder(wr); - v.encode(&mut ebml_w) - }; - let ebml_doc = reader::Doc(@bytes); + let wr = @mut MemWriter::new(); + let mut ebml_w = writer::Encoder(wr); + v.encode(&mut ebml_w); + let ebml_doc = reader::Doc(@wr.inner_ref().to_owned()); let mut deser = reader::Decoder(ebml_doc); let v1 = serialize::Decodable::decode(&mut deser); debug!("v1 == {:?}", v1); diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs index 79a5b555c291f..3ea164fb456f8 100644 --- a/src/libextra/extra.rs +++ b/src/libextra/extra.rs @@ -45,7 +45,6 @@ pub use std::os; // Utility modules pub mod c_vec; -pub mod io_util; // Concurrency @@ -104,7 +103,6 @@ pub mod rational; pub mod complex; pub mod stats; pub mod semver; -pub mod fileinput; pub mod flate; pub mod hex; pub mod uuid; diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs deleted file mode 100644 index 49072dab6d025..0000000000000 --- a/src/libextra/fileinput.rs +++ /dev/null @@ -1,629 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -A library for iterating through the lines in a series of -files. Very similar to [the Python module of the same -name](http://docs.python.org/3.3/library/fileinput.html). - -It allows the programmer to automatically take filenames from the -command line arguments (via `input` and `input_state`), as well as -specify them as a vector directly (`input_vec` and -`input_vec_state`). The files are opened as necessary, so any files -that can't be opened only cause an error when reached in the -iteration. - -On the command line, `stdin` is represented by a filename of `-` (a -single hyphen) and in the functions that take a vector directly -(e.g. `input_vec`) it is represented by `None`. Note `stdin` is *not* -reset once it has been finished, so attempting to iterate on `[None, -None]` will only take input once unless `io::stdin().seek(0, SeekSet)` -is called between. - -The `make_path_option_vec` function handles converting a list of file paths as -strings to the appropriate format, including the (optional) conversion -of `"-"` to `stdin`. - -# Basic - -In many cases, one can use the `input_*` functions without having -to handle any `FileInput` structs. E.g. a simple `cat` program - - for input |line| { - io::println(line) - } - -or a program that numbers lines after concatenating two files - - for input_vec_state(make_path_option_vec([~"a.txt", ~"b.txt"])) |line, state| { - io::println(format!("{}: %s", state.line_num, - line)); - } - -The two `input_vec*` functions take a vec of file names (where empty -means read from `stdin`), the other two functions use the command line -arguments. - -# Advanced - -For more complicated uses (e.g. if one needs to pause iteration and -resume it later), a `FileInput` instance can be constructed via the -`from_vec`, `from_vec_raw` and `from_args` functions. - -Once created, the `each_line` (from the `std::io::ReaderUtil` trait) -and `each_line_state` methods allow one to iterate on the lines; the -latter provides more information about the position within the -iteration to the caller. - -It is possible (and safe) to skip lines and files using the -`read_line` and `next_file` methods. Also, `FileInput` implements -`std::io::Reader`, and the state will be updated correctly while -using any of those methods. - -E.g. the following program reads until an empty line, pauses for user -input, skips the current file and then numbers the remaining lines -(where the numbers are from the start of each file, rather than the -total line count). - - let input = FileInput::from_vec(pathify([~"a.txt", ~"b.txt", ~"c.txt"], - true)); - - for input.each_line |line| { - if line.is_empty() { - break - } - io::println(line); - } - - io::println("Continue?"); - - if io::stdin().read_line() == ~"yes" { - input.next_file(); // skip! - - for input.each_line_state |line, state| { - io::println(format!("{}: %s", state.line_num_file, - line)) - } - } -*/ - -#[allow(missing_doc)]; - - -use std::io::ReaderUtil; -use std::io; -use std::os; - -/** -A summary of the internal state of a `FileInput` object. `line_num` -and `line_num_file` represent the number of lines read in total and in -the current file respectively. `current_path` is `None` if the current -file is `stdin`. -*/ -#[deriving(Clone)] -pub struct FileInputState { - current_path: Option, - line_num: uint, - line_num_file: uint -} - -impl FileInputState { - fn is_stdin(&self) -> bool { - self.current_path.is_none() - } - - fn is_first_line(&self) -> bool { - self.line_num_file == 1 - } -} - -struct FileInput_ { - /** - `Some(path)` is the file represented by `path`, `None` is - `stdin`. Consumed as the files are read. - */ - files: ~[Option], - /** - The current file: `Some(r)` for an open file, `None` before - starting and after reading everything. - */ - 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. - */ - previous_was_newline: bool -} - - -// FIXME #5723: remove this when Reader has &mut self. -// Removing it would mean giving read_byte in the Reader impl for -// FileInput &mut self, which in turn means giving most of the -// io::Reader trait methods &mut self. That can't be done right now -// because of io::with_bytes_reader and #5723. -// 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_ -} - -impl FileInput { - /** - Create a `FileInput` object from a vec of files. An empty - vec means lines are read from `stdin` (use `from_vec_raw` to stop - this behaviour). Any occurrence of `None` represents `stdin`. - */ - pub fn from_vec(files: ~[Option]) -> FileInput { - FileInput::from_vec_raw( - if files.is_empty() { - ~[None] - } else { - files - }) - } - - /** - Identical to `from_vec`, but an empty `files` vec stays - empty. (`None` is `stdin`.) - */ - pub fn from_vec_raw(files: ~[Option]) - -> FileInput { - FileInput{ - fi: @mut FileInput_ { - files: files, - current_reader: None, - state: FileInputState { - current_path: None, - line_num: 0, - line_num_file: 0 - }, - // there was no previous unended line - previous_was_newline: true - } - } - } - - /** - Create a `FileInput` object from the command line - arguments. `"-"` represents `stdin`. - */ - pub fn from_args() -> FileInput { - let args = os::args(); - let pathed = make_path_option_vec(args.tail(), true); - FileInput::from_vec(pathed) - } - - fn current_file_eof(&self) -> bool { - match self.fi.current_reader { - None => false, - Some(r) => r.eof() - } - } - - /** - Skip to the next file in the queue. Can `fail` when opening - a file. - - Returns `false` if there is no more files, and `true` when it - successfully opens the next file. - */ - - pub fn next_file(&self) -> bool { - // No more files - - if self.fi.files.is_empty() { - self.fi.current_reader = None; - return false; - } - - let path_option = self.fi.files.shift(); - let file = match path_option { - None => io::stdin(), - Some(ref path) => io::file_reader(path).unwrap() - }; - - self.fi.current_reader = Some(file); - self.fi.state.current_path = path_option; - self.fi.state.line_num_file = 0; - true - } - - /** - Attempt to open the next file if there is none currently open, - or if the current one is EOF'd. - - Returns `true` if it had to move to the next file and did - so successfully. - */ - fn next_file_if_eof(&self) -> bool { - match self.fi.current_reader { - None => self.next_file(), - Some(r) => { - if r.eof() { - self.next_file() - } else { - false - } - } - } - } - - /** - Apply `f` to each line successively, along with some state - (line numbers and file names, see documentation for - `FileInputState`). Otherwise identical to `lines_each`. - */ - pub fn each_line_state(&self, - f: &fn(&str, FileInputState) -> bool) -> bool { - self.each_line(|line| f(line, self.fi.state.clone())) - } - - - /** - Retrieve the current `FileInputState` information. - */ - pub fn state(&self) -> FileInputState { - self.fi.state.clone() - } -} - -impl io::Reader for FileInput { - fn read_byte(&self) -> int { - loop { - let stepped = self.next_file_if_eof(); - - // if we moved to the next file, and the previous - // character wasn't \n, then there is an unfinished line - // from the previous file. This library models - // line-by-line processing and the trailing line of the - // previous file and the leading of the current file - // should be considered different, so we need to insert a - // fake line separator - if stepped && !self.fi.previous_was_newline { - self.fi.state.line_num += 1; - self.fi.state.line_num_file += 1; - self.fi.previous_was_newline = true; - return '\n' as int; - } - - match self.fi.current_reader { - None => return -1, - Some(r) => { - let b = r.read_byte(); - - if b < 0 { - continue; - } - - if b == '\n' as int { - self.fi.state.line_num += 1; - self.fi.state.line_num_file += 1; - self.fi.previous_was_newline = true; - } else { - self.fi.previous_was_newline = false; - } - - return b; - } - } - } - } - fn read(&self, buf: &mut [u8], len: uint) -> uint { - let mut count = 0; - while count < len { - let b = self.read_byte(); - if b < 0 { break } - - buf[count] = b as u8; - count += 1; - } - - count - } - fn eof(&self) -> bool { - // we've run out of files, and current_reader is either None or eof. - - self.fi.files.is_empty() && - match self.fi.current_reader { None => true, Some(r) => r.eof() } - - } - fn seek(&self, offset: int, whence: io::SeekStyle) { - match self.fi.current_reader { - None => {}, - Some(r) => r.seek(offset, whence) - } - } - fn tell(&self) -> uint { - match self.fi.current_reader { - None => 0, - Some(r) => r.tell() - } - } -} - -/** -Convert a list of strings to an appropriate form for a `FileInput` -instance. `stdin_hyphen` controls whether `-` represents `stdin` or -a literal `-`. -*/ -pub fn make_path_option_vec(vec: &[~str], stdin_hyphen : bool) -> ~[Option] { - vec.iter().map(|s| { - if stdin_hyphen && "-" == *s { - None - } else { - Some(Path::new(s.as_slice())) - } - }).collect() -} - -/** -Iterate directly over the command line arguments (no arguments implies -reading from `stdin`). - -Fails when attempting to read from a file that can't be opened. -*/ -pub fn input(f: &fn(&str) -> bool) -> bool { - let i = FileInput::from_args(); - i.each_line(f) -} - -/** -Iterate directly over the command line arguments (no arguments -implies reading from `stdin`) with the current state of the iteration -provided at each call. - -Fails when attempting to read from a file that can't be opened. -*/ -pub fn input_state(f: &fn(&str, FileInputState) -> bool) -> bool { - let i = FileInput::from_args(); - i.each_line_state(f) -} - -/** -Iterate over a vector of files (an empty vector implies just `stdin`). - -Fails when attempting to read from a file that can't be opened. -*/ -pub fn input_vec(files: ~[Option], f: &fn(&str) -> bool) -> bool { - let i = FileInput::from_vec(files); - i.each_line(f) -} - -/** -Iterate over a vector of files (an empty vector implies just `stdin`) -with the current state of the iteration provided at each call. - -Fails when attempting to read from a file that can't be opened. -*/ -pub fn input_vec_state(files: ~[Option], - f: &fn(&str, FileInputState) -> bool) -> bool { - let i = FileInput::from_vec(files); - i.each_line_state(f) -} - -#[cfg(test)] -mod test { - - use super::{FileInput, make_path_option_vec, input_vec, input_vec_state}; - - use std::rt::io; - use std::rt::io::Writer; - use std::rt::io::file; - use std::vec; - - fn make_file(path : &Path, contents: &[~str]) { - let mut file = file::open(path, io::CreateOrTruncate, io::Write).unwrap(); - - for str in contents.iter() { - file.write(str.as_bytes()); - file.write(['\n' as u8]); - } - } - - #[test] - fn test_make_path_option_vec() { - let strs = [~"some/path", - ~"some/other/path"]; - let paths = ~[Some(Path::new("some/path")), - Some(Path::new("some/other/path"))]; - - assert_eq!(make_path_option_vec(strs, true), paths.clone()); - assert_eq!(make_path_option_vec(strs, false), paths); - - assert_eq!(make_path_option_vec([~"-"], true), ~[None]); - assert_eq!(make_path_option_vec([~"-"], false), ~[Some(Path::new("-"))]); - } - - #[test] - fn test_fileinput_read_byte() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-fileinput-read-byte-{}.tmp", i)), true); - - // 3 files containing 0\n, 1\n, and 2\n respectively - for (i, filename) in filenames.iter().enumerate() { - make_file(filename.get_ref(), [format!("{}", i)]); - } - - let fi = FileInput::from_vec(filenames.clone()); - - for (line, c) in "012".iter().enumerate() { - assert_eq!(fi.read_byte(), c as int); - assert_eq!(fi.state().line_num, line); - assert_eq!(fi.state().line_num_file, 0); - assert_eq!(fi.read_byte(), '\n' as int); - assert_eq!(fi.state().line_num, line + 1); - assert_eq!(fi.state().line_num_file, 1); - - assert_eq!(fi.state().current_path.clone(), filenames[line].clone()); - } - - assert_eq!(fi.read_byte(), -1); - assert!(fi.eof()); - assert_eq!(fi.state().line_num, 3) - - } - - #[test] - fn test_fileinput_read() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-fileinput-read-{}.tmp", i)), true); - - // 3 files containing 1\n, 2\n, and 3\n respectively - for (i, filename) in filenames.iter().enumerate() { - make_file(filename.get_ref(), [format!("{}", i)]); - } - - let fi = FileInput::from_vec(filenames); - let mut buf : ~[u8] = vec::from_elem(6, 0u8); - let count = fi.read(buf, 10); - assert_eq!(count, 6); - assert_eq!(buf, "0\n1\n2\n".as_bytes().to_owned()); - assert!(fi.eof()) - assert_eq!(fi.state().line_num, 3); - } - - #[test] - fn test_input_vec() { - let mut all_lines = ~[]; - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-input-vec-{}.tmp", i)), true); - - for (i, filename) in filenames.iter().enumerate() { - let contents = - vec::from_fn(3, |j| format!("{} {}", i, j)); - make_file(filename.get_ref(), contents); - debug!("contents={:?}", contents); - all_lines.push_all(contents); - } - - let mut read_lines = ~[]; - do input_vec(filenames) |line| { - read_lines.push(line.to_owned()); - true - }; - assert_eq!(read_lines, all_lines); - } - - #[test] - fn test_input_vec_state() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-input-vec-state-{}.tmp", i)),true); - - for (i, filename) in filenames.iter().enumerate() { - let contents = - vec::from_fn(3, |j| format!("{} {}", i, j + 1)); - make_file(filename.get_ref(), contents); - } - - do input_vec_state(filenames) |line, state| { - let nums: ~[&str] = line.split_iter(' ').collect(); - let file_num = from_str::(nums[0]).unwrap(); - let line_num = from_str::(nums[1]).unwrap(); - assert_eq!(line_num, state.line_num_file); - assert_eq!(file_num * 3 + line_num, state.line_num); - true - }; - } - - #[test] - fn test_empty_files() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-empty-files-{}.tmp", i)),true); - - make_file(filenames[0].get_ref(), [~"1", ~"2"]); - make_file(filenames[1].get_ref(), []); - make_file(filenames[2].get_ref(), [~"3", ~"4"]); - - let mut count = 0; - do input_vec_state(filenames.clone()) |line, state| { - let expected_path = match line { - "1" | "2" => filenames[0].clone(), - "3" | "4" => filenames[2].clone(), - _ => fail!("unexpected line") - }; - assert_eq!(state.current_path.clone(), expected_path); - count += 1; - true - }; - assert_eq!(count, 4); - } - - #[test] - fn test_no_trailing_newline() { - let f1 = - Some(Path::new("tmp/lib-fileinput-test-no-trailing-newline-1.tmp")); - let f2 = - Some(Path::new("tmp/lib-fileinput-test-no-trailing-newline-2.tmp")); - - { - let mut wr = file::open(f1.get_ref(), io::CreateOrTruncate, - io::Write).unwrap(); - wr.write("1\n2".as_bytes()); - let mut wr = file::open(f2.get_ref(), io::CreateOrTruncate, - io::Write).unwrap(); - wr.write("3\n4".as_bytes()); - } - - let mut lines = ~[]; - do input_vec(~[f1, f2]) |line| { - lines.push(line.to_owned()); - true - }; - assert_eq!(lines, ~[~"1", ~"2", ~"3", ~"4"]); - } - - - #[test] - fn test_next_file() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-next-file-{}.tmp", i)),true); - - for (i, filename) in filenames.iter().enumerate() { - let contents = vec::from_fn(3, |j| format!("{} {}", i, j + 1)); - make_file(filename.get_ref(), contents); - } - - let input = FileInput::from_vec(filenames); - - // read once from 0 - assert_eq!(input.read_line(), ~"0 1"); - input.next_file(); // skip the rest of 1 - - // read all lines from 1 (but don't read any from 2), - for i in range(1u, 4) { - assert_eq!(input.read_line(), format!("1 {}", i)); - } - // 1 is finished, but 2 hasn't been started yet, so this will - // just "skip" to the beginning of 2 (Python's fileinput does - // the same) - input.next_file(); - - assert_eq!(input.read_line(), ~"2 1"); - } - - #[test] - #[should_fail] - fn test_input_vec_missing_file() { - do input_vec(make_path_option_vec([~"this/file/doesnt/exist"], true)) |line| { - println(line); - true - }; - } -} diff --git a/src/libextra/io_util.rs b/src/libextra/io_util.rs deleted file mode 100644 index 27a09be3a625b..0000000000000 --- a/src/libextra/io_util.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(missing_doc)]; - -use std::io::{Reader, BytesReader}; -use std::io; -use std::cast; - -/// An implementation of the io::Reader interface which reads a buffer of bytes -pub struct BufReader { - /// The buffer of bytes to read - priv buf: ~[u8], - /// The current position in the buffer of bytes - priv pos: @mut uint -} - -impl BufReader { - /// Creates a new buffer reader for the specified buffer - pub fn new(v: ~[u8]) -> BufReader { - BufReader { - buf: v, - pos: @mut 0 - } - } - - fn as_bytes_reader(&self, f: &fn(&BytesReader) -> A) -> A { - // FIXME(#5723) - let bytes = ::std::util::id::<&[u8]>(self.buf); - let bytes: &'static [u8] = unsafe { cast::transmute(bytes) }; - // Recreating the BytesReader state every call since - // I can't get the borrowing to work correctly - let bytes_reader = BytesReader { - bytes: bytes, - pos: @mut *self.pos - }; - - let res = f(&bytes_reader); - - // FIXME #4429: This isn't correct if f fails - *self.pos = *bytes_reader.pos; - - return res; - } -} - -impl Reader for BufReader { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - self.as_bytes_reader(|r| r.read(bytes, len) ) - } - fn read_byte(&self) -> int { - self.as_bytes_reader(|r| r.read_byte() ) - } - fn eof(&self) -> bool { - self.as_bytes_reader(|r| r.eof() ) - } - fn seek(&self, offset: int, whence: io::SeekStyle) { - self.as_bytes_reader(|r| r.seek(offset, whence) ) - } - fn tell(&self) -> uint { - self.as_bytes_reader(|r| r.tell() ) - } -} diff --git a/src/libextra/json.rs b/src/libextra/json.rs index 90260282e4b5b..0aab7b743ba73 100644 --- a/src/libextra/json.rs +++ b/src/libextra/json.rs @@ -20,8 +20,10 @@ use std::char; use std::cast::transmute; use std::f64; use std::hashmap::HashMap; -use std::io::WriterUtil; -use std::io; +use std::rt::io; +use std::rt::io::Decorator; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::mem::MemWriter; use std::num; use std::str; use std::to_str; @@ -86,19 +88,17 @@ fn spaces(n: uint) -> ~str { /// A structure for implementing serialization to JSON. pub struct Encoder { - priv wr: @io::Writer, + priv wr: @mut io::Writer, } /// Creates a new JSON encoder whose output will be written to the writer /// specified. -pub fn Encoder(wr: @io::Writer) -> Encoder { - Encoder { - wr: wr - } +pub fn Encoder(wr: @mut io::Writer) -> Encoder { + Encoder { wr: wr } } impl serialize::Encoder for Encoder { - fn emit_nil(&mut self) { self.wr.write_str("null") } + fn emit_nil(&mut self) { write!(self.wr, "null") } fn emit_uint(&mut self, v: uint) { self.emit_f64(v as f64); } fn emit_u64(&mut self, v: u64) { self.emit_f64(v as f64); } @@ -114,17 +114,21 @@ impl serialize::Encoder for Encoder { fn emit_bool(&mut self, v: bool) { if v { - self.wr.write_str("true"); + write!(self.wr, "true"); } else { - self.wr.write_str("false"); + write!(self.wr, "false"); } } - fn emit_f64(&mut self, v: f64) { self.wr.write_str(f64::to_str_digits(v, 6u)) } + fn emit_f64(&mut self, v: f64) { + write!(self.wr, "{}", f64::to_str_digits(v, 6u)) + } fn emit_f32(&mut self, v: f32) { self.emit_f64(v as f64); } fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } - fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)) } + fn emit_str(&mut self, v: &str) { + write!(self.wr, "{}", escape_str(v)) + } fn emit_enum(&mut self, _name: &str, f: &fn(&mut Encoder)) { f(self) } @@ -137,23 +141,19 @@ impl serialize::Encoder for Encoder { // Bunny => "Bunny" // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} if cnt == 0 { - self.wr.write_str(escape_str(name)); + write!(self.wr, "{}", escape_str(name)); } else { - self.wr.write_char('{'); - self.wr.write_str("\"variant\""); - self.wr.write_char(':'); - self.wr.write_str(escape_str(name)); - self.wr.write_char(','); - self.wr.write_str("\"fields\""); - self.wr.write_str(":["); + write!(self.wr, "\\{\"variant\":"); + write!(self.wr, "{}", escape_str(name)); + write!(self.wr, ",\"fields\":["); f(self); - self.wr.write_str("]}"); + write!(self.wr, "]\\}"); } } fn emit_enum_variant_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { if idx != 0 { - self.wr.write_char(','); + write!(self.wr, ","); } f(self); } @@ -174,18 +174,17 @@ impl serialize::Encoder for Encoder { } fn emit_struct(&mut self, _: &str, _: uint, f: &fn(&mut Encoder)) { - self.wr.write_char('{'); + write!(self.wr, r"\{"); f(self); - self.wr.write_char('}'); + write!(self.wr, r"\}"); } fn emit_struct_field(&mut self, name: &str, idx: uint, f: &fn(&mut Encoder)) { - if idx != 0 { self.wr.write_char(','); } - self.wr.write_str(escape_str(name)); - self.wr.write_char(':'); + if idx != 0 { write!(self.wr, ",") } + write!(self.wr, "{}:", escape_str(name)); f(self); } @@ -211,31 +210,31 @@ impl serialize::Encoder for Encoder { fn emit_option_some(&mut self, f: &fn(&mut Encoder)) { f(self); } fn emit_seq(&mut self, _len: uint, f: &fn(&mut Encoder)) { - self.wr.write_char('['); + write!(self.wr, "["); f(self); - self.wr.write_char(']'); + write!(self.wr, "]"); } fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut Encoder)) { if idx != 0 { - self.wr.write_char(','); + write!(self.wr, ","); } f(self) } fn emit_map(&mut self, _len: uint, f: &fn(&mut Encoder)) { - self.wr.write_char('{'); + write!(self.wr, r"\{"); f(self); - self.wr.write_char('}'); + write!(self.wr, r"\}"); } fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut Encoder)) { - if idx != 0 { self.wr.write_char(','); } + if idx != 0 { write!(self.wr, ",") } f(self) } fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut Encoder)) { - self.wr.write_char(':'); + write!(self.wr, ":"); f(self) } } @@ -243,12 +242,12 @@ impl serialize::Encoder for Encoder { /// Another encoder for JSON, but prints out human-readable JSON instead of /// compact data pub struct PrettyEncoder { - priv wr: @io::Writer, + priv wr: @mut io::Writer, priv indent: uint, } /// Creates a new encoder whose output will be written to the specified writer -pub fn PrettyEncoder(wr: @io::Writer) -> PrettyEncoder { +pub fn PrettyEncoder(wr: @mut io::Writer) -> PrettyEncoder { PrettyEncoder { wr: wr, indent: 0, @@ -256,7 +255,7 @@ pub fn PrettyEncoder(wr: @io::Writer) -> PrettyEncoder { } impl serialize::Encoder for PrettyEncoder { - fn emit_nil(&mut self) { self.wr.write_str("null") } + fn emit_nil(&mut self) { write!(self.wr, "null") } fn emit_uint(&mut self, v: uint) { self.emit_f64(v as f64); } fn emit_u64(&mut self, v: u64) { self.emit_f64(v as f64); } @@ -272,17 +271,19 @@ impl serialize::Encoder for PrettyEncoder { fn emit_bool(&mut self, v: bool) { if v { - self.wr.write_str("true"); + write!(self.wr, "true"); } else { - self.wr.write_str("false"); + write!(self.wr, "false"); } } - fn emit_f64(&mut self, v: f64) { self.wr.write_str(f64::to_str_digits(v, 6u)) } + fn emit_f64(&mut self, v: f64) { + write!(self.wr, "{}", f64::to_str_digits(v, 6u)) + } fn emit_f32(&mut self, v: f32) { self.emit_f64(v as f64); } fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } - fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)); } + fn emit_str(&mut self, v: &str) { write!(self.wr, "{}", escape_str(v)); } fn emit_enum(&mut self, _name: &str, f: &fn(&mut PrettyEncoder)) { f(self) @@ -294,19 +295,13 @@ impl serialize::Encoder for PrettyEncoder { cnt: uint, f: &fn(&mut PrettyEncoder)) { if cnt == 0 { - self.wr.write_str(escape_str(name)); + write!(self.wr, "{}", escape_str(name)); } else { - self.wr.write_char('['); self.indent += 2; - self.wr.write_char('\n'); - self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(",\n"); + write!(self.wr, "[\n{}{},\n", spaces(self.indent), escape_str(name)); f(self); - self.wr.write_char('\n'); self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char(']'); + write!(self.wr, "\n{}]", spaces(self.indent)); } } @@ -314,9 +309,9 @@ impl serialize::Encoder for PrettyEncoder { idx: uint, f: &fn(&mut PrettyEncoder)) { if idx != 0 { - self.wr.write_str(",\n"); + write!(self.wr, ",\n"); } - self.wr.write_str(spaces(self.indent)); + write!(self.wr, "{}", spaces(self.indent)); f(self) } @@ -341,15 +336,13 @@ impl serialize::Encoder for PrettyEncoder { len: uint, f: &fn(&mut PrettyEncoder)) { if len == 0 { - self.wr.write_str("{}"); + write!(self.wr, "\\{\\}"); } else { - self.wr.write_char('{'); + write!(self.wr, "\\{"); self.indent += 2; f(self); - self.wr.write_char('\n'); self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char('}'); + write!(self.wr, "\n{}\\}", spaces(self.indent)); } } @@ -358,13 +351,11 @@ impl serialize::Encoder for PrettyEncoder { idx: uint, f: &fn(&mut PrettyEncoder)) { if idx == 0 { - self.wr.write_char('\n'); + write!(self.wr, "\n"); } else { - self.wr.write_str(",\n"); + write!(self.wr, ",\n"); } - self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(": "); + write!(self.wr, "{}{}: ", spaces(self.indent), escape_str(name)); f(self); } @@ -393,54 +384,50 @@ impl serialize::Encoder for PrettyEncoder { fn emit_seq(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { if len == 0 { - self.wr.write_str("[]"); + write!(self.wr, "[]"); } else { - self.wr.write_char('['); + write!(self.wr, "["); self.indent += 2; f(self); - self.wr.write_char('\n'); self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char(']'); + write!(self.wr, "\n{}]", spaces(self.indent)); } } fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { if idx == 0 { - self.wr.write_char('\n'); + write!(self.wr, "\n"); } else { - self.wr.write_str(",\n"); + write!(self.wr, ",\n"); } - self.wr.write_str(spaces(self.indent)); + write!(self.wr, "{}", spaces(self.indent)); f(self) } fn emit_map(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { if len == 0 { - self.wr.write_str("{}"); + write!(self.wr, "\\{\\}"); } else { - self.wr.write_char('{'); + write!(self.wr, "\\{"); self.indent += 2; f(self); - self.wr.write_char('\n'); self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char('}'); + write!(self.wr, "\n{}\\}", spaces(self.indent)); } } fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { if idx == 0 { - self.wr.write_char('\n'); + write!(self.wr, "\n"); } else { - self.wr.write_str(",\n"); + write!(self.wr, ",\n"); } - self.wr.write_str(spaces(self.indent)); + write!(self.wr, "{}", spaces(self.indent)); f(self); } fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut PrettyEncoder)) { - self.wr.write_str(": "); + write!(self.wr, ": "); f(self); } } @@ -460,21 +447,23 @@ impl serialize::Encodable for Json { impl Json{ /// Encodes a json value into a io::writer. Uses a single line. - pub fn to_writer(&self, wr: @io::Writer) { + pub fn to_writer(&self, wr: @mut io::Writer) { let mut encoder = Encoder(wr); self.encode(&mut encoder) } /// Encodes a json value into a io::writer. /// Pretty-prints in a more readable format. - pub fn to_pretty_writer(&self, wr: @io::Writer) { + pub fn to_pretty_writer(&self, wr: @mut io::Writer) { let mut encoder = PrettyEncoder(wr); self.encode(&mut encoder) } /// Encodes a json value into a string pub fn to_pretty_str(&self) -> ~str { - io::with_str_writer(|wr| self.to_pretty_writer(wr)) + let s = @mut MemWriter::new(); + self.to_pretty_writer(s as @mut io::Writer); + str::from_utf8(s.inner_ref().as_slice()) } } @@ -853,9 +842,9 @@ impl> Parser { } } -/// Decodes a json value from an @io::Reader -pub fn from_reader(rdr: @io::Reader) -> Result { - let s = str::from_utf8(rdr.read_whole_stream()); +/// Decodes a json value from an `&mut io::Reader` +pub fn from_reader(mut rdr: &mut io::Reader) -> Result { + let s = str::from_utf8(rdr.read_to_end()); let mut parser = Parser(~s.iter()); parser.parse() } @@ -1306,7 +1295,9 @@ impl ToJson for Option { impl to_str::ToStr for Json { /// Encodes a json value into a string fn to_str(&self) -> ~str { - io::with_str_writer(|wr| self.to_writer(wr)) + let s = @mut MemWriter::new(); + self.to_writer(s as @mut io::Writer); + str::from_utf8(s.inner_ref().as_slice()) } } @@ -1321,8 +1312,7 @@ mod tests { use super::*; - use std::io; - + use std::rt::io; use serialize::Decodable; use treemap::TreeMap; @@ -1493,18 +1483,28 @@ mod tests { assert_eq!(a.clone(), from_str(a.to_pretty_str()).unwrap()); } + fn with_str_writer(f: &fn(@mut io::Writer)) -> ~str { + use std::rt::io::mem::MemWriter; + use std::rt::io::Decorator; + use std::str; + + let m = @mut MemWriter::new(); + f(m as @mut io::Writer); + str::from_utf8(*m.inner_ref()) + } + #[test] fn test_write_enum() { let animal = Dog; assert_eq!( - do io::with_str_writer |wr| { + do with_str_writer |wr| { let mut encoder = Encoder(wr); animal.encode(&mut encoder); }, ~"\"Dog\"" ); assert_eq!( - do io::with_str_writer |wr| { + do with_str_writer |wr| { let mut encoder = PrettyEncoder(wr); animal.encode(&mut encoder); }, @@ -1513,14 +1513,14 @@ mod tests { let animal = Frog(~"Henry", 349); assert_eq!( - do io::with_str_writer |wr| { + do with_str_writer |wr| { let mut encoder = Encoder(wr); animal.encode(&mut encoder); }, ~"{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}" ); assert_eq!( - do io::with_str_writer |wr| { + do with_str_writer |wr| { let mut encoder = PrettyEncoder(wr); animal.encode(&mut encoder); }, @@ -1536,14 +1536,14 @@ mod tests { #[test] fn test_write_some() { let value = Some(~"jodhpurs"); - let s = do io::with_str_writer |wr| { + let s = do with_str_writer |wr| { let mut encoder = Encoder(wr); value.encode(&mut encoder); }; assert_eq!(s, ~"\"jodhpurs\""); let value = Some(~"jodhpurs"); - let s = do io::with_str_writer |wr| { + let s = do with_str_writer |wr| { let mut encoder = PrettyEncoder(wr); value.encode(&mut encoder); }; @@ -1553,13 +1553,13 @@ mod tests { #[test] fn test_write_none() { let value: Option<~str> = None; - let s = do io::with_str_writer |wr| { + let s = do with_str_writer |wr| { let mut encoder = Encoder(wr); value.encode(&mut encoder); }; assert_eq!(s, ~"null"); - let s = do io::with_str_writer |wr| { + let s = do with_str_writer |wr| { let mut encoder = Encoder(wr); value.encode(&mut encoder); }; diff --git a/src/libextra/semver.rs b/src/libextra/semver.rs index 02c35000ce3a4..0ab38cdb5df83 100644 --- a/src/libextra/semver.rs +++ b/src/libextra/semver.rs @@ -30,8 +30,6 @@ use std::char; use std::cmp; -use std::io::{ReaderUtil}; -use std::io; use std::option::{Option, Some, None}; use std::to_str::ToStr; @@ -147,14 +145,19 @@ condition! { bad_parse: () -> (); } -fn take_nonempty_prefix(rdr: @io::Reader, - ch: char, - pred: &fn(char) -> bool) -> (~str, char) { +fn take_nonempty_prefix>(rdr: &mut T, + pred: &fn(char) -> bool) -> (~str, Option) { let mut buf = ~""; - let mut ch = ch; - while pred(ch) { - buf.push_char(ch); - ch = rdr.read_char(); + let mut ch = rdr.next(); + loop { + match ch { + None => break, + Some(c) if !pred(c) => break, + Some(c) => { + buf.push_char(c); + ch = rdr.next(); + } + } } if buf.is_empty() { bad_parse::cond.raise(()) @@ -163,16 +166,16 @@ fn take_nonempty_prefix(rdr: @io::Reader, (buf, ch) } -fn take_num(rdr: @io::Reader, ch: char) -> (uint, char) { - let (s, ch) = take_nonempty_prefix(rdr, ch, char::is_digit); +fn take_num>(rdr: &mut T) -> (uint, Option) { + let (s, ch) = take_nonempty_prefix(rdr, char::is_digit); match from_str::(s) { None => { bad_parse::cond.raise(()); (0, ch) }, Some(i) => (i, ch) } } -fn take_ident(rdr: @io::Reader, ch: char) -> (Identifier, char) { - let (s,ch) = take_nonempty_prefix(rdr, ch, char::is_alphanumeric); +fn take_ident>(rdr: &mut T) -> (Identifier, Option) { + let (s,ch) = take_nonempty_prefix(rdr, char::is_alphanumeric); if s.iter().all(char::is_digit) { match from_str::(s) { None => { bad_parse::cond.raise(()); (Numeric(0), ch) }, @@ -183,38 +186,38 @@ fn take_ident(rdr: @io::Reader, ch: char) -> (Identifier, char) { } } -fn expect(ch: char, c: char) { - if ch != c { +fn expect(ch: Option, c: char) { + if ch != Some(c) { bad_parse::cond.raise(()) } } -fn parse_reader(rdr: @io::Reader) -> Version { - let (major, ch) = take_num(rdr, rdr.read_char()); +fn parse_iter>(rdr: &mut T) -> Version { + let (major, ch) = take_num(rdr); expect(ch, '.'); - let (minor, ch) = take_num(rdr, rdr.read_char()); + let (minor, ch) = take_num(rdr); expect(ch, '.'); - let (patch, ch) = take_num(rdr, rdr.read_char()); + let (patch, ch) = take_num(rdr); let mut pre = ~[]; let mut build = ~[]; let mut ch = ch; - if ch == '-' { + if ch == Some('-') { loop { - let (id, c) = take_ident(rdr, rdr.read_char()); + let (id, c) = take_ident(rdr); pre.push(id); ch = c; - if ch != '.' { break; } + if ch != Some('.') { break; } } } - if ch == '+' { + if ch == Some('+') { loop { - let (id, c) = take_ident(rdr, rdr.read_char()); + let (id, c) = take_ident(rdr); build.push(id); ch = c; - if ch != '.' { break; } + if ch != Some('.') { break; } } } @@ -236,13 +239,11 @@ pub fn parse(s: &str) -> Option { let s = s.trim(); let mut bad = false; do bad_parse::cond.trap(|_| { debug!("bad"); bad = true }).inside { - do io::with_str_reader(s) |rdr| { - let v = parse_reader(rdr); - if bad || v.to_str() != s.to_owned() { - None - } else { - Some(v) - } + let v = parse_iter(&mut s.iter()); + if bad || v.to_str() != s.to_owned() { + None + } else { + Some(v) } } } diff --git a/src/libextra/stats.rs b/src/libextra/stats.rs index 40f99716ca796..497145ca7c992 100644 --- a/src/libextra/stats.rs +++ b/src/libextra/stats.rs @@ -13,7 +13,7 @@ use sort; use std::cmp; use std::hashmap; -use std::io; +use std::rt::io; use std::num; // NB: this can probably be rewritten in terms of num::Num @@ -273,14 +273,14 @@ pub fn winsorize(samples: &mut [f64], pct: f64) { } /// Render writes the min, max and quartiles of the provided `Summary` to the provided `Writer`. -pub fn write_5_number_summary(w: @io::Writer, s: &Summary) { +pub fn write_5_number_summary(w: &mut io::Writer, s: &Summary) { let (q1,q2,q3) = s.quartiles; - w.write_str(format!("(min={}, q1={}, med={}, q3={}, max={})", + write!(w, "(min={}, q1={}, med={}, q3={}, max={})", s.min, q1, q2, q3, - s.max)); + s.max); } /// Render a boxplot to the provided writer. The boxplot shows the min, max and quartiles of the @@ -295,7 +295,7 @@ pub fn write_5_number_summary(w: @io::Writer, s: &Summary) { /// 10 | [--****#******----------] | 40 /// ~~~~ -pub fn write_boxplot(w: @io::Writer, s: &Summary, width_hint: uint) { +pub fn write_boxplot(w: &mut io::Writer, s: &Summary, width_hint: uint) { let (q1,q2,q3) = s.quartiles; @@ -325,52 +325,48 @@ pub fn write_boxplot(w: @io::Writer, s: &Summary, width_hint: uint) { let range_width = width_hint - overhead_width;; let char_step = range / (range_width as f64); - w.write_str(lostr); - w.write_char(' '); - w.write_char('|'); + write!(w, "{} |", lostr); let mut c = 0; let mut v = lo; while c < range_width && v < s.min { - w.write_char(' '); + write!(w, " "); v += char_step; c += 1; } - w.write_char('['); + write!(w, "["); c += 1; while c < range_width && v < q1 { - w.write_char('-'); + write!(w, "-"); v += char_step; c += 1; } while c < range_width && v < q2 { - w.write_char('*'); + write!(w, "*"); v += char_step; c += 1; } - w.write_char('#'); + write!(w, r"\#"); c += 1; while c < range_width && v < q3 { - w.write_char('*'); + write!(w, "*"); v += char_step; c += 1; } while c < range_width && v < s.max { - w.write_char('-'); + write!(w, "-"); v += char_step; c += 1; } - w.write_char(']'); + write!(w, "]"); while c < range_width { - w.write_char(' '); + write!(w, " "); v += char_step; c += 1; } - w.write_char('|'); - w.write_char(' '); - w.write_str(histr); + write!(w, "| {}", histr); } /// Returns a HashMap with the number of occurrences of every element in the @@ -392,18 +388,20 @@ mod tests { use stats::Summary; use stats::write_5_number_summary; use stats::write_boxplot; - use std::io; + use std::rt::io; + use std::str; fn check(samples: &[f64], summ: &Summary) { let summ2 = Summary::new(samples); - let w = io::stdout(); - w.write_char('\n'); + let mut w = io::stdout(); + let w = &mut w as &mut io::Writer; + write!(w, "\n"); write_5_number_summary(w, &summ2); - w.write_char('\n'); + write!(w, "\n"); write_boxplot(w, &summ2, 50); - w.write_char('\n'); + write!(w, "\n"); assert_eq!(summ.sum, summ2.sum); assert_eq!(summ.min, summ2.min); @@ -944,10 +942,11 @@ mod tests { #[test] fn test_boxplot_nonpositive() { fn t(s: &Summary, expected: ~str) { - let out = do io::with_str_writer |w| { - write_boxplot(w, s, 30) - }; - + use std::rt::io::mem::MemWriter; + use std::rt::io::Decorator; + let mut m = MemWriter::new(); + write_boxplot(&mut m as &mut io::Writer, s, 30); + let out = str::from_utf8_owned(m.inner()); assert_eq!(out, expected); } diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 878224890e619..22ce833ea24d9 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -13,7 +13,7 @@ #[allow(missing_doc)]; -use std::io; +use std::rt::io; #[cfg(not(target_os = "win32"))] use std::os; #[cfg(not(target_os = "win32"))] use terminfo::*; @@ -96,19 +96,19 @@ fn cap_for_attr(attr: attr::Attr) -> &'static str { #[cfg(not(target_os = "win32"))] pub struct Terminal { priv num_colors: u16, - priv out: @io::Writer, + priv out: @mut io::Writer, priv ti: ~TermInfo } #[cfg(target_os = "win32")] pub struct Terminal { priv num_colors: u16, - priv out: @io::Writer, + priv out: @mut io::Writer, } #[cfg(not(target_os = "win32"))] impl Terminal { - pub fn new(out: @io::Writer) -> Result { + pub fn new(out: @mut io::Writer) -> Result { let term = os::getenv("TERM"); if term.is_none() { return Err(~"TERM environment variable undefined"); @@ -243,7 +243,7 @@ impl Terminal { #[cfg(target_os = "win32")] impl Terminal { - pub fn new(out: @io::Writer) -> Result { + pub fn new(out: @mut io::Writer) -> Result { return Ok(Terminal {out: out, num_colors: 0}); } diff --git a/src/libextra/terminfo/parser/compiled.rs b/src/libextra/terminfo/parser/compiled.rs index bc24c8a6e3063..0020f432114dd 100644 --- a/src/libextra/terminfo/parser/compiled.rs +++ b/src/libextra/terminfo/parser/compiled.rs @@ -14,8 +14,9 @@ use std::{vec, str}; -use std::io::Reader; use std::hashmap::HashMap; +use std::rt::io; +use std::rt::io::extensions::{ReaderByteConversions, ReaderUtil}; use super::super::TermInfo; // These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable. @@ -160,7 +161,8 @@ pub static stringnames: &'static[&'static str] = &'static[ "cbt", "_", "cr", "cs "box1"]; /// Parse a compiled terminfo entry, using long capability names if `longnames` is true -pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { +pub fn parse(mut file: &mut io::Reader, + longnames: bool) -> Result<~TermInfo, ~str> { let bnames; let snames; let nnames; @@ -176,17 +178,17 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { } // Check magic number - let magic = file.read_le_u16(); + let magic = file.read_le_u16_(); if (magic != 0x011A) { return Err(format!("invalid magic number: expected {:x} but found {:x}", 0x011A, magic as uint)); } - let names_bytes = file.read_le_i16() as int; - let bools_bytes = file.read_le_i16() as int; - let numbers_count = file.read_le_i16() as int; - let string_offsets_count = file.read_le_i16() as int; - let string_table_bytes = file.read_le_i16() as int; + let names_bytes = file.read_le_i16_() as int; + let bools_bytes = file.read_le_i16_() as int; + let numbers_count = file.read_le_i16_() as int; + let string_offsets_count = file.read_le_i16_() as int; + let string_table_bytes = file.read_le_i16_() as int; assert!(names_bytes > 0); @@ -224,7 +226,7 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { let mut bools_map = HashMap::new(); if bools_bytes != 0 { for i in range(0, bools_bytes) { - let b = file.read_byte(); + let b = file.read_byte().unwrap(); if b < 0 { error!("EOF reading bools after {} entries", i); return Err(~"error: expected more bools but hit EOF"); @@ -245,7 +247,7 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { let mut numbers_map = HashMap::new(); if numbers_count != 0 { for i in range(0, numbers_count) { - let n = file.read_le_u16(); + let n = file.read_le_u16_(); if n != 0xFFFF { debug!("{}\\#{}", nnames[i], n); numbers_map.insert(nnames[i].to_owned(), n); @@ -260,7 +262,7 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { if string_offsets_count != 0 { let mut string_offsets = vec::with_capacity(10); for _ in range(0, string_offsets_count) { - string_offsets.push(file.read_le_u16()); + string_offsets.push(file.read_le_u16_()); } debug!("offsets: {:?}", string_offsets); diff --git a/src/libextra/terminfo/searcher.rs b/src/libextra/terminfo/searcher.rs index ea7d20e096df4..8dff53f14a159 100644 --- a/src/libextra/terminfo/searcher.rs +++ b/src/libextra/terminfo/searcher.rs @@ -13,7 +13,8 @@ use std::{os, str}; use std::os::getenv; -use std::io::{file_reader, Reader}; +use std::rt::io; +use std::rt::io::file::FileInfo; /// Return path to database entry for `term` pub fn get_dbpath_for_term(term: &str) -> Option<~Path> { @@ -73,9 +74,9 @@ pub fn get_dbpath_for_term(term: &str) -> Option<~Path> { } /// Return open file for `term` -pub fn open(term: &str) -> Result<@Reader, ~str> { +pub fn open(term: &str) -> Result<@mut io::Reader, ~str> { match get_dbpath_for_term(term) { - Some(x) => file_reader(x), + Some(x) => Ok(@mut x.open_reader(io::Open).unwrap() as @mut io::Reader), None => Err(format!("could not find terminfo entry for {}", term)) } } diff --git a/src/libextra/test.rs b/src/libextra/test.rs index f95c7aa22b7f0..457f7868e237a 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -30,8 +30,8 @@ use treemap::TreeMap; use std::clone::Clone; use std::comm::{stream, SharedChan, GenericPort, GenericChan}; -use std::io; -use std::result; +use std::rt::io; +use std::rt::io::file::FileInfo; use std::task; use std::to_str::ToStr; use std::f64; @@ -336,8 +336,8 @@ pub enum TestResult { } struct ConsoleTestState { - out: @io::Writer, - log_out: Option<@io::Writer>, + out: @mut io::Writer, + log_out: Option<@mut io::Writer>, term: Option, use_color: bool, total: uint, @@ -353,17 +353,13 @@ struct ConsoleTestState { impl ConsoleTestState { pub fn new(opts: &TestOpts) -> ConsoleTestState { let log_out = match opts.logfile { - Some(ref path) => match io::file_writer(path, - [io::Create, - io::Truncate]) { - result::Ok(w) => Some(w), - result::Err(ref s) => { - fail!("can't open output file: {}", *s) - } + Some(ref path) => { + let out = path.open_writer(io::CreateOrTruncate); + Some(@mut out as @mut io::Writer) }, None => None }; - let out = io::stdout(); + let out = @mut io::stdio::stdout() as @mut io::Writer; let term = match term::Terminal::new(out) { Err(_) => None, Ok(t) => Some(t) @@ -424,12 +420,12 @@ impl ConsoleTestState { word: &str, color: term::color::Color) { match self.term { - None => self.out.write_str(word), + None => self.out.write(word.as_bytes()), Some(ref t) => { if self.use_color { t.fg(color); } - self.out.write_str(word); + self.out.write(word.as_bytes()); if self.use_color { t.reset(); } @@ -440,12 +436,12 @@ impl ConsoleTestState { pub fn write_run_start(&mut self, len: uint) { self.total = len; let noun = if len != 1 { &"tests" } else { &"test" }; - self.out.write_line(format!("\nrunning {} {}", len, noun)); + write!(self.out, "\nrunning {} {}\n", len, noun); } pub fn write_test_start(&self, test: &TestDesc, align: NamePadding) { let name = test.padded_name(self.max_name_len, align); - self.out.write_str(format!("test {} ... ", name)); + write!(self.out, "test {} ... ", name); } pub fn write_result(&self, result: &TestResult) { @@ -455,41 +451,40 @@ impl ConsoleTestState { TrIgnored => self.write_ignored(), TrMetrics(ref mm) => { self.write_metric(); - self.out.write_str(": " + fmt_metrics(mm)); + write!(self.out, ": {}", fmt_metrics(mm)); } TrBench(ref bs) => { self.write_bench(); - self.out.write_str(": " + fmt_bench_samples(bs)) + write!(self.out, ": {}", fmt_bench_samples(bs)); } } - self.out.write_str(&"\n"); + write!(self.out, "\n"); } pub fn write_log(&self, test: &TestDesc, result: &TestResult) { match self.log_out { None => (), Some(out) => { - out.write_line(format!("{} {}", - match *result { + write!(out, "{} {}",match *result { TrOk => ~"ok", TrFailed => ~"failed", TrIgnored => ~"ignored", TrMetrics(ref mm) => fmt_metrics(mm), TrBench(ref bs) => fmt_bench_samples(bs) - }, test.name.to_str())); + }, test.name.to_str()); } } } pub fn write_failures(&self) { - self.out.write_line("\nfailures:"); + write!(self.out, "\nfailures:\n"); let mut failures = ~[]; for f in self.failures.iter() { failures.push(f.name.to_str()); } sort::tim_sort(failures); for name in failures.iter() { - self.out.write_line(format!(" {}", name.to_str())); + writeln!(self.out, " {}", name.to_str()); } } @@ -506,36 +501,34 @@ impl ConsoleTestState { MetricAdded => { added += 1; self.write_added(); - self.out.write_line(format!(": {}", *k)); + writeln!(self.out, ": {}", *k); } MetricRemoved => { removed += 1; self.write_removed(); - self.out.write_line(format!(": {}", *k)); + writeln!(self.out, ": {}", *k); } Improvement(pct) => { improved += 1; - self.out.write_str(*k); - self.out.write_str(": "); + write!(self.out, "{}: ", *k); self.write_improved(); - self.out.write_line(format!(" by {:.2f}%", pct as f64)) + writeln!(self.out, " by {:.2f}%", pct as f64); } Regression(pct) => { regressed += 1; - self.out.write_str(*k); - self.out.write_str(": "); + write!(self.out, "{}: ", *k); self.write_regressed(); - self.out.write_line(format!(" by {:.2f}%", pct as f64)) + writeln!(self.out, " by {:.2f}%", pct as f64); } } } - self.out.write_line(format!("result of ratchet: {} matrics added, {} removed, \ - {} improved, {} regressed, {} noise", - added, removed, improved, regressed, noise)); + writeln!(self.out, "result of ratchet: {} matrics added, {} removed, \ + {} improved, {} regressed, {} noise", + added, removed, improved, regressed, noise); if regressed == 0 { - self.out.write_line("updated ratchet file") + writeln!(self.out, "updated ratchet file"); } else { - self.out.write_line("left ratchet file untouched") + writeln!(self.out, "left ratchet file untouched"); } } @@ -547,12 +540,12 @@ impl ConsoleTestState { let ratchet_success = match *ratchet_metrics { None => true, Some(ref pth) => { - self.out.write_str(format!("\nusing metrics ratchet: {}\n", pth.display())); + write!(self.out, "\nusing metrics ratcher: {}\n", pth.display()); match ratchet_pct { None => (), Some(pct) => - self.out.write_str(format!("with noise-tolerance forced to: {}%%\n", - pct as f64)) + writeln!(self.out, "with noise-tolerance forced to: {}%", + pct) } let (diff, ok) = self.metrics.ratchet(pth, ratchet_pct); self.write_metric_diff(&diff); @@ -567,15 +560,15 @@ impl ConsoleTestState { let success = ratchet_success && test_success; - self.out.write_str("\ntest result: "); + write!(self.out, "\ntest result: "); if success { // There's no parallelism at this point so it's safe to use color self.write_ok(); } else { self.write_failed(); } - self.out.write_str(format!(". {} passed; {} failed; {} ignored; {} measured\n\n", - self.passed, self.failed, self.ignored, self.measured)); + write!(self.out, ". {} passed; {} failed; {} ignored; {} measured\n\n", + self.passed, self.failed, self.ignored, self.measured); return success; } } @@ -659,7 +652,7 @@ pub fn run_tests_console(opts: &TestOpts, None => (), Some(ref pth) => { st.metrics.save(pth); - st.out.write_str(format!("\nmetrics saved to: {}", pth.display())); + write!(st.out, "\nmetrics saved to: {}", pth.display()); } } return st.write_run_finish(&opts.ratchet_metrics, opts.ratchet_noise_percent); @@ -667,39 +660,43 @@ pub fn run_tests_console(opts: &TestOpts, #[test] fn should_sort_failures_before_printing_them() { + use std::rt::io; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; + use std::str; fn dummy() {} - let s = do io::with_str_writer |wr| { - let test_a = TestDesc { - name: StaticTestName("a"), - ignore: false, - should_fail: false - }; - - let test_b = TestDesc { - name: StaticTestName("b"), - ignore: false, - should_fail: false - }; + let m = @mut MemWriter::new(); + let test_a = TestDesc { + name: StaticTestName("a"), + ignore: false, + should_fail: false + }; - let st = @ConsoleTestState { - out: wr, - log_out: None, - term: None, - use_color: false, - total: 0u, - passed: 0u, - failed: 0u, - ignored: 0u, - measured: 0u, - metrics: MetricMap::new(), - failures: ~[test_b, test_a], - max_name_len: 0u, - }; + let test_b = TestDesc { + name: StaticTestName("b"), + ignore: false, + should_fail: false + }; - st.write_failures(); + let st = @ConsoleTestState { + out: m as @mut io::Writer, + log_out: None, + term: None, + use_color: false, + total: 0u, + passed: 0u, + failed: 0u, + ignored: 0u, + measured: 0u, + max_name_len: 10u, + metrics: MetricMap::new(), + failures: ~[test_b, test_a] }; + st.write_failures(); + let s = str::from_utf8(*m.inner_ref()); + let apos = s.find_str("a").unwrap(); let bpos = s.find_str("b").unwrap(); assert!(apos < bpos); @@ -939,15 +936,15 @@ impl MetricMap { /// Load MetricDiff from a file. pub fn load(p: &Path) -> MetricMap { assert!(os::path_exists(p)); - let f = io::file_reader(p).unwrap(); + let f = @mut p.open_reader(io::Open) as @mut io::Reader; let mut decoder = json::Decoder(json::from_reader(f).unwrap()); MetricMap(Decodable::decode(&mut decoder)) } /// Write MetricDiff to a file. pub fn save(&self, p: &Path) { - let f = io::file_writer(p, [io::Create, io::Truncate]).unwrap(); - self.to_json().to_pretty_writer(f); + let f = @mut p.open_writer(io::CreateOrTruncate); + self.to_json().to_pretty_writer(f as @mut io::Writer); } /// Compare against another MetricMap. Optionally compare all diff --git a/src/libextra/time.rs b/src/libextra/time.rs index f675c6f2392c7..2950f02ad19dd 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -10,7 +10,8 @@ #[allow(missing_doc)]; -use std::io; +use std::rt::io::Reader; +use std::rt::io::mem::BufReader; use std::num; use std::str; @@ -666,61 +667,69 @@ pub fn strptime(s: &str, format: &str) -> Result { } } - do io::with_str_reader(format) |rdr| { - let mut tm = Tm { - tm_sec: 0_i32, - tm_min: 0_i32, - tm_hour: 0_i32, - tm_mday: 0_i32, - tm_mon: 0_i32, - tm_year: 0_i32, - tm_wday: 0_i32, - tm_yday: 0_i32, - tm_isdst: 0_i32, - tm_gmtoff: 0_i32, - tm_zone: ~"", - tm_nsec: 0_i32, - }; - let mut pos = 0u; - let len = s.len(); - let mut result = Err(~"Invalid time"); + let mut rdr = BufReader::new(format.as_bytes()); + let mut tm = Tm { + tm_sec: 0_i32, + tm_min: 0_i32, + tm_hour: 0_i32, + tm_mday: 0_i32, + tm_mon: 0_i32, + tm_year: 0_i32, + tm_wday: 0_i32, + tm_yday: 0_i32, + tm_isdst: 0_i32, + tm_gmtoff: 0_i32, + tm_zone: ~"", + tm_nsec: 0_i32, + }; + let mut pos = 0u; + let len = s.len(); + let mut result = Err(~"Invalid time"); - while !rdr.eof() && pos < len { - let range = s.char_range_at(pos); - let ch = range.ch; - let next = range.next; - - match rdr.read_char() { - '%' => { - match parse_type(s, pos, rdr.read_char(), &mut tm) { - Ok(next) => pos = next, - Err(e) => { result = Err(e); break; } - } - }, - c => { - if c != ch { break } - pos = next; + while pos < len { + let range = s.char_range_at(pos); + let ch = range.ch; + let next = range.next; + + let mut buf = [0]; + let c = match rdr.read(buf) { + Some(*) => buf[0] as u8 as char, + None => break + }; + match c { + '%' => { + let ch = match rdr.read(buf) { + Some(*) => buf[0] as u8 as char, + None => break + }; + match parse_type(s, pos, ch, &mut tm) { + Ok(next) => pos = next, + Err(e) => { result = Err(e); break; } } + }, + c => { + if c != ch { break } + pos = next; } } - - if pos == len && rdr.eof() { - Ok(Tm { - tm_sec: tm.tm_sec, - tm_min: tm.tm_min, - tm_hour: tm.tm_hour, - tm_mday: tm.tm_mday, - tm_mon: tm.tm_mon, - tm_year: tm.tm_year, - tm_wday: tm.tm_wday, - tm_yday: tm.tm_yday, - tm_isdst: tm.tm_isdst, - tm_gmtoff: tm.tm_gmtoff, - tm_zone: tm.tm_zone.clone(), - tm_nsec: tm.tm_nsec, - }) - } else { result } } + + if pos == len && rdr.eof() { + Ok(Tm { + tm_sec: tm.tm_sec, + tm_min: tm.tm_min, + tm_hour: tm.tm_hour, + tm_mday: tm.tm_mday, + tm_mon: tm.tm_mon, + tm_year: tm.tm_year, + tm_wday: tm.tm_wday, + tm_yday: tm.tm_yday, + tm_isdst: tm.tm_isdst, + tm_gmtoff: tm.tm_gmtoff, + tm_zone: tm.tm_zone.clone(), + tm_nsec: tm.tm_nsec, + }) + } else { result } } /// Formats the time according to the format string. @@ -929,18 +938,26 @@ pub fn strftime(format: &str, tm: &Tm) -> ~str { } } - let mut buf = ~""; + let mut buf = ~[]; - do io::with_str_reader(format) |rdr| { - while !rdr.eof() { - match rdr.read_char() { - '%' => buf.push_str(parse_type(rdr.read_char(), tm)), - ch => buf.push_char(ch) + let mut rdr = BufReader::new(format.as_bytes()); + loop { + let mut b = [0]; + let ch = match rdr.read(b) { + Some(*) => b[0], + None => break, + }; + match ch as char { + '%' => { + rdr.read(b); + let s = parse_type(b[0] as char, tm); + buf.push_all(s.as_bytes()); } + ch => buf.push(ch as u8) } } - buf + str::from_utf8_owned(buf) } #[cfg(test)] diff --git a/src/libextra/url.rs b/src/libextra/url.rs index e836d3b52709c..d268b106e5cb6 100644 --- a/src/libextra/url.rs +++ b/src/libextra/url.rs @@ -12,10 +12,9 @@ #[allow(missing_doc)]; - +use std::rt::io::{Reader, Seek}; +use std::rt::io::mem::BufReader; use std::cmp::Eq; -use std::io::{Reader, ReaderUtil}; -use std::io; use std::hashmap::HashMap; use std::to_bytes; use std::uint; @@ -68,42 +67,46 @@ impl UserInfo { } fn encode_inner(s: &str, full_url: bool) -> ~str { - do io::with_str_reader(s) |rdr| { - let mut out = ~""; - - while !rdr.eof() { - let ch = rdr.read_byte() as u8 as char; - match ch { - // unreserved: - 'A' .. 'Z' | - 'a' .. 'z' | - '0' .. '9' | - '-' | '.' | '_' | '~' => { - out.push_char(ch); - } - _ => { - if full_url { - match ch { - // gen-delims: - ':' | '/' | '?' | '#' | '[' | ']' | '@' | - - // sub-delims: - '!' | '$' | '&' | '"' | '(' | ')' | '*' | - '+' | ',' | ';' | '=' => { - out.push_char(ch); - } - - _ => out.push_str(format!("%{:X}", ch as uint)) - } - } else { - out.push_str(format!("%{:X}", ch as uint)); + let mut rdr = BufReader::new(s.as_bytes()); + let mut out = ~""; + + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + None => break, + Some(*) => buf[0] as char, + }; + + match ch { + // unreserved: + 'A' .. 'Z' | + 'a' .. 'z' | + '0' .. '9' | + '-' | '.' | '_' | '~' => { + out.push_char(ch); + } + _ => { + if full_url { + match ch { + // gen-delims: + ':' | '/' | '?' | '#' | '[' | ']' | '@' | + + // sub-delims: + '!' | '$' | '&' | '"' | '(' | ')' | '*' | + '+' | ',' | ';' | '=' => { + out.push_char(ch); + } + + _ => out.push_str(format!("%{:X}", ch as uint)) } - } + } else { + out.push_str(format!("%{:X}", ch as uint)); } + } } - - out } + + out } /** @@ -128,41 +131,49 @@ pub fn encode_component(s: &str) -> ~str { } fn decode_inner(s: &str, full_url: bool) -> ~str { - do io::with_str_reader(s) |rdr| { - let mut out = ~""; - - while !rdr.eof() { - match rdr.read_char() { - '%' => { - let bytes = rdr.read_bytes(2u); - let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8 as char; - - if full_url { - // Only decode some characters: - match ch { - // gen-delims: - ':' | '/' | '?' | '#' | '[' | ']' | '@' | - - // sub-delims: - '!' | '$' | '&' | '"' | '(' | ')' | '*' | - '+' | ',' | ';' | '=' => { - out.push_char('%'); - out.push_char(bytes[0u] as char); - out.push_char(bytes[1u] as char); - } - - ch => out.push_char(ch) - } - } else { - out.push_char(ch); + let mut rdr = BufReader::new(s.as_bytes()); + let mut out = ~""; + + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + None => break, + Some(*) => buf[0] as char + }; + match ch { + '%' => { + let mut bytes = [0, 0]; + match rdr.read(bytes) { + Some(2) => {} + _ => fail!() // XXX: malformed url? + } + let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8 as char; + + if full_url { + // Only decode some characters: + match ch { + // gen-delims: + ':' | '/' | '?' | '#' | '[' | ']' | '@' | + + // sub-delims: + '!' | '$' | '&' | '"' | '(' | ')' | '*' | + '+' | ',' | ';' | '=' => { + out.push_char('%'); + out.push_char(bytes[0u] as char); + out.push_char(bytes[1u] as char); + } + + ch => out.push_char(ch) } - } - ch => out.push_char(ch) + } else { + out.push_char(ch); } + } + ch => out.push_char(ch) } - - out } + + out } /** @@ -182,22 +193,25 @@ pub fn decode_component(s: &str) -> ~str { } fn encode_plus(s: &str) -> ~str { - do io::with_str_reader(s) |rdr| { - let mut out = ~""; - - while !rdr.eof() { - let ch = rdr.read_byte() as u8 as char; - match ch { - 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '-' => { - out.push_char(ch); - } - ' ' => out.push_char('+'), - _ => out.push_str(format!("%{:X}", ch as uint)) - } - } + let mut rdr = BufReader::new(s.as_bytes()); + let mut out = ~""; - out + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + Some(*) => buf[0] as char, + None => break, + }; + match ch { + 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '-' => { + out.push_char(ch); + } + ' ' => out.push_char('+'), + _ => out.push_str(format!("%{:X}", ch as uint)) + } } + + out } /** @@ -230,61 +244,69 @@ pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str { * type into a hashmap. */ pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> { - do io::with_bytes_reader(s) |rdr| { - let mut m = HashMap::new(); - let mut key = ~""; - let mut value = ~""; - let mut parsing_key = true; - - while !rdr.eof() { - match rdr.read_char() { - '&' | ';' => { - if key != ~"" && value != ~"" { - let mut values = match m.pop(&key) { - Some(values) => values, - None => ~[], - }; - - values.push(value); - m.insert(key, values); - } + let mut rdr = BufReader::new(s); + let mut m = HashMap::new(); + let mut key = ~""; + let mut value = ~""; + let mut parsing_key = true; + + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + Some(*) => buf[0] as char, + None => break, + }; + match ch { + '&' | ';' => { + if key != ~"" && value != ~"" { + let mut values = match m.pop(&key) { + Some(values) => values, + None => ~[], + }; - parsing_key = true; - key = ~""; - value = ~""; + values.push(value); + m.insert(key, values); } - '=' => parsing_key = false, - ch => { - let ch = match ch { - '%' => { - let bytes = rdr.read_bytes(2u); - uint::parse_bytes(bytes, 16u).unwrap() as u8 as char - } - '+' => ' ', - ch => ch - }; - if parsing_key { - key.push_char(ch) - } else { - value.push_char(ch) + parsing_key = true; + key = ~""; + value = ~""; + } + '=' => parsing_key = false, + ch => { + let ch = match ch { + '%' => { + let mut bytes = [0, 0]; + match rdr.read(bytes) { + Some(2) => {} + _ => fail!() // XXX: malformed? + } + uint::parse_bytes(bytes, 16u).unwrap() as u8 as char } + '+' => ' ', + ch => ch + }; + + if parsing_key { + key.push_char(ch) + } else { + value.push_char(ch) } } } + } - if key != ~"" && value != ~"" { - let mut values = match m.pop(&key) { - Some(values) => values, - None => ~[], - }; - - values.push(value); - m.insert(key, values); - } + if key != ~"" && value != ~"" { + let mut values = match m.pop(&key) { + Some(values) => values, + None => ~[], + }; - m + values.push(value); + m.insert(key, values); } + + m } @@ -292,16 +314,18 @@ fn split_char_first(s: &str, c: char) -> (~str, ~str) { let len = s.len(); let mut index = len; let mut mat = 0; - do io::with_str_reader(s) |rdr| { - let mut ch; - while !rdr.eof() { - ch = rdr.read_byte() as u8 as char; - if ch == c { - // found a match, adjust markers - index = rdr.tell()-1; - mat = 1; - break; - } + let mut rdr = BufReader::new(s.as_bytes()); + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + Some(*) => buf[0] as char, + None => break, + }; + if ch == c { + // found a match, adjust markers + index = (rdr.tell() as uint) - 1; + mat = 1; + break; } } if index+mat == len { diff --git a/src/libextra/uuid.rs b/src/libextra/uuid.rs index 345cf64f1281a..b94b74a696cc2 100644 --- a/src/libextra/uuid.rs +++ b/src/libextra/uuid.rs @@ -522,6 +522,8 @@ mod test { use std::str; use std::rand; use std::num::Zero; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; #[test] fn test_new_nil() { @@ -795,10 +797,10 @@ mod test { use serialize::{Encodable, Decodable}; let u = Uuid::new_v4(); - let bytes = do std::io::with_bytes_writer |wr| { - u.encode(&mut ebml::writer::Encoder(wr)); - }; - let u2 = Decodable::decode(&mut ebml::reader::Decoder(ebml::reader::Doc(@bytes))); + let wr = @mut MemWriter::new(); + u.encode(&mut ebml::writer::Encoder(wr)); + let doc = ebml::reader::Doc(@wr.inner_ref().to_owned()); + let u2 = Decodable::decode(&mut ebml::reader::Decoder(doc)); assert_eq!(u, u2); } } diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 4d79b2059db5c..30efecde37f91 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -19,7 +19,13 @@ use arc::{Arc,RWArc}; use treemap::TreeMap; use std::cell::Cell; use std::comm::{PortOne, oneshot}; -use std::{io, os, task}; +use std::{os, str, task}; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::Decorator; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::mem::MemWriter; +use std::rt::io::file::FileInfo; /** * @@ -174,19 +180,19 @@ impl Database { // FIXME #4330: This should have &mut self and should set self.db_dirty to false. fn save(&self) { - let f = io::file_writer(&self.db_filename, [io::Create, io::Truncate]).unwrap(); - self.db_cache.to_json().to_pretty_writer(f); + let f = @mut self.db_filename.open_writer(io::CreateOrTruncate); + self.db_cache.to_json().to_pretty_writer(f as @mut io::Writer); } fn load(&mut self) { assert!(!self.db_dirty); assert!(os::path_exists(&self.db_filename)); - let f = io::file_reader(&self.db_filename); + let f = self.db_filename.open_reader(io::Open); match f { - Err(e) => fail!("Couldn't load workcache database {}: {}", - self.db_filename.display(), e.to_str()), - Ok(r) => - match json::from_reader(r) { + None => fail!("Couldn't load workcache database {}", + self.db_filename.display()), + Some(r) => + match json::from_reader(@mut r as @mut io::Reader) { Err(e) => fail!("Couldn't parse workcache database (from file {}): {}", self.db_filename.display(), e.to_str()), Ok(r) => { @@ -256,20 +262,18 @@ enum Work<'self, T> { } fn json_encode>(t: &T) -> ~str { - do io::with_str_writer |wr| { - let mut encoder = json::Encoder(wr); - t.encode(&mut encoder); - } + let writer = @mut MemWriter::new(); + let mut encoder = json::Encoder(writer as @mut io::Writer); + t.encode(&mut encoder); + str::from_utf8(writer.inner_ref().as_slice()) } // FIXME(#5121) fn json_decode>(s: &str) -> T { debug!("json decoding: {}", s); - do io::with_str_reader(s) |rdr| { - let j = json::from_reader(rdr).unwrap(); - let mut decoder = json::Decoder(j); - Decodable::decode(&mut decoder) - } + let j = json::from_str(s).unwrap(); + let mut decoder = json::Decoder(j); + Decodable::decode(&mut decoder) } fn digest>(t: &T) -> ~str { @@ -280,8 +284,8 @@ fn digest>(t: &T) -> ~str { fn digest_file(path: &Path) -> ~str { let mut sha = ~Sha1::new(); - let s = io::read_whole_file_str(path); - (*sha).input_str(s.unwrap()); + let s = path.open_reader(io::Open).read_to_end(); + (*sha).input(s); (*sha).result_str() } @@ -492,7 +496,6 @@ impl<'self, T:Send + #[test] fn test() { - use std::io::WriterUtil; use std::{os, run}; // Create a path to a new file 'filename' in the directory in which @@ -507,8 +510,7 @@ fn test() { let pth = make_path(~"foo.c"); { - let r = io::file_writer(&pth, [io::Create]); - r.unwrap().write_str("int main() { return 0; }"); + pth.open_writer(io::Create).write(bytes!("int main() { return 0; }")); } let db_path = make_path(~"db.json"); @@ -539,5 +541,5 @@ fn test() { } }; - io::println(s); + println(s); } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 2438d22881fb5..1b9cb10f1dcfd 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -26,7 +26,6 @@ use std::c_str::ToCStr; use std::char; use std::hash::Streaming; use std::hash; -use std::io; use std::os::consts::{macos, freebsd, linux, android, win32}; use std::os; use std::ptr; @@ -930,7 +929,7 @@ pub fn link_binary(sess: Session, let cc_args = link_args(sess, obj_filename, out_filename, lm); debug!("{} link args: {}", cc_prog, cc_args.connect(" ")); if (sess.opts.debugging_opts & session::print_link_args) != 0 { - io::println(format!("{} link args: {}", cc_prog, cc_args.connect(" "))); + println!("{} link args: {}", cc_prog, cc_args.connect(" ")); } // We run 'cc' here diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 67a59f24e2938..d2b0dad80f656 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -26,7 +26,8 @@ use util::common::time; use util::ppaux; use std::hashmap::{HashMap,HashSet}; -use std::io; +use std::rt::io; +use std::rt::io::mem::MemReader; use std::os; use std::vec; use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt}; @@ -552,17 +553,16 @@ pub fn pretty_print_input(sess: Session, }; let src = sess.codemap.get_filemap(source_name(input)).src; - do io::with_str_reader(src) |rdr| { - pprust::print_crate(sess.codemap, - token::get_ident_interner(), - sess.span_diagnostic, - &crate, - source_name(input), - rdr, - io::stdout(), - annotation, - is_expanded); - } + let rdr = @mut MemReader::new(src.as_bytes().to_owned()); + pprust::print_crate(sess.codemap, + token::get_ident_interner(), + sess.span_diagnostic, + &crate, + source_name(input), + rdr as @mut io::Reader, + @mut io::stdout() as @mut io::Writer, + annotation, + is_expanded); } pub fn get_os(triple: &str) -> Option { @@ -1048,7 +1048,7 @@ pub fn early_error(emitter: @diagnostic::Emitter, msg: &str) -> ! { fail!(); } -pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) { +pub fn list_metadata(sess: Session, path: &Path, out: @mut io::Writer) { metadata::loader::list_file_metadata( token::get_ident_interner(), session::sess_os_to_meta_os(sess.targ_cfg.os), path, out); diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 1023273032942..aca41f5f4cbb9 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -27,8 +27,8 @@ use middle::astencode::vtable_decoder_helpers; use std::u64; -use std::io::WriterUtil; -use std::io; +use std::rt::io; +use std::rt::io::extensions::u64_from_be_bytes; use std::option; use std::str; use std::vec; @@ -56,14 +56,14 @@ fn lookup_hash(d: ebml::Doc, eq_fn: &fn(x:&[u8]) -> bool, hash: u64) -> let index = reader::get_doc(d, tag_index); let table = reader::get_doc(index, tag_index_table); let hash_pos = table.start + (hash % 256 * 4) as uint; - let pos = io::u64_from_be_bytes(*d.data, hash_pos, 4) as uint; + let pos = u64_from_be_bytes(*d.data, hash_pos, 4) as uint; let tagged_doc = reader::doc_at(d.data, pos); let belt = tag_index_buckets_bucket_elt; let mut ret = None; do reader::tagged_docs(tagged_doc.doc, belt) |elt| { - let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4) as uint; + let pos = u64_from_be_bytes(*elt.data, elt.start, 4) as uint; if eq_fn(elt.data.slice(elt.start + 4, elt.end)) { ret = Some(reader::doc_at(d.data, pos).doc); false @@ -78,7 +78,7 @@ pub type GetCrateDataCb<'self> = &'self fn(ast::CrateNum) -> Cmd; pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option { fn eq_item(bytes: &[u8], item_id: int) -> bool { - return io::u64_from_be_bytes( + return u64_from_be_bytes( bytes.slice(0u, 4u), 0u, 4u) as int == item_id; } @@ -1254,7 +1254,7 @@ fn family_names_type(fam: Family) -> bool { fn read_path(d: ebml::Doc) -> (~str, uint) { do reader::with_doc_data(d) |desc| { - let pos = io::u64_from_be_bytes(desc, 0u, 4u) as uint; + let pos = u64_from_be_bytes(desc, 0u, 4u) as uint; let pathbytes = desc.slice(4u, desc.len()); let path = str::from_utf8(pathbytes); @@ -1353,23 +1353,23 @@ fn get_attributes(md: ebml::Doc) -> ~[ast::Attribute] { fn list_meta_items(intr: @ident_interner, meta_items: ebml::Doc, - out: @io::Writer) { + out: @mut io::Writer) { let r = get_meta_items(meta_items); for mi in r.iter() { - out.write_str(format!("{}\n", pprust::meta_item_to_str(*mi, intr))); + write!(out, "{}\n", pprust::meta_item_to_str(*mi, intr)); } } fn list_crate_attributes(intr: @ident_interner, md: ebml::Doc, hash: &str, - out: @io::Writer) { - out.write_str(format!("=Crate Attributes ({})=\n", hash)); + out: @mut io::Writer) { + write!(out, "=Crate Attributes ({})=\n", hash); let r = get_attributes(md); for attr in r.iter() { - out.write_str(format!("{}\n", pprust::attribute_to_str(attr, intr))); + write!(out, "{}\n", pprust::attribute_to_str(attr, intr)); } - out.write_str("\n\n"); + write!(out, "\n\n"); } pub fn get_crate_attributes(data: @~[u8]) -> ~[ast::Attribute] { @@ -1404,17 +1404,16 @@ pub fn get_crate_deps(data: @~[u8]) -> ~[CrateDep] { return deps; } -fn list_crate_deps(data: @~[u8], out: @io::Writer) { - out.write_str("=External Dependencies=\n"); +fn list_crate_deps(data: @~[u8], out: @mut io::Writer) { + write!(out, "=External Dependencies=\n"); let r = get_crate_deps(data); for dep in r.iter() { - out.write_str( - format!("{} {}-{}-{}\n", - dep.cnum, token::ident_to_str(&dep.name), dep.hash, dep.vers)); + write!(out, "{} {}-{}-{}\n", + dep.cnum, token::ident_to_str(&dep.name), dep.hash, dep.vers); } - out.write_str("\n"); + write!(out, "\n"); } pub fn get_crate_hash(data: @~[u8]) -> @str { @@ -1434,7 +1433,7 @@ pub fn get_crate_vers(data: @~[u8]) -> @str { } pub fn list_crate_metadata(intr: @ident_interner, bytes: @~[u8], - out: @io::Writer) { + out: @mut io::Writer) { let hash = get_crate_hash(bytes); let md = reader::Doc(bytes); list_crate_attributes(intr, md, hash, out); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index bae0dcc2a5203..d64820332a5d9 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -22,12 +22,16 @@ use middle::typeck; use middle; use std::hashmap::{HashMap, HashSet}; -use std::io; +use std::rt::io::extensions::WriterByteConversions; +use std::rt::io::{Writer, Seek, Decorator}; +use std::rt::io::mem::MemWriter; use std::str; use std::vec; + use extra::flate; use extra::serialize::Encodable; use extra; + use syntax::abi::AbiSet; use syntax::ast::*; use syntax::ast; @@ -68,17 +72,17 @@ pub struct EncodeParams<'self> { } struct Stats { - inline_bytes: uint, - attr_bytes: uint, - dep_bytes: uint, - lang_item_bytes: uint, - link_args_bytes: uint, - impl_bytes: uint, - misc_bytes: uint, - item_bytes: uint, - index_bytes: uint, - zero_bytes: uint, - total_bytes: uint, + inline_bytes: u64, + attr_bytes: u64, + dep_bytes: u64, + lang_item_bytes: u64, + link_args_bytes: u64, + impl_bytes: u64, + misc_bytes: u64, + item_bytes: u64, + index_bytes: u64, + zero_bytes: u64, + total_bytes: u64, n_inlines: uint } @@ -133,7 +137,7 @@ fn encode_region_param(ecx: &EncodeContext, #[deriving(Clone)] struct entry { val: T, - pos: uint + pos: u64 } fn add_to_index(ebml_w: &mut writer::Encoder, @@ -1395,10 +1399,9 @@ fn create_index( fn encode_index( ebml_w: &mut writer::Encoder, buckets: ~[@~[entry]], - write_fn: &fn(@io::Writer, &T)) { - let writer = ebml_w.writer; + write_fn: &fn(@mut MemWriter, &T)) { ebml_w.start_tag(tag_index); - let mut bucket_locs: ~[uint] = ~[]; + let mut bucket_locs = ~[]; ebml_w.start_tag(tag_index_buckets); for bucket in buckets.iter() { bucket_locs.push(ebml_w.writer.tell()); @@ -1406,8 +1409,11 @@ fn encode_index( for elt in (**bucket).iter() { ebml_w.start_tag(tag_index_buckets_bucket_elt); assert!(elt.pos < 0xffff_ffff); - writer.write_be_u32(elt.pos as u32); - write_fn(writer, &elt.val); + { + let wr: &mut MemWriter = ebml_w.writer; + wr.write_be_u32_(elt.pos as u32); + } + write_fn(ebml_w.writer, &elt.val); ebml_w.end_tag(); } ebml_w.end_tag(); @@ -1416,19 +1422,21 @@ fn encode_index( ebml_w.start_tag(tag_index_table); for pos in bucket_locs.iter() { assert!(*pos < 0xffff_ffff); - writer.write_be_u32(*pos as u32); + let wr: &mut MemWriter = ebml_w.writer; + wr.write_be_u32_(*pos as u32); } ebml_w.end_tag(); ebml_w.end_tag(); } -fn write_str(writer: @io::Writer, s: ~str) { - writer.write_str(s); +fn write_str(writer: @mut MemWriter, s: ~str) { + writer.write(s.as_bytes()); } -fn write_i64(writer: @io::Writer, &n: &i64) { +fn write_i64(writer: @mut MemWriter, &n: &i64) { + let wr: &mut MemWriter = writer; assert!(n < 0x7fff_ffff); - writer.write_be_u32(n as u32); + wr.write_be_u32_(n as u32); } fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @MetaItem) { @@ -1581,11 +1589,17 @@ fn encode_lang_items(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.start_tag(tag_lang_items_item); ebml_w.start_tag(tag_lang_items_item_id); - ebml_w.writer.write_be_u32(i as u32); + { + let wr: &mut MemWriter = ebml_w.writer; + wr.write_be_u32_(i as u32); + } ebml_w.end_tag(); // tag_lang_items_item_id ebml_w.start_tag(tag_lang_items_item_node_id); - ebml_w.writer.write_be_u32(id.node as u32); + { + let wr: &mut MemWriter = ebml_w.writer; + wr.write_be_u32_(id.node as u32); + } ebml_w.end_tag(); // tag_lang_items_item_node_id ebml_w.end_tag(); // tag_lang_items_item @@ -1602,7 +1616,7 @@ fn encode_link_args(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) { let link_args = cstore::get_used_link_args(ecx.cstore); for link_arg in link_args.iter() { ebml_w.start_tag(tag_link_args_arg); - ebml_w.writer.write_str(link_arg.to_str()); + ebml_w.writer.write(link_arg.as_bytes()); ebml_w.end_tag(); } @@ -1720,7 +1734,7 @@ pub static metadata_encoding_version : &'static [u8] = 0, 0, 0, 1 ]; pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { - let wr = @io::BytesWriter::new(); + let wr = @mut MemWriter::new(); let stats = Stats { inline_bytes: 0, attr_bytes: 0, @@ -1765,61 +1779,61 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { reachable: reachable, }; - let mut ebml_w = writer::Encoder(wr as @io::Writer); + let mut ebml_w = writer::Encoder(wr); encode_hash(&mut ebml_w, ecx.link_meta.extras_hash); - let mut i = *wr.pos; + let mut i = wr.tell(); let crate_attrs = synthesize_crate_attrs(&ecx, crate); encode_attributes(&mut ebml_w, crate_attrs); - ecx.stats.attr_bytes = *wr.pos - i; + ecx.stats.attr_bytes = wr.tell() - i; - i = *wr.pos; + i = wr.tell(); encode_crate_deps(&ecx, &mut ebml_w, ecx.cstore); - ecx.stats.dep_bytes = *wr.pos - i; + ecx.stats.dep_bytes = wr.tell() - i; // Encode the language items. - i = *wr.pos; + i = wr.tell(); encode_lang_items(&ecx, &mut ebml_w); - ecx.stats.lang_item_bytes = *wr.pos - i; + ecx.stats.lang_item_bytes = wr.tell() - i; // Encode the link args. - i = *wr.pos; + i = wr.tell(); encode_link_args(&ecx, &mut ebml_w); - ecx.stats.link_args_bytes = *wr.pos - i; + ecx.stats.link_args_bytes = wr.tell() - i; // Encode the def IDs of impls, for coherence checking. - i = *wr.pos; + i = wr.tell(); encode_impls(&ecx, crate, &mut ebml_w); - ecx.stats.impl_bytes = *wr.pos - i; + ecx.stats.impl_bytes = wr.tell() - i; // Encode miscellaneous info. - i = *wr.pos; + i = wr.tell(); encode_misc_info(&ecx, crate, &mut ebml_w); - ecx.stats.misc_bytes = *wr.pos - i; + ecx.stats.misc_bytes = wr.tell() - i; // Encode and index the items. ebml_w.start_tag(tag_items); - i = *wr.pos; + i = wr.tell(); let items_index = encode_info_for_items(&ecx, &mut ebml_w, crate); - ecx.stats.item_bytes = *wr.pos - i; + ecx.stats.item_bytes = wr.tell() - i; - i = *wr.pos; + i = wr.tell(); let items_buckets = create_index(items_index); encode_index(&mut ebml_w, items_buckets, write_i64); - ecx.stats.index_bytes = *wr.pos - i; + ecx.stats.index_bytes = wr.tell() - i; ebml_w.end_tag(); - ecx.stats.total_bytes = *wr.pos; + ecx.stats.total_bytes = wr.tell(); if (tcx.sess.meta_stats()) { - for e in wr.bytes.iter() { + for e in wr.inner_ref().iter() { if *e == 0 { ecx.stats.zero_bytes += 1; } } - io::println("metadata stats:"); + println("metadata stats:"); println!(" inline bytes: {}", ecx.stats.inline_bytes); println!(" attribute bytes: {}", ecx.stats.attr_bytes); println!(" dep bytes: {}", ecx.stats.dep_bytes); @@ -1837,7 +1851,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { // remaining % 4 bytes. wr.write(&[0u8, 0u8, 0u8, 0u8]); - let writer_bytes: &mut ~[u8] = wr.bytes; + let writer_bytes: &mut ~[u8] = wr.inner_mut_ref(); metadata_encoding_version.to_owned() + flate::deflate_bytes(*writer_bytes) @@ -1850,7 +1864,7 @@ pub fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str { ds: def_to_str, tcx: tcx, abbrevs: tyencode::ac_no_abbrevs}; - do io::with_str_writer |wr| { - tyencode::enc_ty(wr, cx, t); - } + let wr = @mut MemWriter::new(); + tyencode::enc_ty(wr, cx, t); + str::from_utf8(*wr.inner_ref()) } diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index e682ff299a935..34eb387a3f5d4 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -25,7 +25,7 @@ use syntax::attr::AttrMetaMethods; use std::c_str::ToCStr; use std::cast; -use std::io; +use std::rt::io; use std::num; use std::option; use std::os::consts::{macos, freebsd, linux, android, win32}; @@ -271,11 +271,11 @@ pub fn read_meta_section_name(os: Os) -> &'static str { pub fn list_file_metadata(intr: @ident_interner, os: Os, path: &Path, - out: @io::Writer) { + out: @mut io::Writer) { match get_metadata_section(os, path) { option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out), option::None => { - out.write_str(format!("could not find metadata in {}.\n", path.display())) + write!(out, "could not find metadata in {}.\n", path.display()) } } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 33be1be895556..7fb33c881156b 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -10,19 +10,26 @@ // Type encoding +use std::hashmap::HashMap; +use std::rt::io; +use std::rt::io::{Decorator, Writer, Seek}; +use std::rt::io::mem::MemWriter; +use std::str; +use std::fmt; use middle::ty::param_ty; use middle::ty; -use std::hashmap::HashMap; -use std::io::WriterUtil; -use std::io; use syntax::abi::AbiSet; use syntax::ast; use syntax::ast::*; use syntax::diagnostic::span_handler; use syntax::print::pprust::*; +macro_rules! mywrite( ($wr:expr, $($arg:tt)*) => ( + format_args!(|a| { mywrite($wr, a) }, $($arg)*) +) ) + pub struct ctxt { diag: @mut span_handler, // Def -> str Callback: @@ -46,6 +53,10 @@ pub enum abbrev_ctxt { ac_use_abbrevs(@mut HashMap), } +fn mywrite(w: @mut MemWriter, fmt: &fmt::Arguments) { + fmt::write(&mut *w as &mut io::Writer, fmt); +} + fn cx_uses_abbrevs(cx: @ctxt) -> bool { match cx.abbrevs { ac_no_abbrevs => return false, @@ -53,41 +64,43 @@ fn cx_uses_abbrevs(cx: @ctxt) -> bool { } } -pub fn enc_ty(w: @io::Writer, cx: @ctxt, t: ty::t) { +pub fn enc_ty(w: @mut MemWriter, cx: @ctxt, t: ty::t) { match cx.abbrevs { ac_no_abbrevs => { let result_str = match cx.tcx.short_names_cache.find(&t) { Some(&s) => s, None => { - let s = do io::with_str_writer |wr| { - enc_sty(wr, cx, &ty::get(t).sty); - }.to_managed(); + let wr = @mut MemWriter::new(); + enc_sty(wr, cx, &ty::get(t).sty); + let s = str::from_utf8(*wr.inner_ref()).to_managed(); cx.tcx.short_names_cache.insert(t, s); s } }; - w.write_str(result_str); + w.write(result_str.as_bytes()); } ac_use_abbrevs(abbrevs) => { match abbrevs.find(&t) { - Some(a) => { w.write_str(a.s); return; } + Some(a) => { w.write(a.s.as_bytes()); return; } None => {} } let pos = w.tell(); enc_sty(w, cx, &ty::get(t).sty); let end = w.tell(); let len = end - pos; - fn estimate_sz(u: uint) -> uint { + fn estimate_sz(u: u64) -> u64 { let mut n = u; - let mut len = 0u; - while n != 0u { len += 1u; n = n >> 4u; } + let mut len = 0; + while n != 0 { len += 1; n = n >> 4; } return len; } - let abbrev_len = 3u + estimate_sz(pos) + estimate_sz(len); + let abbrev_len = 3 + estimate_sz(pos) + estimate_sz(len); if abbrev_len < len { // I.e. it's actually an abbreviation. let s = format!("\\#{:x}:{:x}\\#", pos, len).to_managed(); - let a = ty_abbrev { pos: pos, len: len, s: s }; + let a = ty_abbrev { pos: pos as uint, + len: len as uint, + s: s }; abbrevs.insert(t, a); } return; @@ -95,301 +108,253 @@ pub fn enc_ty(w: @io::Writer, cx: @ctxt, t: ty::t) { } } -fn enc_mutability(w: @io::Writer, mt: ast::Mutability) { +fn enc_mutability(w: @mut MemWriter, mt: ast::Mutability) { match mt { - MutImmutable => (), - MutMutable => w.write_char('m'), + MutImmutable => (), + MutMutable => mywrite!(w, "m"), } } -fn enc_mt(w: @io::Writer, cx: @ctxt, mt: ty::mt) { +fn enc_mt(w: @mut MemWriter, cx: @ctxt, mt: ty::mt) { enc_mutability(w, mt.mutbl); enc_ty(w, cx, mt.ty); } -fn enc_opt(w: @io::Writer, t: Option, enc_f: &fn(T)) { +fn enc_opt(w: @mut MemWriter, t: Option, enc_f: &fn(T)) { match t { - None => w.write_char('n'), - Some(v) => { - w.write_char('s'); - enc_f(v); - } + None => mywrite!(w, "n"), + Some(v) => { + mywrite!(w, "s"); + enc_f(v); + } } } -fn enc_substs(w: @io::Writer, cx: @ctxt, substs: &ty::substs) { +fn enc_substs(w: @mut MemWriter, cx: @ctxt, substs: &ty::substs) { enc_region_substs(w, cx, &substs.regions); do enc_opt(w, substs.self_ty) |t| { enc_ty(w, cx, t) } - w.write_char('['); + mywrite!(w, "["); for t in substs.tps.iter() { enc_ty(w, cx, *t); } - w.write_char(']'); + mywrite!(w, "]"); } -fn enc_region_substs(w: @io::Writer, cx: @ctxt, substs: &ty::RegionSubsts) { +fn enc_region_substs(w: @mut MemWriter, cx: @ctxt, substs: &ty::RegionSubsts) { match *substs { ty::ErasedRegions => { - w.write_char('e'); + mywrite!(w, "e"); } ty::NonerasedRegions(ref regions) => { - w.write_char('n'); + mywrite!(w, "n"); for &r in regions.iter() { enc_region(w, cx, r); } - w.write_char('.'); + mywrite!(w, "."); } } } -fn enc_region(w: @io::Writer, cx: @ctxt, r: ty::Region) { +fn enc_region(w: @mut MemWriter, cx: @ctxt, r: ty::Region) { match r { - ty::re_bound(br) => { - w.write_char('b'); - enc_bound_region(w, cx, br); - } - ty::re_free(ref fr) => { - w.write_char('f'); - w.write_char('['); - w.write_int(fr.scope_id); - w.write_char('|'); - enc_bound_region(w, cx, fr.bound_region); - w.write_char(']'); - } - ty::re_scope(nid) => { - w.write_char('s'); - w.write_int(nid); - w.write_char('|'); - } - ty::re_static => { - w.write_char('t'); - } - ty::re_empty => { - w.write_char('e'); - } - ty::re_infer(_) => { - // these should not crop up after typeck - cx.diag.handler().bug("Cannot encode region variables"); - } + ty::re_bound(br) => { + mywrite!(w, "b"); + enc_bound_region(w, cx, br); + } + ty::re_free(ref fr) => { + mywrite!(w, "f[{}|", fr.scope_id); + enc_bound_region(w, cx, fr.bound_region); + mywrite!(w, "]"); + } + ty::re_scope(nid) => mywrite!(w, "s{}|", nid), + ty::re_static => mywrite!(w, "t"), + ty::re_empty => mywrite!(w, "e"), + ty::re_infer(_) => { + // these should not crop up after typeck + cx.diag.handler().bug("Cannot encode region variables"); + } } } -fn enc_bound_region(w: @io::Writer, cx: @ctxt, br: ty::bound_region) { +fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::bound_region) { match br { - ty::br_self => w.write_char('s'), - ty::br_anon(idx) => { - w.write_char('a'); - w.write_uint(idx); - w.write_char('|'); - } - ty::br_named(s) => { - w.write_char('['); - w.write_str(cx.tcx.sess.str_of(s)); - w.write_char(']') - } - ty::br_cap_avoid(id, br) => { - w.write_char('c'); - w.write_int(id); - w.write_char('|'); - enc_bound_region(w, cx, *br); - } - ty::br_fresh(id) => { - w.write_uint(id); - } + ty::br_self => mywrite!(w, "s"), + ty::br_anon(idx) => mywrite!(w, "a{}|", idx), + ty::br_named(s) => mywrite!(w, "[{}]", cx.tcx.sess.str_of(s)), + ty::br_cap_avoid(id, br) => { + mywrite!(w, "c{}|", id); + enc_bound_region(w, cx, *br); + } + ty::br_fresh(id) => mywrite!(w, "{}", id), } } -pub fn enc_vstore(w: @io::Writer, cx: @ctxt, v: ty::vstore) { - w.write_char('/'); +pub fn enc_vstore(w: @mut MemWriter, cx: @ctxt, v: ty::vstore) { + mywrite!(w, "/"); match v { - ty::vstore_fixed(u) => { - w.write_uint(u); - w.write_char('|'); - } - ty::vstore_uniq => { - w.write_char('~'); - } - ty::vstore_box => { - w.write_char('@'); - } - ty::vstore_slice(r) => { - w.write_char('&'); - enc_region(w, cx, r); - } + ty::vstore_fixed(u) => mywrite!(w, "{}|", u), + ty::vstore_uniq => mywrite!(w, "~"), + ty::vstore_box => mywrite!(w, "@"), + ty::vstore_slice(r) => { + mywrite!(w, "&"); + enc_region(w, cx, r); + } } } -pub fn enc_trait_ref(w: @io::Writer, cx: @ctxt, s: &ty::TraitRef) { - w.write_str((cx.ds)(s.def_id)); - w.write_char('|'); +pub fn enc_trait_ref(w: @mut MemWriter, cx: @ctxt, s: &ty::TraitRef) { + mywrite!(w, "{}|", (cx.ds)(s.def_id)); enc_substs(w, cx, &s.substs); } -pub fn enc_trait_store(w: @io::Writer, cx: @ctxt, s: ty::TraitStore) { +pub fn enc_trait_store(w: @mut MemWriter, cx: @ctxt, s: ty::TraitStore) { match s { - ty::UniqTraitStore => w.write_char('~'), - ty::BoxTraitStore => w.write_char('@'), + ty::UniqTraitStore => mywrite!(w, "~"), + ty::BoxTraitStore => mywrite!(w, "@"), ty::RegionTraitStore(re) => { - w.write_char('&'); + mywrite!(w, "&"); enc_region(w, cx, re); } } } -fn enc_sty(w: @io::Writer, cx: @ctxt, st: &ty::sty) { +fn enc_sty(w: @mut MemWriter, cx: @ctxt, st: &ty::sty) { match *st { - ty::ty_nil => w.write_char('n'), - ty::ty_bot => w.write_char('z'), - ty::ty_bool => w.write_char('b'), - ty::ty_char => w.write_char('c'), - ty::ty_int(t) => { - match t { - ty_i => w.write_char('i'), - ty_i8 => w.write_str(&"MB"), - ty_i16 => w.write_str(&"MW"), - ty_i32 => w.write_str(&"ML"), - ty_i64 => w.write_str(&"MD") + ty::ty_nil => mywrite!(w, "n"), + ty::ty_bot => mywrite!(w, "z"), + ty::ty_bool => mywrite!(w, "b"), + ty::ty_char => mywrite!(w, "c"), + ty::ty_int(t) => { + match t { + ty_i => mywrite!(w, "i"), + ty_i8 => mywrite!(w, "MB"), + ty_i16 => mywrite!(w, "MW"), + ty_i32 => mywrite!(w, "ML"), + ty_i64 => mywrite!(w, "MD") + } } - } - ty::ty_uint(t) => { - match t { - ty_u => w.write_char('u'), - ty_u8 => w.write_str(&"Mb"), - ty_u16 => w.write_str(&"Mw"), - ty_u32 => w.write_str(&"Ml"), - ty_u64 => w.write_str(&"Md") + ty::ty_uint(t) => { + match t { + ty_u => mywrite!(w, "u"), + ty_u8 => mywrite!(w, "Mb"), + ty_u16 => mywrite!(w, "Mw"), + ty_u32 => mywrite!(w, "Ml"), + ty_u64 => mywrite!(w, "Md") + } } - } - ty::ty_float(t) => { - match t { - ty_f32 => w.write_str(&"Mf"), - ty_f64 => w.write_str(&"MF"), + ty::ty_float(t) => { + match t { + ty_f32 => mywrite!(w, "Mf"), + ty_f64 => mywrite!(w, "MF"), + } } - } - ty::ty_enum(def, ref substs) => { - w.write_str(&"t["); - w.write_str((cx.ds)(def)); - w.write_char('|'); - enc_substs(w, cx, substs); - w.write_char(']'); - } - ty::ty_trait(def, ref substs, store, mt, bounds) => { - w.write_str(&"x["); - w.write_str((cx.ds)(def)); - w.write_char('|'); - enc_substs(w, cx, substs); - enc_trait_store(w, cx, store); - enc_mutability(w, mt); - let bounds = ty::ParamBounds {builtin_bounds: bounds, - trait_bounds: ~[]}; - enc_bounds(w, cx, &bounds); - w.write_char(']'); - } - ty::ty_tup(ref ts) => { - w.write_str(&"T["); - for t in ts.iter() { enc_ty(w, cx, *t); } - w.write_char(']'); - } - ty::ty_box(mt) => { w.write_char('@'); enc_mt(w, cx, mt); } - ty::ty_uniq(mt) => { w.write_char('~'); enc_mt(w, cx, mt); } - ty::ty_ptr(mt) => { w.write_char('*'); enc_mt(w, cx, mt); } - ty::ty_rptr(r, mt) => { - w.write_char('&'); - enc_region(w, cx, r); - enc_mt(w, cx, mt); - } - ty::ty_evec(mt, v) => { - w.write_char('V'); - enc_mt(w, cx, mt); - enc_vstore(w, cx, v); - } - ty::ty_estr(v) => { - w.write_char('v'); - enc_vstore(w, cx, v); - } - ty::ty_unboxed_vec(mt) => { w.write_char('U'); enc_mt(w, cx, mt); } - ty::ty_closure(ref f) => { - w.write_char('f'); - enc_closure_ty(w, cx, f); - } - ty::ty_bare_fn(ref f) => { - w.write_char('F'); - enc_bare_fn_ty(w, cx, f); - } - ty::ty_infer(_) => { - cx.diag.handler().bug("Cannot encode inference variable types"); - } - ty::ty_param(param_ty {idx: id, def_id: did}) => { - w.write_char('p'); - w.write_str((cx.ds)(did)); - w.write_char('|'); - w.write_str(id.to_str()); - } - ty::ty_self(did) => { - w.write_char('s'); - w.write_str((cx.ds)(did)); - w.write_char('|'); - } - ty::ty_type => w.write_char('Y'), - ty::ty_opaque_closure_ptr(p) => { - w.write_str(&"C&"); - enc_sigil(w, p); - } - ty::ty_opaque_box => w.write_char('B'), - ty::ty_struct(def, ref substs) => { - debug!("~~~~ {}", "a["); - w.write_str(&"a["); - let s = (cx.ds)(def); - debug!("~~~~ {}", s); - w.write_str(s); - debug!("~~~~ {}", "|"); - w.write_char('|'); - enc_substs(w, cx, substs); - debug!("~~~~ {}", "]"); - w.write_char(']'); - } - ty::ty_err => fail!("Shouldn't encode error type") + ty::ty_enum(def, ref substs) => { + mywrite!(w, "t[{}|", (cx.ds)(def)); + enc_substs(w, cx, substs); + mywrite!(w, "]"); + } + ty::ty_trait(def, ref substs, store, mt, bounds) => { + mywrite!(w, "x[{}|", (cx.ds)(def)); + enc_substs(w, cx, substs); + enc_trait_store(w, cx, store); + enc_mutability(w, mt); + let bounds = ty::ParamBounds {builtin_bounds: bounds, + trait_bounds: ~[]}; + enc_bounds(w, cx, &bounds); + mywrite!(w, "]"); + } + ty::ty_tup(ref ts) => { + mywrite!(w, "T["); + for t in ts.iter() { enc_ty(w, cx, *t); } + mywrite!(w, "]"); + } + ty::ty_box(mt) => { mywrite!(w, "@"); enc_mt(w, cx, mt); } + ty::ty_uniq(mt) => { mywrite!(w, "~"); enc_mt(w, cx, mt); } + ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); } + ty::ty_rptr(r, mt) => { + mywrite!(w, "&"); + enc_region(w, cx, r); + enc_mt(w, cx, mt); + } + ty::ty_evec(mt, v) => { + mywrite!(w, "V"); + enc_mt(w, cx, mt); + enc_vstore(w, cx, v); + } + ty::ty_estr(v) => { + mywrite!(w, "v"); + enc_vstore(w, cx, v); + } + ty::ty_unboxed_vec(mt) => { mywrite!(w, "U"); enc_mt(w, cx, mt); } + ty::ty_closure(ref f) => { + mywrite!(w, "f"); + enc_closure_ty(w, cx, f); + } + ty::ty_bare_fn(ref f) => { + mywrite!(w, "F"); + enc_bare_fn_ty(w, cx, f); + } + ty::ty_infer(_) => { + cx.diag.handler().bug("Cannot encode inference variable types"); + } + ty::ty_param(param_ty {idx: id, def_id: did}) => { + mywrite!(w, "p{}|{}", (cx.ds)(did), id); + } + ty::ty_self(did) => { + mywrite!(w, "s{}|", (cx.ds)(did)); + } + ty::ty_type => mywrite!(w, "Y"), + ty::ty_opaque_closure_ptr(p) => { + mywrite!(w, "C&"); + enc_sigil(w, p); + } + ty::ty_opaque_box => mywrite!(w, "B"), + ty::ty_struct(def, ref substs) => { + mywrite!(w, "a[{}|", (cx.ds)(def)); + enc_substs(w, cx, substs); + mywrite!(w, "]"); + } + ty::ty_err => fail!("Shouldn't encode error type") } } -fn enc_sigil(w: @io::Writer, sigil: Sigil) { +fn enc_sigil(w: @mut MemWriter, sigil: Sigil) { match sigil { - ManagedSigil => w.write_str("@"), - OwnedSigil => w.write_str("~"), - BorrowedSigil => w.write_str("&"), + ManagedSigil => mywrite!(w, "@"), + OwnedSigil => mywrite!(w, "~"), + BorrowedSigil => mywrite!(w, "&"), } } -fn enc_purity(w: @io::Writer, p: purity) { +fn enc_purity(w: @mut MemWriter, p: purity) { match p { - impure_fn => w.write_char('i'), - unsafe_fn => w.write_char('u'), - extern_fn => w.write_char('c') + impure_fn => mywrite!(w, "i"), + unsafe_fn => mywrite!(w, "u"), + extern_fn => mywrite!(w, "c") } } -fn enc_abi_set(w: @io::Writer, abis: AbiSet) { - w.write_char('['); +fn enc_abi_set(w: @mut MemWriter, abis: AbiSet) { + mywrite!(w, "["); do abis.each |abi| { - w.write_str(abi.name()); - w.write_char(','); + mywrite!(w, "{},", abi.name()); true }; - w.write_char(']') + mywrite!(w, "]") } -fn enc_onceness(w: @io::Writer, o: Onceness) { +fn enc_onceness(w: @mut MemWriter, o: Onceness) { match o { - Once => w.write_char('o'), - Many => w.write_char('m') + Once => mywrite!(w, "o"), + Many => mywrite!(w, "m") } } -pub fn enc_bare_fn_ty(w: @io::Writer, cx: @ctxt, ft: &ty::BareFnTy) { +pub fn enc_bare_fn_ty(w: @mut MemWriter, cx: @ctxt, ft: &ty::BareFnTy) { enc_purity(w, ft.purity); enc_abi_set(w, ft.abis); enc_fn_sig(w, cx, &ft.sig); } -fn enc_closure_ty(w: @io::Writer, cx: @ctxt, ft: &ty::ClosureTy) { +fn enc_closure_ty(w: @mut MemWriter, cx: @ctxt, ft: &ty::ClosureTy) { enc_sigil(w, ft.sigil); enc_purity(w, ft.purity); enc_onceness(w, ft.onceness); @@ -400,37 +365,34 @@ fn enc_closure_ty(w: @io::Writer, cx: @ctxt, ft: &ty::ClosureTy) { enc_fn_sig(w, cx, &ft.sig); } -fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) { - w.write_char('['); +fn enc_fn_sig(w: @mut MemWriter, cx: @ctxt, fsig: &ty::FnSig) { + mywrite!(w, "["); for ty in fsig.inputs.iter() { enc_ty(w, cx, *ty); } - w.write_char(']'); + mywrite!(w, "]"); enc_ty(w, cx, fsig.output); } -fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) { +fn enc_bounds(w: @mut MemWriter, cx: @ctxt, bs: &ty::ParamBounds) { for bound in bs.builtin_bounds.iter() { match bound { - ty::BoundSend => w.write_char('S'), - ty::BoundFreeze => w.write_char('K'), - ty::BoundStatic => w.write_char('O'), - ty::BoundSized => w.write_char('Z'), + ty::BoundSend => mywrite!(w, "S"), + ty::BoundFreeze => mywrite!(w, "K"), + ty::BoundStatic => mywrite!(w, "O"), + ty::BoundSized => mywrite!(w, "Z"), } } for &tp in bs.trait_bounds.iter() { - w.write_char('I'); + mywrite!(w, "I"); enc_trait_ref(w, cx, tp); } - w.write_char('.'); + mywrite!(w, "."); } -pub fn enc_type_param_def(w: @io::Writer, cx: @ctxt, v: &ty::TypeParameterDef) { - w.write_str(cx.tcx.sess.str_of(v.ident)); - w.write_char(':'); - w.write_str((cx.ds)(v.def_id)); - w.write_char('|'); +pub fn enc_type_param_def(w: @mut MemWriter, cx: @ctxt, v: &ty::TypeParameterDef) { + mywrite!(w, "{}:{}|", cx.tcx.sess.str_of(v.ident), (cx.ds)(v.def_id)); enc_bounds(w, cx, v.bounds); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3d7f28b8b30b1..cb8c7b3262fbf 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -23,13 +23,6 @@ use middle::{ty, typeck, moves}; use middle; use util::ppaux::ty_to_str; -use std::at_vec; -use std::libc; -use extra::ebml::reader; -use extra::ebml; -use extra::serialize; -use extra::serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers}; -use extra::serialize::{Decoder, Decodable}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::inlined_item_utils; @@ -40,9 +33,18 @@ use syntax::fold::*; use syntax::fold; use syntax::parse::token; use syntax; -use writer = extra::ebml::writer; +use std::at_vec; +use std::libc; use std::cast; +use std::rt::io::Seek; + +use extra::ebml::reader; +use extra::ebml; +use extra::serialize; +use extra::serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers}; +use extra::serialize::{Decoder, Decodable}; +use writer = extra::ebml::writer; #[cfg(test)] use syntax::parse; #[cfg(test)] use syntax::print::pprust; @@ -1319,14 +1321,14 @@ fn mk_ctxt() -> @fake_ext_ctxt { #[cfg(test)] fn roundtrip(in_item: Option<@ast::item>) { - use std::io; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; let in_item = in_item.unwrap(); - let bytes = do io::with_bytes_writer |wr| { - let mut ebml_w = writer::Encoder(wr); - encode_item_ast(&mut ebml_w, in_item); - }; - let ebml_doc = reader::Doc(@bytes); + let wr = @mut MemWriter::new(); + let mut ebml_w = writer::Encoder(wr); + encode_item_ast(&mut ebml_w, in_item); + let ebml_doc = reader::Doc(@wr.inner_ref().to_owned()); let out_item = decode_item_ast(ebml_doc); assert_eq!(in_item, out_item); diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 2722fff12a828..55daff90e62e2 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -21,7 +21,6 @@ use util::common::stmt_set; use util::ppaux::{note_and_explain_region, Repr, UserString}; use std::hashmap::{HashSet, HashMap}; -use std::io; use std::ops::{BitOr, BitAnd}; use std::result::{Result}; use syntax::ast; @@ -99,7 +98,7 @@ pub fn check_crate( visit::walk_crate(bccx, crate, ()); if tcx.sess.borrowck_stats() { - io::println("--- borrowck stats ---"); + println("--- borrowck stats ---"); println!("paths requiring guarantees: {}", bccx.stats.guaranteed_paths); println!("paths requiring loans : {}", diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 22fd1d393e972..7ad55936b9ed7 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -18,7 +18,7 @@ use std::cast; -use std::io; +use std::rt::io; use std::uint; use std::vec; use std::hashmap::HashMap; @@ -349,12 +349,12 @@ impl DataFlowContext { debug!("Dataflow result:"); debug!("{}", { let this = @(*self).clone(); - this.pretty_print_to(io::stderr(), blk); + this.pretty_print_to(@mut io::stderr() as @mut io::Writer, blk); "" }); } - fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::Block) { + fn pretty_print_to(@self, wr: @mut io::Writer, blk: &ast::Block) { let ps = pprust::rust_printer_annotated(wr, self.tcx.sess.intr(), self as @pprust::pp_ann); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 71934c9f2a7ed..695f4a6fd13b5 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -111,7 +111,8 @@ use middle::moves; use std::cast::transmute; use std::hashmap::HashMap; -use std::io; +use std::rt::io; +use std::str; use std::to_str; use std::uint; use std::vec; @@ -739,15 +740,14 @@ impl Liveness { } pub fn write_vars(&self, - wr: @io::Writer, + wr: &mut io::Writer, ln: LiveNode, test: &fn(uint) -> LiveNode) { let node_base_idx = self.idx(ln, Variable(0)); for var_idx in range(0u, self.ir.num_vars) { let idx = node_base_idx + var_idx; if test(idx).is_valid() { - wr.write_str(" "); - wr.write_str(Variable(var_idx).to_str()); + write!(wr, " {}", Variable(var_idx).to_str()); } } } @@ -784,20 +784,14 @@ impl Liveness { } pub fn ln_str(&self, ln: LiveNode) -> ~str { - do io::with_str_writer |wr| { - wr.write_str("[ln("); - wr.write_uint(*ln); - wr.write_str(") of kind "); - wr.write_str(format!("{:?}", self.ir.lnks[*ln])); - wr.write_str(" reads"); + str::from_utf8_owned(do io::mem::with_mem_writer |wr| { + let wr = wr as &mut io::Writer; + write!(wr, "[ln({}) of kind {:?} reads", *ln, self.ir.lnks[*ln]); self.write_vars(wr, ln, |idx| self.users[idx].reader ); - wr.write_str(" writes"); + write!(wr, " writes"); self.write_vars(wr, ln, |idx| self.users[idx].writer ); - wr.write_str(" "); - wr.write_str(" precedes "); - wr.write_str((self.successors[*ln]).to_str()); - wr.write_str("]"); - } + write!(wr, " precedes {}]", self.successors[*ln].to_str()); + }) } pub fn init_empty(&self, ln: LiveNode, succ_ln: LiveNode) { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index df7b09f9db79a..8b5167b7e8fa5 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -70,7 +70,6 @@ use middle::trans::type_::Type; use std::c_str::ToCStr; use std::hash; use std::hashmap::HashMap; -use std::io; use std::libc::c_uint; use std::vec; use std::local_data; @@ -3163,7 +3162,7 @@ pub fn trans_crate(sess: session::Session, // Translate the metadata. write_metadata(ccx, &crate); if ccx.sess.trans_stats() { - io::println("--- trans stats ---"); + println("--- trans stats ---"); println!("n_static_tydescs: {}", ccx.stats.n_static_tydescs); println!("n_glues_created: {}", ccx.stats.n_glues_created); println!("n_null_glues: {}", ccx.stats.n_null_glues); @@ -3173,7 +3172,7 @@ pub fn trans_crate(sess: session::Session, println!("n_monos: {}", ccx.stats.n_monos); println!("n_inlines: {}", ccx.stats.n_inlines); println!("n_closures: {}", ccx.stats.n_closures); - io::println("fn stats:"); + println("fn stats:"); do sort::quick_sort(ccx.stats.fn_stats) |&(_, _, insns_a), &(_, _, insns_b)| { insns_a > insns_b } diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index ecf45d5c424cc..ce50397d00322 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -36,7 +36,8 @@ use driver::session; use middle::lint; use std::comm; -use std::io; +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; use std::num; use std::os; use std::result; @@ -181,7 +182,7 @@ Available lint options: lint::level_to_str(spec.default), spec.desc); } - io::println(""); + println(""); } pub fn describe_debug_flags() { @@ -247,7 +248,7 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) { 1u => { let ifile = matches.free[0].as_slice(); if "-" == ifile { - let src = str::from_utf8(io::stdin().read_whole_stream()); + let src = str::from_utf8(io::stdin().read_to_end()); str_input(src.to_managed()) } else { file_input(Path::new(ifile)) @@ -275,7 +276,7 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) { if ls { match input { file_input(ref ifile) => { - list_metadata(sess, &(*ifile), io::stdout()); + list_metadata(sess, &(*ifile), @mut io::stdout() as @mut io::Writer); } str_input(_) => { early_error(demitter, "can not list metadata for stdin"); diff --git a/src/librustdoc/rustdoc.rs b/src/librustdoc/rustdoc.rs index 4c53fe48fe15c..c0fab1ad98f2f 100644 --- a/src/librustdoc/rustdoc.rs +++ b/src/librustdoc/rustdoc.rs @@ -28,6 +28,9 @@ use std::local_data; use std::rt::io::Writer; use std::rt::io::file::FileInfo; use std::rt::io; +use std::rt::io::mem::MemWriter; +use std::rt::io::Decorator; +use std::str; use extra::getopts; use extra::getopts::groups; use extra::json; @@ -257,11 +260,11 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output { /// This input format purely deserializes the json output file. No passes are /// run over the deserialized output. fn json_input(input: &str) -> Result { - let input = match ::std::io::file_reader(&Path::new(input)) { - Ok(i) => i, - Err(s) => return Err(s), + let input = match Path::new(input).open_reader(io::Open) { + Some(f) => f, + None => return Err(format!("couldn't open {} for reading", input)), }; - match json::from_reader(input) { + match json::from_reader(@mut input as @mut io::Reader) { Err(s) => Err(s.to_str()), Ok(json::Object(obj)) => { let mut obj = obj; @@ -306,8 +309,10 @@ fn json_output(crate: clean::Crate, res: ~[plugins::PluginJson], dst: Path) { // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode // straight to the Rust JSON representation. - let crate_json_str = do std::io::with_str_writer |w| { - crate.encode(&mut json::Encoder(w)); + let crate_json_str = { + let w = @mut MemWriter::new(); + crate.encode(&mut json::Encoder(w as @mut io::Writer)); + str::from_utf8(*w.inner_ref()) }; let crate_json = match json::from_str(crate_json_str) { Ok(j) => j, diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index 72197219fc5ae..bee21d70b2d87 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -10,7 +10,7 @@ // Context data structure used by rustpkg -use std::{io, os}; +use std::os; use extra::workcache; use rustc::driver::session::{OptLevel, No}; @@ -243,43 +243,43 @@ pub fn flags_forbidden_for_cmd(flags: &RustcFlags, }; if flags.linker.is_some() && cmd != "build" && cmd != "install" { - io::println("The --linker option can only be used with the build or install commands."); + println("The --linker option can only be used with the build or install commands."); return true; } if flags.link_args.is_some() && cmd != "build" && cmd != "install" { - io::println("The --link-args option can only be used with the build or install commands."); + println("The --link-args option can only be used with the build or install commands."); return true; } if !cfgs.is_empty() && cmd != "build" && cmd != "install" { - io::println("The --cfg option can only be used with the build or install commands."); + println("The --cfg option can only be used with the build or install commands."); return true; } if user_supplied_opt_level && cmd != "build" && cmd != "install" { - io::println("The -O and --opt-level options can only be used with the build \ + println("The -O and --opt-level options can only be used with the build \ or install commands."); return true; } if flags.save_temps && cmd != "build" && cmd != "install" { - io::println("The --save-temps option can only be used with the build \ + println("The --save-temps option can only be used with the build \ or install commands."); return true; } if flags.target.is_some() && cmd != "build" && cmd != "install" { - io::println("The --target option can only be used with the build \ + println("The --target option can only be used with the build \ or install commands."); return true; } if flags.target_cpu.is_some() && cmd != "build" && cmd != "install" { - io::println("The --target-cpu option can only be used with the build \ + println("The --target-cpu option can only be used with the build \ or install commands."); return true; } if flags.experimental_features.is_some() && cmd != "build" && cmd != "install" { - io::println("The -Z option can only be used with the build or install commands."); + println("The -Z option can only be used with the build or install commands."); return true; } diff --git a/src/librustpkg/messages.rs b/src/librustpkg/messages.rs index 96c99a7a0f17e..79c8ff794ab56 100644 --- a/src/librustpkg/messages.rs +++ b/src/librustpkg/messages.rs @@ -9,31 +9,38 @@ // except according to those terms. use extra::term; -use std::io; +use std::rt::io; pub fn note(msg: &str) { - pretty_message(msg, "note: ", term::color::GREEN, io::stdout()) + pretty_message(msg, "note: ", term::color::GREEN, + @mut io::stdout() as @mut io::Writer) } pub fn warn(msg: &str) { - pretty_message(msg, "warning: ", term::color::YELLOW, io::stdout()) + pretty_message(msg, "warning: ", term::color::YELLOW, + @mut io::stdout() as @mut io::Writer) } pub fn error(msg: &str) { - pretty_message(msg, "error: ", term::color::RED, io::stdout()) + pretty_message(msg, "error: ", term::color::RED, + @mut io::stdout() as @mut io::Writer) } -fn pretty_message<'a>(msg: &'a str, prefix: &'a str, color: term::color::Color, out: @io::Writer) { +fn pretty_message<'a>(msg: &'a str, + prefix: &'a str, + color: term::color::Color, + out: @mut io::Writer) { let term = term::Terminal::new(out); match term { Ok(ref t) => { t.fg(color); - out.write_str(prefix); + out.write(prefix.as_bytes()); t.reset(); }, _ => { - out.write_str(prefix); + out.write(prefix.as_bytes()); } } - out.write_line(msg); + out.write(msg.as_bytes()); + out.write(['\n' as u8]); } diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index 2c1fdccd13c7e..bd3a1b2f67282 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -24,7 +24,7 @@ extern mod extra; extern mod rustc; extern mod syntax; -use std::{io, os, result, run, str, task}; +use std::{os, result, run, str, task}; pub use std::path::Path; use extra::workcache; @@ -346,7 +346,7 @@ impl CtxMethods for BuildContext { } } "list" => { - io::println("Installed packages:"); + println("Installed packages:"); do installed_packages::list_installed_packages |pkg_id| { do pkg_id.path.display().with_str |s| { println(s); @@ -726,7 +726,7 @@ impl CtxMethods for BuildContext { } pub fn main() { - io::println("WARNING: The Rust package manager is experimental and may be unstable"); + println("WARNING: The Rust package manager is experimental and may be unstable"); os::set_exit_status(main_args(os::args())); } diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index 9a571e0757084..c3e4205dfc972 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -10,7 +10,7 @@ // Utils for working with version control repositories. Just git right now. -use std::{io, os, run, str}; +use std::{os, run, str}; use std::run::{ProcessOutput, ProcessOptions, Process}; use extra::tempfile::TempDir; use version::*; @@ -36,8 +36,8 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult source.as_str().unwrap().to_owned(), target.as_str().unwrap().to_owned()]); if outp.status != 0 { - io::println(str::from_utf8_owned(outp.output.clone())); - io::println(str::from_utf8_owned(outp.error)); + println(str::from_utf8_owned(outp.output.clone())); + println(str::from_utf8_owned(outp.error)); return DirToUse(target.clone()); } else { @@ -52,8 +52,8 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()), ~"checkout", format!("{}", *s)]); if outp.status != 0 { - io::println(str::from_utf8_owned(outp.output.clone())); - io::println(str::from_utf8_owned(outp.error)); + println(str::from_utf8_owned(outp.output.clone())); + println(str::from_utf8_owned(outp.error)); return DirToUse(target.clone()); } } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 16e13f7009212..ce5e81d410923 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -11,7 +11,10 @@ // rustpkg unit tests use context::{BuildContext, Context, RustcFlags}; -use std::{io, os, run, str, task}; +use std::{os, run, str, task}; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::file::FileInfo; use extra::arc::Arc; use extra::arc::RWArc; use extra::tempfile::TempDir; @@ -81,8 +84,9 @@ fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId { } fn writeFile(file_path: &Path, contents: &str) { - let out = io::file_writer(file_path, [io::Create, io::Truncate]).unwrap(); - out.write_line(contents); + let mut out = file_path.open_writer(io::CreateOrTruncate); + out.write(contents.as_bytes()); + out.write(['\n' as u8]); } fn mk_emptier_workspace(tag: &str) -> TempDir { @@ -550,10 +554,11 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) { debug!("Frobbed? {:?}", maybe_p); match maybe_p { Some(ref p) => { - let w = io::file_writer(p, &[io::Append]); - match w { - Err(s) => { let _ = cond.raise((p.clone(), format!("Bad path: {}", s))); } - Ok(w) => w.write_line("/* hi */") + do io::io_error::cond.trap(|e| { + cond.raise((p.clone(), format!("Bad path: {}", e.desc))); + }).inside { + let mut w = p.open_writer(io::Append); + w.write(bytes!("/* hi */\n")); } } None => fail!("frob_source_file failed to find a source file in {}", diff --git a/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs b/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs index 0fd68ca3a2042..6c9a63fe7bd8a 100644 --- a/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs +++ b/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs @@ -15,8 +15,6 @@ The test runner should check that, after `rustpkg build hello-world`: * testsuite/hello-world/build/ does not contain a library */ -use std::io; - fn main() { - io::println(~"Hello world!"); + println(~"Hello world!"); } diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs index b667dc0a576fd..016635339a9d9 100644 --- a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs @@ -11,7 +11,7 @@ extern mod rustpkg; extern mod rustc; -use std::{io, os, task}; +use std::{os, task}; use rustpkg::api; use rustpkg::version::NoVersion; use rustpkg::workcache_support::digest_file_with_date; @@ -36,7 +36,7 @@ pub fn main() { } if args[2] != ~"install" { - io::println(format!("Warning: I don't know how to {}", args[2])); + println(format!("Warning: I don't know how to {}", args[2])); return; } diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs index 0b838b3e0f9e3..f82c585b1d156 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs @@ -11,7 +11,10 @@ extern mod rustpkg; extern mod rustc; -use std::{io, os}; +use std::os; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::file::FileInfo; use rustpkg::api; use rustpkg::version::NoVersion; @@ -42,9 +45,9 @@ pub fn main() { let out_path = os::self_exe_path().expect("Couldn't get self_exe path"); debug!("Writing file"); - let file = io::file_writer(&out_path.join("generated.rs"), [io::Create]).unwrap(); - file.write_str("pub fn wheeeee() { let xs = [1, 2, 3]; \ - for _ in xs.iter() { assert!(true); } }"); + let mut file = out_path.join("generated.rs").open_writer(io::Create); + file.write("pub fn wheeeee() { let xs = [1, 2, 3]; \ + for _ in xs.iter() { assert!(true); } }".as_bytes()); let context = api::default_context(sysroot, api::default_workspace()); api::install_pkg(&context, os::getcwd(), ~"fancy-lib", NoVersion, ~[]); diff --git a/src/librustpkg/testsuite/pass/src/hello-world/main.rs b/src/librustpkg/testsuite/pass/src/hello-world/main.rs index c8b2ce97c0c00..d4c65954fe629 100644 --- a/src/librustpkg/testsuite/pass/src/hello-world/main.rs +++ b/src/librustpkg/testsuite/pass/src/hello-world/main.rs @@ -18,8 +18,6 @@ The test runner should check that, after `rustpkg build hello-world`: * testsuite/pass/hello-world/build is empty */ -use std::io; - fn main() { - io::println(~"Hello world!"); + println(~"Hello world!"); } diff --git a/src/librustpkg/usage.rs b/src/librustpkg/usage.rs index 4b10451c81363..ef6ac485b7294 100644 --- a/src/librustpkg/usage.rs +++ b/src/librustpkg/usage.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; - pub fn general() { - io::println("Usage: rustpkg [options] [args..] + println("Usage: rustpkg [options] [args..] Where is one of: build, clean, do, info, install, list, prefer, test, uninstall, unprefer @@ -24,7 +22,7 @@ Options: } pub fn build() { - io::println("rustpkg build [options..] [package-ID] + println("rustpkg build [options..] [package-ID] Build the given package ID if specified. With no package ID argument, build the package in the current directory. In that case, the current @@ -50,21 +48,21 @@ Options: } pub fn clean() { - io::println("rustpkg clean + println("rustpkg clean Remove all build files in the work cache for the package in the current directory."); } pub fn do_cmd() { - io::println("rustpkg do + println("rustpkg do Runs a command in the package script. You can listen to a command by tagging a function with the attribute `#[pkg_do(cmd)]`."); } pub fn info() { - io::println("rustpkg [options..] info + println("rustpkg [options..] info Probe the package script in the current directory for information. @@ -73,13 +71,13 @@ Options: } pub fn list() { - io::println("rustpkg list + println("rustpkg list List all installed packages."); } pub fn install() { - io::println("rustpkg install [options..] [package-ID] + println("rustpkg install [options..] [package-ID] Install the given package ID if specified. With no package ID argument, install the package in the current directory. @@ -105,14 +103,14 @@ Options: } pub fn uninstall() { - io::println("rustpkg uninstall [@version] + println("rustpkg uninstall [@version] Remove a package by id or name and optionally version. If the package(s) is/are depended on by another package then they cannot be removed."); } pub fn prefer() { - io::println("rustpkg [options..] prefer [@version] + println("rustpkg [options..] prefer [@version] By default all binaries are given a unique name so that multiple versions can coexist. The prefer command will symlink the uniquely named binary to @@ -130,7 +128,7 @@ Example: } pub fn unprefer() { - io::println("rustpkg [options..] unprefer [@version] + println("rustpkg [options..] unprefer [@version] Remove all symlinks from the store to the binary directory for a package name and optionally version. If version is not supplied, the latest version @@ -139,7 +137,7 @@ information."); } pub fn test() { - io::println("rustpkg [options..] test + println("rustpkg [options..] test Build all test crates in the current directory with the test flag. Then, run all the resulting test executables, redirecting the output @@ -150,7 +148,7 @@ Options: } pub fn init() { - io::println("rustpkg init + println("rustpkg init This will turn the current working directory into a workspace. The first command you run when starting off a new project. diff --git a/src/librustpkg/workcache_support.rs b/src/librustpkg/workcache_support.rs index d49a581e07047..b68e42d8ebe24 100644 --- a/src/librustpkg/workcache_support.rs +++ b/src/librustpkg/workcache_support.rs @@ -8,21 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::file::FileInfo; + use extra::sha1::Sha1; use extra::digest::Digest; use extra::workcache; -use std::io; /// Hashes the file contents along with the last-modified time pub fn digest_file_with_date(path: &Path) -> ~str { use conditions::bad_path::cond; use cond1 = conditions::bad_stat::cond; - let s = io::read_whole_file_str(path); - match s { - Ok(s) => { + let mut err = None; + let bytes = do io::io_error::cond.trap(|e| err = Some(e)).inside { + path.open_reader(io::Open).read_to_end() + }; + match err { + None => { let mut sha = Sha1::new(); - sha.input_str(s); + sha.input(bytes); let st = match path.stat() { Some(st) => st, None => cond1.raise((path.clone(), format!("Couldn't get file access time"))) @@ -30,11 +36,9 @@ pub fn digest_file_with_date(path: &Path) -> ~str { sha.input_str(st.modified.to_str()); sha.result_str() } - Err(e) => { - let path = cond.raise((path.clone(), format!("Couldn't read file: {}", e))); - // FIXME (#9639): This needs to handle non-utf8 paths - // XXX: I'm pretty sure this is the wrong return value - path.as_str().unwrap().to_owned() + Some(e) => { + cond.raise((path.clone(), format!("Couldn't read file: {}", e.desc))); + ~"" } } } diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index acfa02a4defd5..b2e68c8d20fa7 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -348,12 +348,57 @@ impl<'self> Iterator for CStringIterator<'self> { } } +/// Parses a C "multistring", eg windows env values or +/// the req->ptr result in a uv_fs_readdir() call. +/// +/// Optionally, a `count` can be passed in, limiting the +/// parsing to only being done `count`-times. +/// +/// The specified closure is invoked with each string that +/// is found, and the number of strings found is returned. +pub unsafe fn from_c_multistring(buf: *libc::c_char, + count: Option, + f: &fn(&CString)) -> uint { + + let mut curr_ptr: uint = buf as uint; + let mut ctr = 0; + let (limited_count, limit) = match count { + Some(limit) => (true, limit), + None => (false, 0) + }; + while ((limited_count && ctr < limit) || !limited_count) + && *(curr_ptr as *libc::c_char) != 0 as libc::c_char { + let cstr = CString::new(curr_ptr as *libc::c_char, false); + f(&cstr); + curr_ptr += cstr.len() + 1; + ctr += 1; + } + return ctr; +} + #[cfg(test)] mod tests { use super::*; use libc; use ptr; use option::{Some, None}; + use vec; + + #[test] + fn test_str_multistring_parsing() { + unsafe { + let input = bytes!("zero", "\x00", "one", "\x00", "\x00"); + let ptr = vec::raw::to_ptr(input); + let expected = ["zero", "one"]; + let mut it = expected.iter(); + let result = do from_c_multistring(ptr as *libc::c_char, None) |c| { + let cbytes = c.as_bytes().slice_to(c.len()); + assert_eq!(cbytes, it.next().unwrap().as_bytes()); + }; + assert_eq!(result, 2); + assert!(it.next().is_none()); + } + } #[test] fn test_str_to_c_str() { diff --git a/src/libstd/io.rs b/src/libstd/io.rs deleted file mode 100644 index 4e55c5fe60eb5..0000000000000 --- a/src/libstd/io.rs +++ /dev/null @@ -1,2181 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -The `io` module contains basic input and output routines. - -A quick summary: - -## `Reader` and `Writer` traits - -These traits define the minimal set of methods that anything that can do -input and output should implement. - -## `ReaderUtil` and `WriterUtil` traits - -Richer methods that allow you to do more. `Reader` only lets you read a certain -number of bytes into a buffer, while `ReaderUtil` allows you to read a whole -line, for example. - -Generally, these richer methods are probably the ones you want to actually -use in day-to-day Rust. - -Furthermore, because there is an implementation of `ReaderUtil` for -``, when your input or output code implements `Reader`, you get -all of these methods for free. - -## `print` and `println` - -These very useful functions are defined here. You generally don't need to -import them, though, as the prelude already does. - -## `stdin`, `stdout`, and `stderr` - -These functions return references to the classic three file descriptors. They -implement `Reader` and `Writer`, where appropriate. - -*/ - -#[allow(missing_doc)]; - -use cast; -use cast::transmute; -use clone::Clone; -use c_str::ToCStr; -use container::Container; -use int; -use iter::Iterator; -use libc::consts::os::posix88::*; -use libc::{c_int, c_void, size_t}; -use libc; -use num; -use ops::Drop; -use option::{Some, None}; -use os; -use path::{Path,GenericPath}; -use ptr; -use result::{Result, Ok, Err}; -use str::{StrSlice, OwnedStr}; -use str; -use to_str::ToStr; -use uint; -use vec::{MutableVector, ImmutableVector, OwnedVector, OwnedCopyableVector, CopyableVector}; -use vec; - -#[allow(non_camel_case_types)] // not sure what to do about this -pub type fd_t = c_int; - -pub mod rustrt { - use libc; - - #[link_name = "rustrt"] - extern { - pub fn rust_get_stdin() -> *libc::FILE; - pub fn rust_get_stdout() -> *libc::FILE; - pub fn rust_get_stderr() -> *libc::FILE; - } -} - -// Reading - -// FIXME (#2004): This is all buffered. We might need an unbuffered variant -// as well -/** -* The SeekStyle enum describes the relationship between the position -* we'd like to seek to from our current position. It's used as an argument -* to the `seek` method defined on the `Reader` trait. -* -* There are three seek styles: -* -* 1. `SeekSet` means that the new position should become our position. -* 2. `SeekCur` means that we should seek from the current position. -* 3. `SeekEnd` means that we should seek from the end. -* -* # Examples -* -* None right now. -*/ -pub enum SeekStyle { SeekSet, SeekEnd, SeekCur, } - - -/** -* The core Reader trait. All readers must implement this trait. -* -* # Examples -* -* None right now. -*/ -pub trait Reader { - // FIXME (#2004): Seekable really should be orthogonal. - - // FIXME (#2982): This should probably return an error. - /** - * Reads bytes and puts them into `bytes`, advancing the cursor. Returns the - * number of bytes read. - * - * The number of bytes to be read is `len` or the end of the file, - * whichever comes first. - * - * The buffer must be at least `len` bytes long. - * - * `read` is conceptually similar to C's `fread` function. - * - * # Examples - * - * None right now. - */ - fn read(&self, bytes: &mut [u8], len: uint) -> uint; - - /** - * Reads a single byte, advancing the cursor. - * - * In the case of an EOF or an error, returns a negative value. - * - * `read_byte` is conceptually similar to C's `getc` function. - * - * # Examples - * - * None right now. - */ - fn read_byte(&self) -> int; - - /** - * Returns a boolean value: are we currently at EOF? - * - * Note that stream position may be already at the end-of-file point, - * but `eof` returns false until an attempt to read at that position. - * - * `eof` is conceptually similar to C's `feof` function. - * - * # Examples - * - * None right now. - */ - fn eof(&self) -> bool; - - /** - * Seek to a given `position` in the stream. - * - * Takes an optional SeekStyle, which affects how we seek from the - * position. See `SeekStyle` docs for more details. - * - * `seek` is conceptually similar to C's `fseek` function. - * - * # Examples - * - * None right now. - */ - fn seek(&self, position: int, style: SeekStyle); - - /** - * Returns the current position within the stream. - * - * `tell` is conceptually similar to C's `ftell` function. - * - * # Examples - * - * None right now. - */ - fn tell(&self) -> uint; -} - -impl Reader for @Reader { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - self.read(bytes, len) - } - fn read_byte(&self) -> int { - self.read_byte() - } - fn eof(&self) -> bool { - self.eof() - } - fn seek(&self, position: int, style: SeekStyle) { - self.seek(position, style) - } - fn tell(&self) -> uint { - self.tell() - } -} - -/** -* The `ReaderUtil` trait is a home for many of the utility functions -* a particular Reader should implement. -* -* The default `Reader` trait is focused entirely on bytes. `ReaderUtil` is based -* on higher-level concepts like 'chars' and 'lines.' -* -* # Examples: -* -* None right now. -*/ -pub trait ReaderUtil { - - /** - * Reads `len` number of bytes, and gives you a new vector back. - * - * # Examples - * - * None right now. - */ - fn read_bytes(&self, len: uint) -> ~[u8]; - - /** - * Reads up until a specific byte is seen or EOF. - * - * The `include` parameter specifies if the character should be included - * in the returned string. - * - * # Examples - * - * None right now. - */ - fn read_until(&self, c: u8, include: bool) -> ~str; - - /** - * Reads up until the first '\n' or EOF. - * - * The '\n' is not included in the result. - * - * # Examples - * - * None right now. - */ - fn read_line(&self) -> ~str; - - /** - * Reads `n` chars. - * - * Assumes that those chars are UTF-8 encoded. - * - * The '\n' is not included in the result. - * - * # Examples - * - * None right now. - */ - fn read_chars(&self, n: uint) -> ~[char]; - - /** - * Reads a single UTF-8 encoded char. - * - * # Examples - * - * None right now. - */ - fn read_char(&self) -> char; - - /** - * Reads up until the first null byte or EOF. - * - * The null byte is not returned. - * - * # Examples - * - * None right now. - */ - fn read_c_str(&self) -> ~str; - - /** - * Reads all remaining data in the stream. - * - * # Examples - * - * None right now. - */ - fn read_whole_stream(&self) -> ~[u8]; - - /** - * Iterate over every byte until EOF or the iterator breaks. - * - * # Examples - * - * None right now. - */ - fn each_byte(&self, it: &fn(int) -> bool) -> bool; - - /** - * Iterate over every char until EOF or the iterator breaks. - * - * # Examples - * - * None right now. - */ - fn each_char(&self, it: &fn(char) -> bool) -> bool; - - /** - * Iterate over every line until EOF or the iterator breaks. - * - * # Examples - * - * None right now. - */ - fn each_line(&self, it: &fn(&str) -> bool) -> bool; - - /** - * Reads all of the lines in the stream. - * - * Returns a vector of those lines. - * - * # Examples - * - * None right now. - */ - fn read_lines(&self) -> ~[~str]; - - /** - * Reads `n` little-endian unsigned integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_le_uint_n(&self, nbytes: uint) -> u64; - - /** - * Reads `n` little-endian signed integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_le_int_n(&self, nbytes: uint) -> i64; - - /** - * Reads `n` big-endian unsigned integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_be_uint_n(&self, nbytes: uint) -> u64; - - /** - * Reads `n` big-endian signed integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_be_int_n(&self, nbytes: uint) -> i64; - - /** - * Reads a little-endian unsigned integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_le_uint(&self) -> uint; - - /** - * Reads a little-endian integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_le_int(&self) -> int; - - /** - * Reads a big-endian unsigned integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_be_uint(&self) -> uint; - - /** - * Reads a big-endian integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_be_int(&self) -> int; - - /** - * Reads a big-endian `u64`. - * - * `u64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_u64(&self) -> u64; - - /** - * Reads a big-endian `u32`. - * - * `u32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_u32(&self) -> u32; - - /** - * Reads a big-endian `u16`. - * - * `u16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_u16(&self) -> u16; - - /** - * Reads a big-endian `i64`. - * - * `i64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_i64(&self) -> i64; - - /** - * Reads a big-endian `i32`. - * - * `i32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_i32(&self) -> i32; - - /** - * Reads a big-endian `i16`. - * - * `i16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_i16(&self) -> i16; - - /** - * Reads a big-endian `f64`. - * - * `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_be_f64(&self) -> f64; - - /** - * Reads a big-endian `f32`. - * - * `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_be_f32(&self) -> f32; - - /** - * Reads a little-endian `u64`. - * - * `u64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_u64(&self) -> u64; - - /** - * Reads a little-endian `u32`. - * - * `u32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_u32(&self) -> u32; - - /** - * Reads a little-endian `u16`. - * - * `u16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_u16(&self) -> u16; - - /** - * Reads a little-endian `i64`. - * - * `i64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_i64(&self) -> i64; - - /** - * Reads a little-endian `i32`. - * - * `i32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_i32(&self) -> i32; - - /** - * Reads a little-endian `i16`. - * - * `i16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_i16(&self) -> i16; - - /** - * Reads a little-endian `f64`. - * - * `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_le_f64(&self) -> f64; - - /** - * Reads a little-endian `f32`. - * - * `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_le_f32(&self) -> f32; - - /** - * Read a u8. - * - * `u8`s are 1 byte. - * - * # Examples - * - * None right now. - */ - fn read_u8(&self) -> u8; - - /** - * Read an i8. - * - * `i8`s are 1 byte. - * - * # Examples - * - * None right now. - */ - fn read_i8(&self) -> i8; -} - -impl ReaderUtil for T { - - fn read_bytes(&self, len: uint) -> ~[u8] { - let mut bytes = vec::with_capacity(len); - unsafe { vec::raw::set_len(&mut bytes, len); } - - let count = self.read(bytes, len); - - unsafe { vec::raw::set_len(&mut bytes, count); } - bytes - } - - fn read_until(&self, c: u8, include: bool) -> ~str { - let mut bytes = ~[]; - loop { - let ch = self.read_byte(); - if ch == -1 || ch == c as int { - if include && ch == c as int { - bytes.push(ch as u8); - } - break; - } - bytes.push(ch as u8); - } - str::from_utf8(bytes) - } - - fn read_line(&self) -> ~str { - self.read_until('\n' as u8, false) - } - - fn read_chars(&self, n: uint) -> ~[char] { - // returns the (consumed offset, n_req), appends characters to &chars - fn chars_from_utf8(bytes: &~[u8], chars: &mut ~[char]) - -> (uint, uint) { - let mut i = 0; - let bytes_len = bytes.len(); - while i < bytes_len { - let b0 = bytes[i]; - let w = str::utf8_char_width(b0); - let end = i + w; - i += 1; - assert!((w > 0)); - if w == 1 { - unsafe { - chars.push(transmute(b0 as u32)); - } - continue; - } - // can't satisfy this char with the existing data - if end > bytes_len { - return (i - 1, end - bytes_len); - } - let mut val = 0; - while i < end { - let next = bytes[i] as int; - i += 1; - assert!((next > -1)); - assert_eq!(next & 192, 128); - val <<= 6; - val += (next & 63) as uint; - } - // See str::StrSlice::char_at - val += ((b0 << ((w + 1) as u8)) as uint) - << (w - 1) * 6 - w - 1u; - unsafe { - chars.push(transmute(val as u32)); - } - } - return (i, 0); - } - let mut bytes = ~[]; - let mut chars = ~[]; - // might need more bytes, but reading n will never over-read - let mut nbread = n; - while nbread > 0 { - let data = self.read_bytes(nbread); - if data.is_empty() { - // eof - FIXME (#2004): should we do something if - // we're split in a unicode char? - break; - } - bytes.push_all(data); - let (offset, nbreq) = chars_from_utf8::(&bytes, &mut chars); - let ncreq = n - chars.len(); - // again we either know we need a certain number of bytes - // to complete a character, or we make sure we don't - // over-read by reading 1-byte per char needed - nbread = if ncreq > nbreq { ncreq } else { nbreq }; - if nbread > 0 { - bytes = bytes.slice(offset, bytes.len()).to_owned(); - } - } - chars - } - - fn read_char(&self) -> char { - let c = self.read_chars(1); - if c.len() == 0 { - return unsafe { transmute(-1u32) }; // FIXME: #8971: unsound - } - assert_eq!(c.len(), 1); - return c[0]; - } - - fn read_c_str(&self) -> ~str { - self.read_until(0u8, false) - } - - fn read_whole_stream(&self) -> ~[u8] { - let mut bytes: ~[u8] = ~[]; - while !self.eof() { bytes.push_all(self.read_bytes(2048u)); } - bytes - } - - fn each_byte(&self, it: &fn(int) -> bool) -> bool { - loop { - match self.read_byte() { - -1 => break, - ch => if !it(ch) { return false; } - } - } - return true; - } - - fn each_char(&self, it: &fn(char) -> bool) -> bool { - // FIXME: #8971: unsound - let eof: char = unsafe { transmute(-1u32) }; - loop { - match self.read_char() { - c if c == eof => break, - ch => if !it(ch) { return false; } - } - } - return true; - } - - fn each_line(&self, it: &fn(s: &str) -> bool) -> bool { - while !self.eof() { - // include the \n, so that we can distinguish an entirely empty - // line read after "...\n", and the trailing empty line in - // "...\n\n". - let mut line = self.read_until('\n' as u8, true); - - // blank line at the end of the reader is ignored - if self.eof() && line.is_empty() { break; } - - // trim the \n, so that each_line is consistent with read_line - let n = line.len(); - if line[n-1] == '\n' as u8 { - unsafe { str::raw::set_len(&mut line, n-1); } - } - - if !it(line) { return false; } - } - return true; - } - - fn read_lines(&self) -> ~[~str] { - do vec::build(None) |push| { - do self.each_line |line| { - push(line.to_owned()); - true - }; - } - } - - // FIXME int reading methods need to deal with eof - issue #2004 - - fn read_le_uint_n(&self, nbytes: uint) -> u64 { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0u64; - let mut pos = 0; - let mut i = nbytes; - while i > 0 { - val += (self.read_u8() as u64) << pos; - pos += 8; - i -= 1; - } - val - } - - fn read_le_int_n(&self, nbytes: uint) -> i64 { - extend_sign(self.read_le_uint_n(nbytes), nbytes) - } - - fn read_be_uint_n(&self, nbytes: uint) -> u64 { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0u64; - let mut i = nbytes; - while i > 0 { - i -= 1; - val += (self.read_u8() as u64) << i * 8; - } - val - } - - fn read_be_int_n(&self, nbytes: uint) -> i64 { - extend_sign(self.read_be_uint_n(nbytes), nbytes) - } - - fn read_le_uint(&self) -> uint { - self.read_le_uint_n(uint::bytes) as uint - } - - fn read_le_int(&self) -> int { - self.read_le_int_n(int::bytes) as int - } - - fn read_be_uint(&self) -> uint { - self.read_be_uint_n(uint::bytes) as uint - } - - fn read_be_int(&self) -> int { - self.read_be_int_n(int::bytes) as int - } - - fn read_be_u64(&self) -> u64 { - self.read_be_uint_n(8) as u64 - } - - fn read_be_u32(&self) -> u32 { - self.read_be_uint_n(4) as u32 - } - - fn read_be_u16(&self) -> u16 { - self.read_be_uint_n(2) as u16 - } - - fn read_be_i64(&self) -> i64 { - self.read_be_int_n(8) as i64 - } - - fn read_be_i32(&self) -> i32 { - self.read_be_int_n(4) as i32 - } - - fn read_be_i16(&self) -> i16 { - self.read_be_int_n(2) as i16 - } - - fn read_be_f64(&self) -> f64 { - unsafe { - cast::transmute::(self.read_be_u64()) - } - } - - fn read_be_f32(&self) -> f32 { - unsafe { - cast::transmute::(self.read_be_u32()) - } - } - - fn read_le_u64(&self) -> u64 { - self.read_le_uint_n(8) as u64 - } - - fn read_le_u32(&self) -> u32 { - self.read_le_uint_n(4) as u32 - } - - fn read_le_u16(&self) -> u16 { - self.read_le_uint_n(2) as u16 - } - - fn read_le_i64(&self) -> i64 { - self.read_le_int_n(8) as i64 - } - - fn read_le_i32(&self) -> i32 { - self.read_le_int_n(4) as i32 - } - - fn read_le_i16(&self) -> i16 { - self.read_le_int_n(2) as i16 - } - - fn read_le_f64(&self) -> f64 { - unsafe { - cast::transmute::(self.read_le_u64()) - } - } - - fn read_le_f32(&self) -> f32 { - unsafe { - cast::transmute::(self.read_le_u32()) - } - } - - fn read_u8(&self) -> u8 { - self.read_byte() as u8 - } - - fn read_i8(&self) -> i8 { - self.read_byte() as i8 - } -} - -fn extend_sign(val: u64, nbytes: uint) -> i64 { - let shift = (8 - nbytes) * 8; - (val << shift) as i64 >> shift -} - -// Reader implementations - -fn convert_whence(whence: SeekStyle) -> i32 { - return match whence { - SeekSet => 0i32, - SeekCur => 1i32, - SeekEnd => 2i32 - }; -} - -impl Reader for *libc::FILE { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - do bytes.as_mut_buf |buf_p, buf_len| { - assert!(buf_len >= len); - - let count = libc::fread(buf_p as *mut c_void, 1u as size_t, - len as size_t, *self) as uint; - if count < len { - match libc::ferror(*self) { - 0 => (), - _ => { - error!("error reading buffer: {}", os::last_os_error()); - fail!(); - } - } - } - - count - } - } - } - fn read_byte(&self) -> int { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::fgetc(*self) as int - } - } - fn eof(&self) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - return libc::feof(*self) != 0 as c_int; - } - } - fn seek(&self, offset: int, whence: SeekStyle) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - assert!(libc::fseek(*self, - offset as libc::c_long, - convert_whence(whence)) == 0 as c_int); - } - } - fn tell(&self) -> uint { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - return libc::ftell(*self) as uint; - } - } -} - -struct Wrapper { - base: T, - cleanup: C, -} - -// A forwarding impl of reader that also holds on to a resource for the -// duration of its lifetime. -// FIXME there really should be a better way to do this // #2004 -impl Reader for Wrapper { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - self.base.read(bytes, len) - } - fn read_byte(&self) -> int { self.base.read_byte() } - fn eof(&self) -> bool { self.base.eof() } - fn seek(&self, off: int, whence: SeekStyle) { - self.base.seek(off, whence) - } - fn tell(&self) -> uint { self.base.tell() } -} - -pub struct FILERes { - priv f: *libc::FILE, -} - -impl FILERes { - pub fn new(f: *libc::FILE) -> FILERes { - FILERes { f: f } - } -} - -impl Drop for FILERes { - fn drop(&mut self) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::fclose(self.f); - } - } -} - -pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> @Reader { - if cleanup { - @Wrapper { base: f, cleanup: FILERes::new(f) } as @Reader - } else { - @f as @Reader - } -} - -// FIXME (#2004): this should either be an trait-less impl, a set of -// top-level functions that take a reader, or a set of default methods on -// reader (which can then be called reader) - -/** -* Gives a `Reader` that allows you to read values from standard input. -* -* # Example -* -* ```rust -* let stdin = std::io::stdin(); -* let line = stdin.read_line(); -* std::io::print(line); -* ``` -*/ -pub fn stdin() -> @Reader { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - @rustrt::rust_get_stdin() as @Reader - } -} - -pub fn file_reader(path: &Path) -> Result<@Reader, ~str> { - #[fixed_stack_segment]; #[inline(never)]; - - let f = do path.with_c_str |pathbuf| { - do "rb".with_c_str |modebuf| { - unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) } - } - }; - - if f as uint == 0u { - do path.display().with_str |p| { - Err(~"error opening " + p) - } - } else { - Ok(FILE_reader(f, true)) - } -} - - -// Byte readers -pub struct BytesReader { - // FIXME(#5723) see other FIXME below - // FIXME(#7268) this should also be parameterized over <'self> - bytes: &'static [u8], - pos: @mut uint -} - -impl Reader for BytesReader { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - let count = num::min(len, self.bytes.len() - *self.pos); - - let view = self.bytes.slice(*self.pos, self.bytes.len()); - vec::bytes::copy_memory(bytes, view, count); - - *self.pos += count; - - count - } - - fn read_byte(&self) -> int { - if *self.pos == self.bytes.len() { - return -1; - } - - let b = self.bytes[*self.pos]; - *self.pos += 1u; - b as int - } - - fn eof(&self) -> bool { - *self.pos == self.bytes.len() - } - - fn seek(&self, offset: int, whence: SeekStyle) { - let pos = *self.pos; - *self.pos = seek_in_buf(offset, pos, self.bytes.len(), whence); - } - - fn tell(&self) -> uint { - *self.pos - } -} - -pub fn with_bytes_reader(bytes: &[u8], f: &fn(@Reader) -> T) -> T { - // XXX XXX XXX this is glaringly unsound - // FIXME(#5723) Use a &Reader for the callback's argument. Should be: - // fn with_bytes_reader<'r, T>(bytes: &'r [u8], f: &fn(&'r Reader) -> T) -> T - let bytes: &'static [u8] = unsafe { cast::transmute(bytes) }; - f(@BytesReader { - bytes: bytes, - pos: @mut 0 - } as @Reader) -} - -pub fn with_str_reader(s: &str, f: &fn(@Reader) -> T) -> T { - // FIXME(#5723): As above. - with_bytes_reader(s.as_bytes(), f) -} - -// Writing -pub enum FileFlag { Append, Create, Truncate, NoFlag, } - -// What type of writer are we? -#[deriving(Eq)] -pub enum WriterType { Screen, File } - -// FIXME (#2004): Seekable really should be orthogonal. -// FIXME (#2004): eventually u64 -/// The raw underlying writer trait. All writers must implement this. -pub trait Writer { - - /// Write all of the given bytes. - fn write(&self, v: &[u8]); - - /// Move the current position within the stream. The second parameter - /// determines the position that the first parameter is relative to. - fn seek(&self, int, SeekStyle); - - /// Return the current position within the stream. - fn tell(&self) -> uint; - - /// Flush the output buffer for this stream (if there is one). - fn flush(&self) -> int; - - /// Determine if this Writer is writing to a file or not. - fn get_type(&self) -> WriterType; -} - -impl Writer for @Writer { - fn write(&self, v: &[u8]) { self.write(v) } - fn seek(&self, a: int, b: SeekStyle) { self.seek(a, b) } - fn tell(&self) -> uint { self.tell() } - fn flush(&self) -> int { self.flush() } - fn get_type(&self) -> WriterType { self.get_type() } -} - -impl Writer for Wrapper { - fn write(&self, bs: &[u8]) { self.base.write(bs); } - fn seek(&self, off: int, style: SeekStyle) { self.base.seek(off, style); } - fn tell(&self) -> uint { self.base.tell() } - fn flush(&self) -> int { self.base.flush() } - fn get_type(&self) -> WriterType { File } -} - -impl Writer for *libc::FILE { - fn write(&self, v: &[u8]) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - do v.as_imm_buf |vbuf, len| { - let nout = libc::fwrite(vbuf as *c_void, - 1, - len as size_t, - *self); - if nout != len as size_t { - error!("error writing buffer: {}", os::last_os_error()); - fail!(); - } - } - } - } - fn seek(&self, offset: int, whence: SeekStyle) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - assert!(libc::fseek(*self, - offset as libc::c_long, - convert_whence(whence)) == 0 as c_int); - } - } - fn tell(&self) -> uint { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::ftell(*self) as uint - } - } - fn flush(&self) -> int { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::fflush(*self) as int - } - } - fn get_type(&self) -> WriterType { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - let fd = libc::fileno(*self); - if libc::isatty(fd) == 0 { File } - else { Screen } - } - } -} - -impl Writer for fd_t { - fn write(&self, v: &[u8]) { - #[fixed_stack_segment]; #[inline(never)]; - - #[cfg(windows)] - type IoSize = libc::c_uint; - #[cfg(windows)] - type IoRet = c_int; - - #[cfg(unix)] - type IoSize = size_t; - #[cfg(unix)] - type IoRet = libc::ssize_t; - - unsafe { - let mut count = 0u; - do v.as_imm_buf |vbuf, len| { - while count < len { - let vb = ptr::offset(vbuf, count as int) as *c_void; - let nout = libc::write(*self, vb, len as IoSize); - if nout < 0 as IoRet { - error!("error writing buffer: {}", os::last_os_error()); - fail!(); - } - count += nout as uint; - } - } - } - } - fn seek(&self, _offset: int, _whence: SeekStyle) { - error!("need 64-bit foreign calls for seek, sorry"); - fail!(); - } - fn tell(&self) -> uint { - error!("need 64-bit foreign calls for tell, sorry"); - fail!(); - } - fn flush(&self) -> int { 0 } - fn get_type(&self) -> WriterType { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - if libc::isatty(*self) == 0 { File } else { Screen } - } - } -} - -pub struct FdRes { - priv fd: fd_t, -} - -impl FdRes { - pub fn new(fd: fd_t) -> FdRes { - FdRes { fd: fd } - } -} - -impl Drop for FdRes { - fn drop(&mut self) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::close(self.fd); - } - } -} - -pub fn fd_writer(fd: fd_t, cleanup: bool) -> @Writer { - if cleanup { - @Wrapper { base: fd, cleanup: FdRes::new(fd) } as @Writer - } else { - @fd as @Writer - } -} - - -pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) - -> Result<@Writer, ~str> { - #[fixed_stack_segment]; #[inline(never)]; - - #[cfg(windows)] - fn wb() -> c_int { - (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int - } - - #[cfg(unix)] - fn wb() -> c_int { O_WRONLY as c_int } - - let mut fflags: c_int = wb(); - for f in flags.iter() { - match *f { - Append => fflags |= O_APPEND as c_int, - Create => fflags |= O_CREAT as c_int, - Truncate => fflags |= O_TRUNC as c_int, - NoFlag => () - } - } - let fd = unsafe { - do path.with_c_str |pathbuf| { - libc::open(pathbuf, fflags, (S_IRUSR | S_IWUSR) as c_int) - } - }; - if fd < (0 as c_int) { - Err(format!("error opening {}: {}", path.display(), os::last_os_error())) - } else { - Ok(fd_writer(fd, true)) - } -} - -pub fn u64_to_le_bytes(n: u64, size: uint, - f: &fn(v: &[u8]) -> T) -> T { - assert!(size <= 8u); - match size { - 1u => f(&[n as u8]), - 2u => f(&[n as u8, - (n >> 8) as u8]), - 4u => f(&[n as u8, - (n >> 8) as u8, - (n >> 16) as u8, - (n >> 24) as u8]), - 8u => f(&[n as u8, - (n >> 8) as u8, - (n >> 16) as u8, - (n >> 24) as u8, - (n >> 32) as u8, - (n >> 40) as u8, - (n >> 48) as u8, - (n >> 56) as u8]), - _ => { - - let mut bytes: ~[u8] = ~[]; - let mut i = size; - let mut n = n; - while i > 0u { - bytes.push((n & 255_u64) as u8); - n >>= 8_u64; - i -= 1u; - } - f(bytes) - } - } -} - -pub fn u64_to_be_bytes(n: u64, size: uint, - f: &fn(v: &[u8]) -> T) -> T { - assert!(size <= 8u); - match size { - 1u => f(&[n as u8]), - 2u => f(&[(n >> 8) as u8, - n as u8]), - 4u => f(&[(n >> 24) as u8, - (n >> 16) as u8, - (n >> 8) as u8, - n as u8]), - 8u => f(&[(n >> 56) as u8, - (n >> 48) as u8, - (n >> 40) as u8, - (n >> 32) as u8, - (n >> 24) as u8, - (n >> 16) as u8, - (n >> 8) as u8, - n as u8]), - _ => { - let mut bytes: ~[u8] = ~[]; - let mut i = size; - while i > 0u { - let shift = ((i - 1u) * 8u) as u64; - bytes.push((n >> shift) as u8); - i -= 1u; - } - f(bytes) - } - } -} - -pub fn u64_from_be_bytes(data: &[u8], - start: uint, - size: uint) - -> u64 { - let mut sz = size; - assert!((sz <= 8u)); - let mut val = 0_u64; - let mut pos = start; - while sz > 0u { - sz -= 1u; - val += (data[pos] as u64) << ((sz * 8u) as u64); - pos += 1u; - } - return val; -} - -// FIXME: #3048 combine trait+impl (or just move these to -// default methods on writer) -/// Generic utility functions defined on writers. -pub trait WriterUtil { - - /// Write a single utf-8 encoded char. - fn write_char(&self, ch: char); - - /// Write every char in the given str, encoded as utf-8. - fn write_str(&self, s: &str); - - /// Write the given str, as utf-8, followed by '\n'. - fn write_line(&self, s: &str); - - /// Write the result of passing n through `int::to_str_bytes`. - fn write_int(&self, n: int); - - /// Write the result of passing n through `uint::to_str_bytes`. - fn write_uint(&self, n: uint); - - /// Write a little-endian uint (number of bytes depends on system). - fn write_le_uint(&self, n: uint); - - /// Write a little-endian int (number of bytes depends on system). - fn write_le_int(&self, n: int); - - /// Write a big-endian uint (number of bytes depends on system). - fn write_be_uint(&self, n: uint); - - /// Write a big-endian int (number of bytes depends on system). - fn write_be_int(&self, n: int); - - /// Write a big-endian u64 (8 bytes). - fn write_be_u64(&self, n: u64); - - /// Write a big-endian u32 (4 bytes). - fn write_be_u32(&self, n: u32); - - /// Write a big-endian u16 (2 bytes). - fn write_be_u16(&self, n: u16); - - /// Write a big-endian i64 (8 bytes). - fn write_be_i64(&self, n: i64); - - /// Write a big-endian i32 (4 bytes). - fn write_be_i32(&self, n: i32); - - /// Write a big-endian i16 (2 bytes). - fn write_be_i16(&self, n: i16); - - /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - fn write_be_f64(&self, f: f64); - - /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - fn write_be_f32(&self, f: f32); - - /// Write a little-endian u64 (8 bytes). - fn write_le_u64(&self, n: u64); - - /// Write a little-endian u32 (4 bytes). - fn write_le_u32(&self, n: u32); - - /// Write a little-endian u16 (2 bytes). - fn write_le_u16(&self, n: u16); - - /// Write a little-endian i64 (8 bytes). - fn write_le_i64(&self, n: i64); - - /// Write a little-endian i32 (4 bytes). - fn write_le_i32(&self, n: i32); - - /// Write a little-endian i16 (2 bytes). - fn write_le_i16(&self, n: i16); - - /// Write a little-endian IEEE754 double-precision floating-point - /// (8 bytes). - fn write_le_f64(&self, f: f64); - - /// Write a little-endian IEEE754 single-precision floating-point - /// (4 bytes). - fn write_le_f32(&self, f: f32); - - /// Write a u8 (1 byte). - fn write_u8(&self, n: u8); - - /// Write a i8 (1 byte). - fn write_i8(&self, n: i8); -} - -impl WriterUtil for T { - fn write_char(&self, ch: char) { - if (ch as uint) < 128u { - self.write(&[ch as u8]); - } else { - self.write_str(str::from_char(ch)); - } - } - fn write_str(&self, s: &str) { self.write(s.as_bytes()) } - fn write_line(&self, s: &str) { - self.write_str(s); - self.write_str(&"\n"); - } - fn write_int(&self, n: int) { - int::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - fn write_uint(&self, n: uint) { - uint::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - fn write_le_uint(&self, n: uint) { - u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - fn write_le_int(&self, n: int) { - u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v)) - } - fn write_be_uint(&self, n: uint) { - u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - fn write_be_int(&self, n: int) { - u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v)) - } - fn write_be_u64(&self, n: u64) { - u64_to_be_bytes(n, 8u, |v| self.write(v)) - } - fn write_be_u32(&self, n: u32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_be_u16(&self, n: u16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_be_i64(&self, n: i64) { - u64_to_be_bytes(n as u64, 8u, |v| self.write(v)) - } - fn write_be_i32(&self, n: i32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_be_i16(&self, n: i16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_be_f64(&self, f:f64) { - unsafe { - self.write_be_u64(cast::transmute(f)) - } - } - fn write_be_f32(&self, f:f32) { - unsafe { - self.write_be_u32(cast::transmute(f)) - } - } - fn write_le_u64(&self, n: u64) { - u64_to_le_bytes(n, 8u, |v| self.write(v)) - } - fn write_le_u32(&self, n: u32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_le_u16(&self, n: u16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_le_i64(&self, n: i64) { - u64_to_le_bytes(n as u64, 8u, |v| self.write(v)) - } - fn write_le_i32(&self, n: i32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_le_i16(&self, n: i16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_le_f64(&self, f:f64) { - unsafe { - self.write_le_u64(cast::transmute(f)) - } - } - fn write_le_f32(&self, f:f32) { - unsafe { - self.write_le_u32(cast::transmute(f)) - } - } - - fn write_u8(&self, n: u8) { self.write([n]) } - fn write_i8(&self, n: i8) { self.write([n as u8]) } - -} - -pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> { - mk_file_writer(path, flags).and_then(|w| Ok(w)) -} - -// FIXME (#2004) it would be great if this could be a const -// FIXME (#2004) why are these different from the way stdin() is -// implemented? - - -/** -* Gives a `Writer` which allows you to write to the standard output. -* -* # Example -* -* ```rust -* let stdout = std::io::stdout(); -* stdout.write_str("hello\n"); -* ``` -*/ -pub fn stdout() -> @Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) } - -/** -* Gives a `Writer` which allows you to write to standard error. -* -* # Example -* -* ```rust -* let stderr = std::io::stderr(); -* stderr.write_str("hello\n"); -* ``` -*/ -pub fn stderr() -> @Writer { fd_writer(libc::STDERR_FILENO as c_int, false) } - -/** -* Prints a string to standard output. -* -* This string will not have an implicit newline at the end. If you want -* an implicit newline, please see `println`. -* -* # Example -* -* ```rust -* // print is imported into the prelude, and so is always available. -* print("hello"); -* ``` -*/ -pub fn print(s: &str) { - stdout().write_str(s); -} - -/** -* Prints a string to standard output, followed by a newline. -* -* If you do not want an implicit newline, please see `print`. -* -* # Example -* -* ```rust -* // println is imported into the prelude, and so is always available. -* println("hello"); -* ``` -*/ -pub fn println(s: &str) { - stdout().write_line(s); -} - -pub struct BytesWriter { - bytes: @mut ~[u8], - pos: @mut uint, -} - -impl BytesWriter { - pub fn new() -> BytesWriter { - BytesWriter { - bytes: @mut ~[], - pos: @mut 0 - } - } -} - -impl Writer for BytesWriter { - fn write(&self, v: &[u8]) { - let v_len = v.len(); - - let bytes = &mut *self.bytes; - let count = num::max(bytes.len(), *self.pos + v_len); - bytes.reserve(count); - - unsafe { - vec::raw::set_len(bytes, count); - - let view = bytes.mut_slice(*self.pos, count); - vec::bytes::copy_memory(view, v, v_len); - } - - *self.pos += v_len; - } - - fn seek(&self, offset: int, whence: SeekStyle) { - let pos = *self.pos; - let len = self.bytes.len(); - *self.pos = seek_in_buf(offset, pos, len, whence); - } - - fn tell(&self) -> uint { - *self.pos - } - - fn flush(&self) -> int { - 0 - } - - fn get_type(&self) -> WriterType { - File - } -} - -pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] { - let wr = @BytesWriter::new(); - f(wr as @Writer); - let @BytesWriter { bytes, _ } = wr; - (*bytes).clone() -} - -pub fn with_str_writer(f: &fn(@Writer)) -> ~str { - str::from_utf8(with_bytes_writer(f)) -} - -// Utility functions -pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) -> - uint { - let mut bpos = pos as int; - let blen = len as int; - match whence { - SeekSet => bpos = offset, - SeekCur => bpos += offset, - SeekEnd => bpos = blen + offset - } - if bpos < 0 { bpos = 0; } else if bpos > blen { bpos = blen; } - return bpos as uint; -} - -pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> { - do read_whole_file(file).and_then |bytes| { - if str::is_utf8(bytes) { - Ok(str::from_utf8(bytes)) - } else { - Err(file.display().to_str() + " is not UTF-8") - } - } -} - -// FIXME (#2004): implement this in a low-level way. Going through the -// abstractions is pointless. -pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> { - do file_reader(file).and_then |rdr| { - Ok(rdr.read_whole_stream()) - } -} - -// fsync related - -pub mod fsync { - use io::{FILERes, FdRes, fd_t}; - use libc; - use ops::Drop; - use option::{None, Option, Some}; - use os; - - pub enum Level { - // whatever fsync does on that platform - FSync, - - // fdatasync on linux, similiar or more on other platforms - FDataSync, - - // full fsync - // - // You must additionally sync the parent directory as well! - FullFSync, - } - - - // Artifacts that need to fsync on destruction - pub struct Res { - priv arg: Arg, - } - - impl Res { - pub fn new(arg: Arg) -> Res { - Res { arg: arg } - } - } - - #[unsafe_destructor] - impl Drop for Res { - fn drop(&mut self) { - match self.arg.opt_level { - None => (), - Some(level) => { - // fail hard if not succesful - assert!(((self.arg.fsync_fn)(&self.arg.val, level) != -1)); - } - } - } - } - - pub struct Arg { - priv val: t, - priv opt_level: Option, - priv fsync_fn: extern "Rust" fn(f: &t, Level) -> int, - } - - // fsync file after executing blk - // FIXME (#2004) find better way to create resources within lifetime of - // outer res - pub fn FILE_res_sync(file: &FILERes, - opt_level: Option, - blk: &fn(v: Res<*libc::FILE>)) { - blk(Res::new(Arg { - val: file.f, - opt_level: opt_level, - fsync_fn: fsync_FILE, - })); - - fn fileno(stream: *libc::FILE) -> libc::c_int { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { libc::fileno(stream) } - } - - fn fsync_FILE(stream: &*libc::FILE, level: Level) -> int { - fsync_fd(fileno(*stream), level) - } - } - - // fsync fd after executing blk - pub fn fd_res_sync(fd: &FdRes, opt_level: Option, - blk: &fn(v: Res)) { - blk(Res::new(Arg { - val: fd.fd, - opt_level: opt_level, - fsync_fn: fsync_fd_helper, - })); - } - - fn fsync_fd(fd: libc::c_int, level: Level) -> int { - #[fixed_stack_segment]; #[inline(never)]; - - os::fsync_fd(fd, level) as int - } - - fn fsync_fd_helper(fd_ptr: &libc::c_int, level: Level) -> int { - fsync_fd(*fd_ptr, level) - } - - // Type of objects that may want to fsync - pub trait FSyncable { fn fsync(&self, l: Level) -> int; } - - // Call o.fsync after executing blk - pub fn obj_sync(o: @FSyncable, opt_level: Option, - blk: &fn(v: Res<@FSyncable>)) { - blk(Res::new(Arg { - val: o, - opt_level: opt_level, - fsync_fn: obj_fsync_fn, - })); - } - - fn obj_fsync_fn(o: &@FSyncable, level: Level) -> int { - (*o).fsync(level) - } -} - -#[cfg(test)] -mod tests { - use prelude::*; - use i32; - use io::{BytesWriter, SeekCur, SeekEnd, SeekSet}; - use io; - use path::Path; - use result::{Ok, Err}; - use u64; - use vec; - use cast::transmute; - - #[test] - fn test_simple() { - let tmpfile = &Path::new("tmp/lib-io-test-simple.tmp"); - debug!("{}", tmpfile.display()); - let frood: ~str = - ~"A hoopy frood who really knows where his towel is."; - debug!("{}", frood.clone()); - { - let out = io::file_writer(tmpfile, [io::Create, io::Truncate]).unwrap(); - out.write_str(frood); - } - let inp = io::file_reader(tmpfile).unwrap(); - let frood2: ~str = inp.read_c_str(); - debug!("{}", frood2.clone()); - assert_eq!(frood, frood2); - } - - #[test] - fn test_each_byte_each_char_file() { - // Issue #5056 -- shouldn't include trailing EOF. - let path = Path::new("tmp/lib-io-test-each-byte-each-char-file.tmp"); - - { - // create empty, enough to reproduce a problem - io::file_writer(&path, [io::Create]).unwrap(); - } - - { - let file = io::file_reader(&path).unwrap(); - do file.each_byte() |_| { - fail!("must be empty") - }; - } - - { - let file = io::file_reader(&path).unwrap(); - do file.each_char() |_| { - fail!("must be empty") - }; - } - } - - #[test] - fn test_readchars_empty() { - do io::with_str_reader("") |inp| { - let res : ~[char] = inp.read_chars(128); - assert_eq!(res.len(), 0); - } - } - - #[test] - fn test_read_line_utf8() { - do io::with_str_reader("生锈的汤匙切肉汤hello生锈的汤匙切肉汤") |inp| { - let line = inp.read_line(); - assert_eq!(line, ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤"); - } - } - - #[test] - fn test_read_lines() { - do io::with_str_reader("a\nb\nc\n") |inp| { - assert_eq!(inp.read_lines(), ~[~"a", ~"b", ~"c"]); - } - - do io::with_str_reader("a\nb\nc") |inp| { - assert_eq!(inp.read_lines(), ~[~"a", ~"b", ~"c"]); - } - - do io::with_str_reader("") |inp| { - assert!(inp.read_lines().is_empty()); - } - } - - #[test] - fn test_readchars_wide() { - let wide_test = ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤"; - let ivals : ~[int] = ~[ - 29983, 38152, 30340, 27748, - 21273, 20999, 32905, 27748, - 104, 101, 108, 108, 111, - 29983, 38152, 30340, 27748, - 21273, 20999, 32905, 27748]; - fn check_read_ln(len : uint, s: &str, ivals: &[int]) { - do io::with_str_reader(s) |inp| { - let res : ~[char] = inp.read_chars(len); - if len <= ivals.len() { - assert_eq!(res.len(), len); - } - for (iv, c) in ivals.iter().zip(res.iter()) { - assert!(*iv == *c as int) - } - } - } - let mut i = 0; - while i < 8 { - check_read_ln(i, wide_test, ivals); - i += 1; - } - // check a long read for good measure - check_read_ln(128, wide_test, ivals); - } - - #[test] - fn test_readchar() { - do io::with_str_reader("生") |inp| { - let res = inp.read_char(); - assert_eq!(res as int, 29983); - } - } - - #[test] - fn test_readchar_empty() { - do io::with_str_reader("") |inp| { - let res = inp.read_char(); - assert_eq!(res, unsafe { transmute(-1u32) }); // FIXME: #8971: unsound - } - } - - #[test] - fn file_reader_not_exist() { - match io::file_reader(&Path::new("not a file")) { - Err(e) => { - assert_eq!(e, ~"error opening not a file"); - } - Ok(_) => fail!() - } - } - - #[test] - #[should_fail] - fn test_read_buffer_too_small() { - let path = &Path::new("tmp/lib-io-test-read-buffer-too-small.tmp"); - // ensure the file exists - io::file_writer(path, [io::Create]).unwrap(); - - let file = io::file_reader(path).unwrap(); - let mut buf = vec::from_elem(5, 0u8); - file.read(buf, 6); // this should fail because buf is too small - } - - #[test] - fn test_read_buffer_big_enough() { - let path = &Path::new("tmp/lib-io-test-read-buffer-big-enough.tmp"); - // ensure the file exists - io::file_writer(path, [io::Create]).unwrap(); - - let file = io::file_reader(path).unwrap(); - let mut buf = vec::from_elem(5, 0u8); - file.read(buf, 4); // this should succeed because buf is big enough - } - - #[test] - fn test_write_empty() { - let file = io::file_writer(&Path::new("tmp/lib-io-test-write-empty.tmp"), - [io::Create]).unwrap(); - file.write([]); - } - - #[test] - fn file_writer_bad_name() { - match io::file_writer(&Path::new("?/?"), []) { - Err(e) => { - assert!(e.starts_with("error opening")); - } - Ok(_) => fail!() - } - } - - #[test] - fn bytes_buffer_overwrite() { - let wr = BytesWriter::new(); - wr.write([0u8, 1u8, 2u8, 3u8]); - assert!(*wr.bytes == ~[0u8, 1u8, 2u8, 3u8]); - wr.seek(-2, SeekCur); - wr.write([4u8, 5u8, 6u8, 7u8]); - assert!(*wr.bytes == ~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]); - wr.seek(-2, SeekEnd); - wr.write([8u8]); - wr.seek(1, SeekSet); - wr.write([9u8]); - assert!(*wr.bytes == ~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]); - } - - #[test] - fn test_read_write_le() { - let path = Path::new("tmp/lib-io-test-read-write-le.tmp"); - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - // write the ints to the file - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - for i in uints.iter() { - file.write_le_u64(*i); - } - } - - // then read them back and check that they are the same - { - let file = io::file_reader(&path).unwrap(); - for i in uints.iter() { - assert_eq!(file.read_le_u64(), *i); - } - } - } - - #[test] - fn test_read_write_be() { - let path = Path::new("tmp/lib-io-test-read-write-be.tmp"); - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - // write the ints to the file - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - for i in uints.iter() { - file.write_be_u64(*i); - } - } - - // then read them back and check that they are the same - { - let file = io::file_reader(&path).unwrap(); - for i in uints.iter() { - assert_eq!(file.read_be_u64(), *i); - } - } - } - - #[test] - fn test_read_be_int_n() { - let path = Path::new("tmp/lib-io-test-read-be-int-n.tmp"); - let ints = [i32::min_value, -123456, -42, -5, 0, 1, i32::max_value]; - - // write the ints to the file - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - for i in ints.iter() { - file.write_be_i32(*i); - } - } - - // then read them back and check that they are the same - { - let file = io::file_reader(&path).unwrap(); - for i in ints.iter() { - // this tests that the sign extension is working - // (comparing the values as i32 would not test this) - assert_eq!(file.read_be_int_n(4), *i as i64); - } - } - } - - #[test] - fn test_read_f32() { - let path = Path::new("tmp/lib-io-test-read-f32.tmp"); - //big-endian floating-point 8.1250 - let buf = ~[0x41, 0x02, 0x00, 0x00]; - - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - file.write(buf); - } - - { - let file = io::file_reader(&path).unwrap(); - let f = file.read_be_f32(); - assert_eq!(f, 8.1250); - } - } - - #[test] - fn test_read_write_f32() { - let path = Path::new("tmp/lib-io-test-read-write-f32.tmp"); - let f:f32 = 8.1250; - - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - file.write_be_f32(f); - file.write_le_f32(f); - } - - { - let file = io::file_reader(&path).unwrap(); - assert_eq!(file.read_be_f32(), 8.1250); - assert_eq!(file.read_le_f32(), 8.1250); - } - } -} diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index 5e1ef3658b3f5..35a3ca3cff05d 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -112,7 +112,7 @@ pub fn log(_level: u32, args: &fmt::Arguments) { } None => { // There is no logger anywhere, just write to stderr - let mut logger = StdErrLogger; + let mut logger = StdErrLogger::new(); logger.log(args); } } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index ba2b42c9b9c8b..1f32c6a0a35ef 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -32,7 +32,6 @@ use c_str::CString; use clone::Clone; use container::Container; -use io; use iter::range; use libc; use libc::{c_char, c_void, c_int, size_t}; @@ -62,7 +61,7 @@ pub fn close(fd: c_int) -> c_int { // which are for Windows and for non-Windows, if necessary. // See https://github.com/mozilla/rust/issues/9822 for more information. -pub mod rustrt { +mod rustrt { use libc::{c_char, c_int}; use libc; @@ -190,6 +189,8 @@ pub fn env() -> ~[(~str,~str)] { #[cfg(windows)] unsafe fn get_env_pairs() -> ~[~str] { #[fixed_stack_segment]; #[inline(never)]; + use c_str; + use str::StrSlice; use libc::funcs::extra::kernel32::{ GetEnvironmentStringsA, @@ -200,7 +201,10 @@ pub fn env() -> ~[(~str,~str)] { fail!("os::env() failure getting env string from OS: {}", os::last_os_error()); } - let result = str::raw::from_c_multistring(ch as *libc::c_char, None); + let mut result = ~[]; + do c_str::from_c_multistring(ch as *libc::c_char, None) |cstr| { + result.push(cstr.as_str().unwrap().to_owned()); + }; FreeEnvironmentStringsA(ch); result } @@ -353,64 +357,6 @@ pub fn fdopen(fd: c_int) -> *FILE { } } - -// fsync related - -#[cfg(windows)] -pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - use libc::funcs::extra::msvcrt::*; - return commit(fd); - } -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "android")] -pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - use libc::funcs::posix01::unistd::*; - match level { - io::fsync::FSync - | io::fsync::FullFSync => return fsync(fd), - io::fsync::FDataSync => return fdatasync(fd) - } - } -} - -#[cfg(target_os = "macos")] -pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - use libc::consts::os::extra::*; - use libc::funcs::posix88::fcntl::*; - use libc::funcs::posix01::unistd::*; - match level { - io::fsync::FSync => return fsync(fd), - _ => { - // According to man fnctl, the ok retval is only specified to be - // !=-1 - if (fcntl(F_FULLFSYNC as c_int, fd) == -1 as c_int) - { return -1 as c_int; } - else - { return 0 as c_int; } - } - } - } -} - -#[cfg(target_os = "freebsd")] -pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - use libc::funcs::posix01::unistd::*; - return fsync(fd); - } -} - pub struct Pipe { input: c_int, out: c_int diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 886ad9995a150..bb8e6674b464b 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -53,7 +53,6 @@ pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; pub use default::Default; pub use from_str::FromStr; pub use hash::Hash; -pub use io::{Reader, ReaderUtil, Writer, WriterUtil}; pub use iter::{FromIterator, Extendable}; pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, ClonableIterator}; pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize}; diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs index 99634b532b082..4b16f0bc0e183 100644 --- a/src/libstd/rt/io/extensions.rs +++ b/src/libstd/rt/io/extensions.rs @@ -18,11 +18,10 @@ use int; use iter::Iterator; use vec; use rt::io::{Reader, Writer, Decorator}; -use rt::io::{read_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE}; +use rt::io::{io_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE}; use option::{Option, Some, None}; use unstable::finally::Finally; use cast; -use io::{u64_to_le_bytes, u64_to_be_bytes}; pub trait ReaderUtil { @@ -41,8 +40,8 @@ pub trait ReaderUtil { /// /// # Failure /// - /// Raises the same conditions as `read`. Additionally raises `read_error` - /// on EOF. If `read_error` is handled then `push_bytes` may push less + /// Raises the same conditions as `read`. Additionally raises `io_error` + /// on EOF. If `io_error` is handled then `push_bytes` may push less /// than the requested number of bytes. fn push_bytes(&mut self, buf: &mut ~[u8], len: uint); @@ -50,8 +49,8 @@ pub trait ReaderUtil { /// /// # Failure /// - /// Raises the same conditions as `read`. Additionally raises `read_error` - /// on EOF. If `read_error` is handled then the returned vector may + /// Raises the same conditions as `read`. Additionally raises `io_error` + /// on EOF. If `io_error` is handled then the returned vector may /// contain less than the requested number of bytes. fn read_bytes(&mut self, len: uint) -> ~[u8]; @@ -314,7 +313,7 @@ impl ReaderUtil for T { total_read += nread; } None => { - read_error::cond.raise(standard_error(EndOfFile)); + io_error::cond.raise(standard_error(EndOfFile)); break; } } @@ -334,11 +333,11 @@ impl ReaderUtil for T { fn read_to_end(&mut self) -> ~[u8] { let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE); let mut keep_reading = true; - do read_error::cond.trap(|e| { + do io_error::cond.trap(|e| { if e.kind == EndOfFile { keep_reading = false; } else { - read_error::cond.raise(e) + io_error::cond.raise(e) } }).inside { while keep_reading { @@ -634,6 +633,88 @@ fn extend_sign(val: u64, nbytes: uint) -> i64 { (val << shift) as i64 >> shift } +pub fn u64_to_le_bytes(n: u64, size: uint, + f: &fn(v: &[u8]) -> T) -> T { + assert!(size <= 8u); + match size { + 1u => f(&[n as u8]), + 2u => f(&[n as u8, + (n >> 8) as u8]), + 4u => f(&[n as u8, + (n >> 8) as u8, + (n >> 16) as u8, + (n >> 24) as u8]), + 8u => f(&[n as u8, + (n >> 8) as u8, + (n >> 16) as u8, + (n >> 24) as u8, + (n >> 32) as u8, + (n >> 40) as u8, + (n >> 48) as u8, + (n >> 56) as u8]), + _ => { + + let mut bytes: ~[u8] = ~[]; + let mut i = size; + let mut n = n; + while i > 0u { + bytes.push((n & 255_u64) as u8); + n >>= 8_u64; + i -= 1u; + } + f(bytes) + } + } +} + +pub fn u64_to_be_bytes(n: u64, size: uint, + f: &fn(v: &[u8]) -> T) -> T { + assert!(size <= 8u); + match size { + 1u => f(&[n as u8]), + 2u => f(&[(n >> 8) as u8, + n as u8]), + 4u => f(&[(n >> 24) as u8, + (n >> 16) as u8, + (n >> 8) as u8, + n as u8]), + 8u => f(&[(n >> 56) as u8, + (n >> 48) as u8, + (n >> 40) as u8, + (n >> 32) as u8, + (n >> 24) as u8, + (n >> 16) as u8, + (n >> 8) as u8, + n as u8]), + _ => { + let mut bytes: ~[u8] = ~[]; + let mut i = size; + while i > 0u { + let shift = ((i - 1u) * 8u) as u64; + bytes.push((n >> shift) as u8); + i -= 1u; + } + f(bytes) + } + } +} + +pub fn u64_from_be_bytes(data: &[u8], + start: uint, + size: uint) + -> u64 { + let mut sz = size; + assert!((sz <= 8u)); + let mut val = 0_u64; + let mut pos = start; + while sz > 0u { + sz -= 1u; + val += (data[pos] as u64) << ((sz * 8u) as u64); + pos += 1u; + } + return val; +} + #[cfg(test)] mod test { use super::ReaderUtil; @@ -641,7 +722,7 @@ mod test { use cell::Cell; use rt::io::mem::{MemReader, MemWriter}; use rt::io::mock::MockReader; - use rt::io::{read_error, placeholder_error}; + use rt::io::{io_error, placeholder_error}; #[test] fn read_byte() { @@ -681,10 +762,10 @@ mod test { fn read_byte_error() { let mut reader = MockReader::new(); reader.read = |_| { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None }; - do read_error::cond.trap(|_| { + do io_error::cond.trap(|_| { }).inside { let byte = reader.read_byte(); assert!(byte == None); @@ -722,11 +803,11 @@ mod test { fn bytes_error() { let mut reader = MockReader::new(); reader.read = |_| { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None }; let mut it = reader.bytes(); - do read_error::cond.trap(|_| ()).inside { + do io_error::cond.trap(|_| ()).inside { let byte = it.next(); assert!(byte == None); } @@ -765,7 +846,7 @@ mod test { #[test] fn read_bytes_eof() { let mut reader = MemReader::new(~[10, 11]); - do read_error::cond.trap(|_| { + do io_error::cond.trap(|_| { }).inside { assert!(reader.read_bytes(4) == ~[10, 11]); } @@ -806,7 +887,7 @@ mod test { fn push_bytes_eof() { let mut reader = MemReader::new(~[10, 11]); let mut buf = ~[8, 9]; - do read_error::cond.trap(|_| { + do io_error::cond.trap(|_| { }).inside { reader.push_bytes(&mut buf, 4); assert!(buf == ~[8, 9, 10, 11]); @@ -824,13 +905,13 @@ mod test { buf[0] = 10; Some(1) } else { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None } } }; let mut buf = ~[8, 9]; - do read_error::cond.trap(|_| { } ).inside { + do io_error::cond.trap(|_| { } ).inside { reader.push_bytes(&mut buf, 4); } assert!(buf == ~[8, 9, 10]); @@ -850,7 +931,7 @@ mod test { buf[0] = 10; Some(1) } else { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None } } @@ -903,7 +984,7 @@ mod test { buf[1] = 11; Some(2) } else { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None } } diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index a43bcd8142e18..d035e2f457cc2 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -15,10 +15,11 @@ with regular files & directories on a filesystem. At the top-level of the module are a set of freestanding functions, associated with various filesystem operations. They all operate -on a `PathLike` object. +on a `ToCStr` object. This trait is already defined for common +objects such as strings and `Path` instances. All operations in this module, including those as part of `FileStream` et al -block the task during execution. Most will raise `std::rt::io::{io_error,read_error}` +block the task during execution. Most will raise `std::rt::io::io_error` conditions in the event of failure. Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When @@ -30,15 +31,14 @@ free function counterparts. */ use prelude::*; -use super::support::PathLike; +use c_str::ToCStr; use super::{Reader, Writer, Seek}; use super::{SeekStyle, Read, Write}; -use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject}; -use rt::io::{io_error, read_error, EndOfFile, +use rt::rtio::{RtioFileStream, IoFactory, with_local_io}; +use rt::io::{io_error, EndOfFile, FileMode, FileAccess, FileStat, IoError, PathAlreadyExists, PathDoesntExist, MismatchedFileTypeForOperation, ignore_io_error}; -use rt::local::Local; use option::{Some, None}; use path::Path; @@ -48,7 +48,6 @@ use path::Path; /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::open; /// use std::rt::io::{FileMode, FileAccess}; /// @@ -87,22 +86,20 @@ use path::Path; /// * Attempting to open a file with a `FileAccess` that the user lacks permissions /// for /// * Filesystem-level errors (full disk, etc) -pub fn open(path: &P, - mode: FileMode, - access: FileAccess - ) -> Option { - let open_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_open(path, mode, access) - }; - match open_result { - Ok(fd) => Some(FileStream { - fd: fd, - last_nread: -1 - }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None +pub fn open(path: &P, + mode: FileMode, + access: FileAccess + ) -> Option { + do with_local_io |io| { + match io.fs_open(&path.to_c_str(), mode, access) { + Ok(fd) => Some(FileStream { + fd: fd, + last_nread: -1 + }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -113,7 +110,6 @@ pub fn open(path: &P, /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::unlink; /// /// let p = &Path("/some/file/path.txt"); @@ -129,17 +125,16 @@ pub fn open(path: &P, /// /// This function will raise an `io_error` condition if the user lacks permissions to /// remove the file or if some other filesystem-level error occurs -pub fn unlink(path: &P) { - let unlink_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_unlink(path) - }; - match unlink_result { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); +pub fn unlink(path: &P) { + do with_local_io |io| { + match io.fs_unlink(&path.to_c_str()) { + Ok(_) => Some(()), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } - } + }; } /// Create a new, empty directory at the provided path @@ -148,7 +143,6 @@ pub fn unlink(path: &P) { /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::mkdir; /// /// let p = &Path("/some/dir"); @@ -159,17 +153,16 @@ pub fn unlink(path: &P) { /// /// This call will raise an `io_error` condition if the user lacks permissions to make a /// new directory at the provided path, or if the directory already exists -pub fn mkdir(path: &P) { - let mkdir_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_mkdir(path) - }; - match mkdir_result { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); +pub fn mkdir(path: &P) { + do with_local_io |io| { + match io.fs_mkdir(&path.to_c_str()) { + Ok(_) => Some(()), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } - } + }; } /// Remove an existing, empty directory @@ -178,7 +171,6 @@ pub fn mkdir(path: &P) { /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::rmdir; /// /// let p = &Path("/some/dir"); @@ -189,23 +181,22 @@ pub fn mkdir(path: &P) { /// /// This call will raise an `io_error` condition if the user lacks permissions to remove the /// directory at the provided path, or if the directory isn't empty -pub fn rmdir(path: &P) { - let rmdir_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_rmdir(path) - }; - match rmdir_result { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); +pub fn rmdir(path: &P) { + do with_local_io |io| { + match io.fs_rmdir(&path.to_c_str()) { + Ok(_) => Some(()), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } - } + }; } /// Get information on the file, directory, etc at the provided path /// -/// Given a `rt::io::support::PathLike`, query the file system to get -/// information about a file, directory, etc. +/// Given a path, query the file system to get information about a file, +/// directory, etc. /// /// Returns a `Some(std::rt::io::PathInfo)` on success /// @@ -213,7 +204,6 @@ pub fn rmdir(path: &P) { /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::stat; /// /// let p = &Path("/some/file/path.txt"); @@ -238,18 +228,14 @@ pub fn rmdir(path: &P) { /// This call will raise an `io_error` condition if the user lacks the requisite /// permissions to perform a `stat` call on the given path or if there is no /// entry in the filesystem at the provided path. -pub fn stat(path: &P) -> Option { - let open_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_stat(path) - }; - match open_result { - Ok(p) => { - Some(p) - }, - Err(ioerr) => { - io_error::cond.raise(ioerr); - None +pub fn stat(path: &P) -> Option { + do with_local_io |io| { + match io.fs_stat(&path.to_c_str()) { + Ok(p) => Some(p), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -260,7 +246,6 @@ pub fn stat(path: &P) -> Option { /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::readdir; /// /// fn visit_dirs(dir: &Path, cb: &fn(&Path)) { @@ -279,18 +264,14 @@ pub fn stat(path: &P) -> Option { /// Will raise an `io_error` condition if the provided `path` doesn't exist, /// the process lacks permissions to view the contents or if the `path` points /// at a non-directory file -pub fn readdir(path: &P) -> Option<~[Path]> { - let readdir_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_readdir(path, 0) - }; - match readdir_result { - Ok(p) => { - Some(p) - }, - Err(ioerr) => { - io_error::cond.raise(ioerr); - None +pub fn readdir(path: &P) -> Option<~[Path]> { + do with_local_io |io| { + match io.fs_readdir(&path.to_c_str(), 0) { + Ok(p) => Some(p), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -380,7 +361,7 @@ impl Reader for FileStream { Err(ioerr) => { // EOF is indicated by returning None if ioerr.kind != EndOfFile { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } return None; } @@ -407,7 +388,7 @@ impl Writer for FileStream { match self.fd.flush() { Ok(_) => (), Err(ioerr) => { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } } } @@ -420,7 +401,7 @@ impl Seek for FileStream { match res { Ok(cursor) => cursor, Err(ioerr) => { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); return -1; } } @@ -434,7 +415,7 @@ impl Seek for FileStream { () }, Err(ioerr) => { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } } } diff --git a/src/libstd/rt/io/mem.rs b/src/libstd/rt/io/mem.rs index 5f6b4398c22f7..0ec37cd3c0789 100644 --- a/src/libstd/rt/io/mem.rs +++ b/src/libstd/rt/io/mem.rs @@ -22,46 +22,66 @@ use vec; /// Writes to an owned, growable byte vector pub struct MemWriter { - priv buf: ~[u8] + priv buf: ~[u8], + priv pos: uint, } impl MemWriter { - pub fn new() -> MemWriter { MemWriter { buf: vec::with_capacity(128) } } + pub fn new() -> MemWriter { + MemWriter { buf: vec::with_capacity(128), pos: 0 } + } } impl Writer for MemWriter { fn write(&mut self, buf: &[u8]) { - self.buf.push_all(buf) + // Make sure the internal buffer is as least as big as where we + // currently are + let difference = self.pos as i64 - self.buf.len() as i64; + if difference > 0 { + self.buf.grow(difference as uint, &0); + } + + // Figure out what bytes will be used to overwrite what's currently + // there (left), and what will be appended on the end (right) + let cap = self.buf.len() - self.pos; + let (left, right) = if cap <= buf.len() { + (buf.slice_to(cap), buf.slice_from(cap)) + } else { + (buf, &[]) + }; + + // Do the necessary writes + if left.len() > 0 { + vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos), + left, left.len()); + } + if right.len() > 0 { + self.buf.push_all(right); + } + + // Bump us forward + self.pos += buf.len(); } fn flush(&mut self) { /* no-op */ } } impl Seek for MemWriter { - fn tell(&self) -> u64 { self.buf.len() as u64 } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -impl Decorator<~[u8]> for MemWriter { - - fn inner(self) -> ~[u8] { - match self { - MemWriter { buf: buf } => buf - } - } + fn tell(&self) -> u64 { self.pos as u64 } - fn inner_ref<'a>(&'a self) -> &'a ~[u8] { - match *self { - MemWriter { buf: ref buf } => buf + fn seek(&mut self, pos: i64, style: SeekStyle) { + match style { + SeekSet => { self.pos = pos as uint; } + SeekEnd => { self.pos = self.buf.len() + pos as uint; } + SeekCur => { self.pos += pos as uint; } } } +} - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { - match *self { - MemWriter { buf: ref mut buf } => buf - } - } +impl Decorator<~[u8]> for MemWriter { + fn inner(self) -> ~[u8] { self.buf } + fn inner_ref<'a>(&'a self) -> &'a ~[u8] { &self.buf } + fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { &mut self.buf } } /// Reads from an owned byte vector @@ -208,6 +228,7 @@ pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] { mod test { use prelude::*; use super::*; + use rt::io::*; #[test] fn test_mem_writer() { @@ -218,7 +239,24 @@ mod test { writer.write([1, 2, 3]); writer.write([4, 5, 6, 7]); assert_eq!(writer.tell(), 8); - assert_eq!(writer.inner(), ~[0, 1, 2, 3, 4, 5 , 6, 7]); + assert_eq!(*writer.inner_ref(), ~[0, 1, 2, 3, 4, 5, 6, 7]); + + writer.seek(0, SeekSet); + assert_eq!(writer.tell(), 0); + writer.write([3, 4]); + assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 3, 4, 5, 6, 7]); + + writer.seek(1, SeekCur); + writer.write([0, 1]); + assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 7]); + + writer.seek(-1, SeekEnd); + writer.write([1, 2]); + assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2]); + + writer.seek(1, SeekEnd); + writer.write([1]); + assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]); } #[test] diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index a80c1aab39889..758c97791658f 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -261,7 +261,6 @@ pub use self::net::tcp::TcpListener; pub use self::net::tcp::TcpStream; pub use self::net::udp::UdpStream; pub use self::pipe::PipeStream; -pub use self::pipe::UnboundPipeStream; pub use self::process::Process; // Some extension traits that all Readers and Writers get. @@ -299,10 +298,6 @@ pub mod comm_adapters; /// Extension traits pub mod extensions; -/// Non-I/O things needed by the I/O module -// XXX: shouldn this really be pub? -pub mod support; - /// Basic Timer pub mod timer; @@ -331,9 +326,11 @@ pub mod native { /// Mock implementations for testing mod mock; +/// Signal handling +pub mod signal; + /// The default buffer size for various I/O operations -/// XXX: Not pub -pub static DEFAULT_BUF_SIZE: uint = 1024 * 64; +static DEFAULT_BUF_SIZE: uint = 1024 * 64; /// The type passed to I/O condition handlers to indicate error /// @@ -375,7 +372,9 @@ pub enum IoErrorKind { BrokenPipe, PathAlreadyExists, PathDoesntExist, - MismatchedFileTypeForOperation + MismatchedFileTypeForOperation, + ResourceUnavailable, + IoUnavailable, } // FIXME: #8242 implementing manually because deriving doesn't work for some reason @@ -395,7 +394,9 @@ impl ToStr for IoErrorKind { BrokenPipe => ~"BrokenPipe", PathAlreadyExists => ~"PathAlreadyExists", PathDoesntExist => ~"PathDoesntExist", - MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation" + MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation", + IoUnavailable => ~"IoUnavailable", + ResourceUnavailable => ~"ResourceUnavailable", } } } @@ -406,12 +407,6 @@ condition! { pub io_error: IoError -> (); } -// XXX: Can't put doc comments on macros -// Raised by `read` on error -condition! { - pub read_error: IoError -> (); -} - /// Helper for wrapper calls where you want to /// ignore any io_errors that might be raised pub fn ignore_io_error(cb: &fn() -> T) -> T { @@ -431,7 +426,7 @@ pub trait Reader { /// /// # Failure /// - /// Raises the `read_error` condition on error. If the condition + /// Raises the `io_error` condition on error. If the condition /// is handled then no guarantee is made about the number of bytes /// read and the contents of `buf`. If the condition is handled /// returns `None` (XXX see below). diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs index d682098118172..ba819df071a97 100644 --- a/src/libstd/rt/io/native/file.rs +++ b/src/libstd/rt/io/native/file.rs @@ -17,13 +17,31 @@ use os; use prelude::*; use super::super::*; -fn raise_error() { +#[cfg(windows)] +fn get_err(errno: i32) -> (IoErrorKind, &'static str) { + match errno { + libc::EOF => (EndOfFile, "end of file"), + _ => (OtherIoError, "unknown error"), + } +} + +#[cfg(not(windows))] +fn get_err(errno: i32) -> (IoErrorKind, &'static str) { // XXX: this should probably be a bit more descriptive... - let (kind, desc) = match os::errno() as i32 { + match errno { libc::EOF => (EndOfFile, "end of file"), + + // These two constants can have the same value on some systems, but + // different values on others, so we can't use a match clause + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => + (ResourceUnavailable, "resource temporarily unavailable"), + _ => (OtherIoError, "unknown error"), - }; + } +} +fn raise_error() { + let (kind, desc) = get_err(os::errno() as i32); io_error::cond.raise(IoError { kind: kind, desc: desc, diff --git a/src/libstd/rt/io/net/addrinfo.rs b/src/libstd/rt/io/net/addrinfo.rs new file mode 100644 index 0000000000000..27cf9781c9c3c --- /dev/null +++ b/src/libstd/rt/io/net/addrinfo.rs @@ -0,0 +1,126 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +Synchronous DNS Resolution + +Contains the functionality to perform DNS resolution in a style related to +getaddrinfo() + +*/ + +use option::{Option, Some, None}; +use result::{Ok, Err}; +use rt::io::{io_error}; +use rt::io::net::ip::{SocketAddr, IpAddr}; +use rt::rtio::{IoFactory, with_local_io}; + +/// Hints to the types of sockets that are desired when looking up hosts +pub enum SocketType { + Stream, Datagram, Raw +} + +/// Flags which can be or'd into the `flags` field of a `Hint`. These are used +/// to manipulate how a query is performed. +/// +/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo` +pub enum Flag { + AddrConfig, + All, + CanonName, + NumericHost, + NumericServ, + Passive, + V4Mapped, +} + +/// A transport protocol associated with either a hint or a return value of +/// `lookup` +pub enum Protocol { + TCP, UDP +} + +/// This structure is used to provide hints when fetching addresses for a +/// remote host to control how the lookup is performed. +/// +/// For details on these fields, see their corresponding definitions via +/// `man -s 3 getaddrinfo` +pub struct Hint { + family: uint, + socktype: Option, + protocol: Option, + flags: uint, +} + +pub struct Info { + address: SocketAddr, + family: uint, + socktype: Option, + protocol: Option, + flags: uint, +} + +/// Easy name resolution. Given a hostname, returns the list of IP addresses for +/// that hostname. +/// +/// # Failure +/// +/// On failure, this will raise on the `io_error` condition. +pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { + lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip)) +} + +/// Full-fleged resolution. This function will perform a synchronous call to +/// getaddrinfo, controlled by the parameters +/// +/// # Arguments +/// +/// * hostname - an optional hostname to lookup against +/// * servname - an optional service name, listed in the system services +/// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this +/// controls lookup +/// +/// # Failure +/// +/// On failure, this will raise on the `io_error` condition. +/// +/// XXX: this is not public because the `Hint` structure is not ready for public +/// consumption just yet. +fn lookup(hostname: Option<&str>, servname: Option<&str>, + hint: Option) -> Option<~[Info]> { + do with_local_io |io| { + match io.get_host_addresses(hostname, servname, hint) { + Ok(i) => Some(i), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + } +} + +#[cfg(test)] +mod test { + use option::Some; + use rt::io::net::ip::Ipv4Addr; + use super::*; + + #[test] + fn dns_smoke_test() { + let ipaddrs = get_host_addresses("localhost").unwrap(); + let mut found_local = false; + let local_addr = &Ipv4Addr(127, 0, 0, 1); + for addr in ipaddrs.iter() { + found_local = found_local || addr == local_addr; + } + assert!(found_local); + } +} diff --git a/src/libstd/rt/io/net/mod.rs b/src/libstd/rt/io/net/mod.rs index f44e879a63a2a..cf109167089d4 100644 --- a/src/libstd/rt/io/net/mod.rs +++ b/src/libstd/rt/io/net/mod.rs @@ -8,55 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use option::{Option, Some, None}; -use result::{Ok, Err}; -use rt::io::io_error; -use rt::io::net::ip::IpAddr; -use rt::rtio::{IoFactory, IoFactoryObject}; -use rt::local::Local; +pub use self::addrinfo::get_host_addresses; +pub mod addrinfo; pub mod tcp; pub mod udp; pub mod ip; #[cfg(unix)] pub mod unix; - -/// Simplistic name resolution -pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { - /*! - * Get the IP addresses for a given host name. - * - * Raises io_error on failure. - */ - - let ipaddrs = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).get_host_addresses(host) - }; - - match ipaddrs { - Ok(i) => Some(i), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } -} - -#[cfg(test)] -mod test { - use option::Some; - use rt::io::net::ip::Ipv4Addr; - use super::*; - - #[test] - fn dns_smoke_test() { - let ipaddrs = get_host_addresses("localhost").unwrap(); - let mut found_local = false; - let local_addr = &Ipv4Addr(127, 0, 0, 1); - for addr in ipaddrs.iter() { - found_local = found_local || addr == local_addr; - } - assert!(found_local); - } -} diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index f29e17cfc2f3d..4e841b36a5d37 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -12,37 +12,27 @@ use option::{Option, Some, None}; use result::{Ok, Err}; use rt::io::net::ip::SocketAddr; use rt::io::{Reader, Writer, Listener, Acceptor}; -use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{IoFactory, IoFactoryObject, - RtioSocket, - RtioTcpListener, RtioTcpListenerObject, - RtioTcpAcceptor, RtioTcpAcceptorObject, - RtioTcpStream, RtioTcpStreamObject}; -use rt::local::Local; +use rt::io::{io_error, EndOfFile}; +use rt::rtio::{IoFactory, with_local_io, + RtioSocket, RtioTcpListener, RtioTcpAcceptor, RtioTcpStream}; pub struct TcpStream { - priv obj: ~RtioTcpStreamObject + priv obj: ~RtioTcpStream } impl TcpStream { - fn new(s: ~RtioTcpStreamObject) -> TcpStream { + fn new(s: ~RtioTcpStream) -> TcpStream { TcpStream { obj: s } } pub fn connect(addr: SocketAddr) -> Option { - let stream = unsafe { - rtdebug!("borrowing io to connect"); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - rtdebug!("about to connect"); - (*io).tcp_connect(addr) - }; - - match stream { - Ok(s) => Some(TcpStream::new(s)), - Err(ioerr) => { - rtdebug!("failed to connect: {:?}", ioerr); - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.tcp_connect(addr) { + Ok(s) => Some(TcpStream::new(s)), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -77,7 +67,7 @@ impl Reader for TcpStream { Err(ioerr) => { // EOF is indicated by returning None if ioerr.kind != EndOfFile { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } return None; } @@ -99,20 +89,18 @@ impl Writer for TcpStream { } pub struct TcpListener { - priv obj: ~RtioTcpListenerObject + priv obj: ~RtioTcpListener } impl TcpListener { pub fn bind(addr: SocketAddr) -> Option { - let listener = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).tcp_bind(addr) - }; - match listener { - Ok(l) => Some(TcpListener { obj: l }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - return None; + do with_local_io |io| { + match io.tcp_bind(addr) { + Ok(l) => Some(TcpListener { obj: l }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -142,7 +130,7 @@ impl Listener for TcpListener { } pub struct TcpAcceptor { - priv obj: ~RtioTcpAcceptorObject + priv obj: ~RtioTcpAcceptor } impl Acceptor for TcpAcceptor { @@ -320,7 +308,7 @@ mod test { let mut buf = [0]; let nread = stream.read(buf); assert!(nread.is_none()); - do read_error::cond.trap(|e| { + do io_error::cond.trap(|e| { if cfg!(windows) { assert_eq!(e.kind, NotConnected); } else { @@ -355,7 +343,7 @@ mod test { let mut buf = [0]; let nread = stream.read(buf); assert!(nread.is_none()); - do read_error::cond.trap(|e| { + do io_error::cond.trap(|e| { if cfg!(windows) { assert_eq!(e.kind, NotConnected); } else { diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index 27faae0838b15..2e4ae95d98eea 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -12,25 +12,22 @@ use option::{Option, Some, None}; use result::{Ok, Err}; use rt::io::net::ip::SocketAddr; use rt::io::{Reader, Writer}; -use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{RtioSocket, RtioUdpSocketObject, RtioUdpSocket, IoFactory, IoFactoryObject}; -use rt::local::Local; +use rt::io::{io_error, EndOfFile}; +use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, with_local_io}; pub struct UdpSocket { - priv obj: ~RtioUdpSocketObject + priv obj: ~RtioUdpSocket } impl UdpSocket { pub fn bind(addr: SocketAddr) -> Option { - let socket = unsafe { - let factory: *mut IoFactoryObject = Local::unsafe_borrow(); - (*factory).udp_bind(addr) - }; - match socket { - Ok(s) => Some(UdpSocket { obj: s }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.udp_bind(addr) { + Ok(s) => Some(UdpSocket { obj: s }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -41,7 +38,7 @@ impl UdpSocket { Err(ioerr) => { // EOF is indicated by returning None if ioerr.kind != EndOfFile { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } None } diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs index 1771a963ba78c..e424956e2ff63 100644 --- a/src/libstd/rt/io/net/unix.rs +++ b/src/libstd/rt/io/net/unix.rs @@ -8,44 +8,289 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + +Named pipes + +This module contains the ability to communicate over named pipes with +synchronous I/O. On windows, this corresponds to talking over a Named Pipe, +while on Unix it corresponds to UNIX domain sockets. + +These pipes are similar to TCP in the sense that you can have both a stream to a +server and a server itself. The server provided accepts other `UnixStream` +instances as clients. + +*/ + use prelude::*; -use super::super::*; -use super::super::support::PathLike; -pub struct UnixStream; +use c_str::ToCStr; +use rt::rtio::{IoFactory, RtioUnixListener, with_local_io}; +use rt::rtio::{RtioUnixAcceptor, RtioPipe}; +use rt::io::pipe::PipeStream; +use rt::io::{io_error, Listener, Acceptor, Reader, Writer}; + +/// A stream which communicates over a named pipe. +pub struct UnixStream { + priv obj: PipeStream, +} impl UnixStream { - pub fn connect(_path: &P) -> Option { - fail!() + fn new(obj: ~RtioPipe) -> UnixStream { + UnixStream { obj: PipeStream::new(obj) } + } + + /// Connect to a pipe named by `path`. This will attempt to open a + /// connection to the underlying socket. + /// + /// The returned stream will be closed when the object falls out of scope. + /// + /// # Failure + /// + /// This function will raise on the `io_error` condition if the connection + /// could not be made. + /// + /// # Example + /// + /// use std::rt::io::net::unix::UnixStream; + /// + /// let server = Path("path/to/my/socket"); + /// let mut stream = UnixStream::connect(&server); + /// stream.write([1, 2, 3]); + /// + pub fn connect(path: &P) -> Option { + do with_local_io |io| { + match io.unix_connect(&path.to_c_str()) { + Ok(s) => Some(UnixStream::new(s)), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + } } } impl Reader for UnixStream { - fn read(&mut self, _buf: &mut [u8]) -> Option { fail!() } - - fn eof(&mut self) -> bool { fail!() } + fn read(&mut self, buf: &mut [u8]) -> Option { self.obj.read(buf) } + fn eof(&mut self) -> bool { self.obj.eof() } } impl Writer for UnixStream { - fn write(&mut self, _v: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } + fn write(&mut self, buf: &[u8]) { self.obj.write(buf) } + fn flush(&mut self) { self.obj.flush() } } -pub struct UnixListener; +pub struct UnixListener { + priv obj: ~RtioUnixListener, +} impl UnixListener { - pub fn bind(_path: &P) -> Option { - fail!() + + /// Creates a new listener, ready to receive incoming connections on the + /// specified socket. The server will be named by `path`. + /// + /// This listener will be closed when it falls out of scope. + /// + /// # Failure + /// + /// This function will raise on the `io_error` condition if the specified + /// path could not be bound. + /// + /// # Example + /// + /// use std::rt::io::net::unix::UnixListener; + /// + /// let server = Path("path/to/my/socket"); + /// let mut stream = UnixListener::bind(&server); + /// for client in stream.incoming() { + /// let mut client = client; + /// client.write([1, 2, 3, 4]); + /// } + /// + pub fn bind(path: &P) -> Option { + do with_local_io |io| { + match io.unix_bind(&path.to_c_str()) { + Ok(s) => Some(UnixListener{ obj: s }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + } } } impl Listener for UnixListener { - fn listen(self) -> Option { fail!() } + fn listen(self) -> Option { + match self.obj.listen() { + Ok(acceptor) => Some(UnixAcceptor { obj: acceptor }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + } } -pub struct UnixAcceptor; +pub struct UnixAcceptor { + priv obj: ~RtioUnixAcceptor, +} impl Acceptor for UnixAcceptor { - fn accept(&mut self) -> Option { fail!() } + fn accept(&mut self) -> Option { + match self.obj.accept() { + Ok(s) => Some(UnixStream::new(s)), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + } +} + +#[cfg(test)] +mod tests { + use prelude::*; + use super::*; + use cell::Cell; + use rt::test::*; + use rt::io::*; + use rt::comm::oneshot; + use os; + + fn smalltest(server: ~fn(UnixStream), client: ~fn(UnixStream)) { + let server = Cell::new(server); + let client = Cell::new(client); + do run_in_mt_newsched_task { + let server = Cell::new(server.take()); + let client = Cell::new(client.take()); + let path1 = next_test_unix(); + let path2 = path1.clone(); + let (port, chan) = oneshot(); + let port = Cell::new(port); + let chan = Cell::new(chan); + + do spawntask { + let mut acceptor = UnixListener::bind(&path1).listen(); + chan.take().send(()); + server.take()(acceptor.accept().unwrap()); + } + + do spawntask { + port.take().recv(); + client.take()(UnixStream::connect(&path2).unwrap()); + } + } + } + + #[test] + fn bind_error() { + do run_in_mt_newsched_task { + let mut called = false; + do io_error::cond.trap(|e| { + assert!(e.kind == PermissionDenied); + called = true; + }).inside { + let listener = UnixListener::bind(&("path/to/nowhere")); + assert!(listener.is_none()); + } + assert!(called); + } + } + + #[test] + fn connect_error() { + do run_in_mt_newsched_task { + let mut called = false; + do io_error::cond.trap(|e| { + assert_eq!(e.kind, OtherIoError); + called = true; + }).inside { + let stream = UnixStream::connect(&("path/to/nowhere")); + assert!(stream.is_none()); + } + assert!(called); + } + } + + #[test] + fn smoke() { + smalltest(|mut server| { + let mut buf = [0]; + server.read(buf); + assert!(buf[0] == 99); + }, |mut client| { + client.write([99]); + }) + } + + #[test] + fn read_eof() { + smalltest(|mut server| { + let mut buf = [0]; + assert!(server.read(buf).is_none()); + assert!(server.read(buf).is_none()); + }, |_client| { + // drop the client + }) + } + + #[test] + fn write_begone() { + smalltest(|mut server| { + let buf = [0]; + let mut stop = false; + while !stop{ + do io_error::cond.trap(|e| { + assert_eq!(e.kind, BrokenPipe); + stop = true; + }).inside { + server.write(buf); + } + } + }, |_client| { + // drop the client + }) + } + + #[test] + fn accept_lots() { + do run_in_mt_newsched_task { + let times = 10; + let path1 = next_test_unix(); + let path2 = path1.clone(); + let (port, chan) = oneshot(); + let port = Cell::new(port); + let chan = Cell::new(chan); + + do spawntask { + let mut acceptor = UnixListener::bind(&path1).listen(); + chan.take().send(()); + do times.times { + let mut client = acceptor.accept(); + let mut buf = [0]; + client.read(buf); + assert_eq!(buf[0], 100); + } + } + + do spawntask { + port.take().recv(); + do times.times { + let mut stream = UnixStream::connect(&path2); + stream.write([100]); + } + } + } + } + + #[test] + fn path_exists() { + do run_in_mt_newsched_task { + let path = next_test_unix(); + let _acceptor = UnixListener::bind(&path).listen(); + assert!(os::path_exists(&path)); + } + } } diff --git a/src/libstd/rt/io/option.rs b/src/libstd/rt/io/option.rs index 2ea1b6154830a..52699964b6241 100644 --- a/src/libstd/rt/io/option.rs +++ b/src/libstd/rt/io/option.rs @@ -13,12 +13,10 @@ //! I/O constructors return option types to allow errors to be handled. //! These implementations allow e.g. `Option` to be used //! as a `Reader` without unwrapping the option first. -//! -//! # XXX Seek and Close use option::*; -use super::{Reader, Writer, Listener, Acceptor}; -use super::{standard_error, PreviousIoError, io_error, read_error, IoError}; +use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle}; +use super::{standard_error, PreviousIoError, io_error, IoError}; fn prev_io_error() -> IoError { standard_error(PreviousIoError) @@ -45,7 +43,7 @@ impl Reader for Option { match *self { Some(ref mut reader) => reader.read(buf), None => { - read_error::cond.raise(prev_io_error()); + io_error::cond.raise(prev_io_error()); None } } @@ -62,6 +60,24 @@ impl Reader for Option { } } +impl Seek for Option { + fn tell(&self) -> u64 { + match *self { + Some(ref seeker) => seeker.tell(), + None => { + io_error::cond.raise(prev_io_error()); + 0 + } + } + } + fn seek(&mut self, pos: i64, style: SeekStyle) { + match *self { + Some(ref mut seeker) => seeker.seek(pos, style), + None => io_error::cond.raise(prev_io_error()) + } + } +} + impl, L: Listener> Listener for Option { fn listen(self) -> Option { match self { @@ -91,7 +107,7 @@ mod test { use option::*; use super::super::mem::*; use rt::test::*; - use super::super::{PreviousIoError, io_error, read_error}; + use super::super::{PreviousIoError, io_error, io_error}; #[test] fn test_option_writer() { @@ -145,7 +161,7 @@ mod test { let mut buf = []; let mut called = false; - do read_error::cond.trap(|err| { + do io_error::cond.trap(|err| { assert_eq!(err.kind, PreviousIoError); called = true; }).inside { diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs index d2cd531ed266f..ec9a4a0101fee 100644 --- a/src/libstd/rt/io/pipe.rs +++ b/src/libstd/rt/io/pipe.rs @@ -15,37 +15,47 @@ use prelude::*; use super::{Reader, Writer}; -use rt::io::{io_error, read_error, EndOfFile}; -use rt::local::Local; -use rt::rtio::{RtioPipe, RtioPipeObject, IoFactoryObject, IoFactory}; -use rt::rtio::RtioUnboundPipeObject; +use rt::io::{io_error, EndOfFile}; +use rt::io::native::file; +use rt::rtio::{RtioPipe, with_local_io}; pub struct PipeStream { - priv obj: RtioPipeObject + priv obj: ~RtioPipe, } -// This should not be a newtype, but rt::uv::process::set_stdio needs to reach -// into the internals of this :( -pub struct UnboundPipeStream(~RtioUnboundPipeObject); - impl PipeStream { - /// Creates a new pipe initialized, but not bound to any particular - /// source/destination - pub fn new() -> Option { - let pipe = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).pipe_init(false) - }; - match pipe { - Ok(p) => Some(UnboundPipeStream(p)), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + /// Consumes a file descriptor to return a pipe stream that will have + /// synchronous, but non-blocking reads/writes. This is useful if the file + /// descriptor is acquired via means other than the standard methods. + /// + /// This operation consumes ownership of the file descriptor and it will be + /// closed once the object is deallocated. + /// + /// # Example + /// + /// use std::libc; + /// use std::rt::io::pipe; + /// + /// let mut pipe = PipeStream::open(libc::STDERR_FILENO); + /// pipe.write(bytes!("Hello, stderr!")); + /// + /// # Failure + /// + /// If the pipe cannot be created, an error will be raised on the + /// `io_error` condition. + pub fn open(fd: file::fd_t) -> Option { + do with_local_io |io| { + match io.pipe_open(fd) { + Ok(obj) => Some(PipeStream { obj: obj }), + Err(e) => { + io_error::cond.raise(e); + None + } } } } - pub fn bind(inner: RtioPipeObject) -> PipeStream { + pub fn new(inner: ~RtioPipe) -> PipeStream { PipeStream { obj: inner } } } @@ -57,14 +67,14 @@ impl Reader for PipeStream { Err(ioerr) => { // EOF is indicated by returning None if ioerr.kind != EndOfFile { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } return None; } } } - fn eof(&mut self) -> bool { fail!() } + fn eof(&mut self) -> bool { false } } impl Writer for PipeStream { @@ -77,5 +87,5 @@ impl Writer for PipeStream { } } - fn flush(&mut self) { fail!() } + fn flush(&mut self) {} } diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs index 5f2453852ee7f..ae087099d1fa5 100644 --- a/src/libstd/rt/io/process.rs +++ b/src/libstd/rt/io/process.rs @@ -11,12 +11,12 @@ //! Bindings for executing child processes use prelude::*; +use cell::Cell; use libc; use rt::io; use rt::io::io_error; -use rt::local::Local; -use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory}; +use rt::rtio::{RtioProcess, IoFactory, with_local_io}; // windows values don't matter as long as they're at least one of unix's // TERM/KILL/INT signals @@ -26,7 +26,7 @@ use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory}; #[cfg(not(windows))] pub static MustDieSignal: int = libc::SIGKILL as int; pub struct Process { - priv handle: ~RtioProcessObject, + priv handle: ~RtioProcess, io: ~[Option], } @@ -57,7 +57,7 @@ pub struct ProcessConfig<'self> { /// 0 - stdin /// 1 - stdout /// 2 - stderr - io: ~[StdioContainer] + io: &'self [StdioContainer] } /// Describes what to do with a standard io stream for a child process. @@ -70,42 +70,32 @@ pub enum StdioContainer { /// specified for. InheritFd(libc::c_int), - // XXX: these two shouldn't have libuv-specific implementation details - - /// The specified libuv stream is inherited for the corresponding file - /// descriptor it is assigned to. - // XXX: this needs to be thought out more. - //InheritStream(uv::net::StreamWatcher), - - /// Creates a pipe for the specified file descriptor which will be directed - /// into the previously-initialized pipe passed in. + /// Creates a pipe for the specified file descriptor which will be created + /// when the process is spawned. /// /// The first boolean argument is whether the pipe is readable, and the /// second is whether it is writable. These properties are from the view of /// the *child* process, not the parent process. - CreatePipe(io::UnboundPipeStream, - bool /* readable */, - bool /* writable */), + CreatePipe(bool /* readable */, bool /* writable */), } impl Process { /// Creates a new pipe initialized, but not bound to any particular /// source/destination pub fn new(config: ProcessConfig) -> Option { - let process = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).spawn(config) - }; - match process { - Ok((p, io)) => Some(Process{ - handle: p, - io: io.move_iter().map(|p| - p.map(|p| io::PipeStream::bind(p)) - ).collect() - }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + let config = Cell::new(config); + do with_local_io |io| { + match io.spawn(config.take()) { + Ok((p, io)) => Some(Process{ + handle: p, + io: io.move_iter().map(|p| + p.map(|p| io::PipeStream::new(p)) + ).collect() + }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs new file mode 100644 index 0000000000000..a13fc19d000a8 --- /dev/null +++ b/src/libstd/rt/io/signal.rs @@ -0,0 +1,220 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +Signal handling + +This modules provides bindings to receive signals safely, built on top of the +local I/O factory. There are a number of defined signals which can be caught, +but not all signals will work across all platforms (windows doesn't have +definitions for a number of signals. + +*/ + +use comm::{Port, SharedChan, stream}; +use hashmap; +use option::{Some, None}; +use result::{Err, Ok}; +use rt::io::io_error; +use rt::rtio::{IoFactory, RtioSignal, with_local_io}; + +#[deriving(Eq, IterBytes)] +pub enum Signum { + /// Equivalent to SIGBREAK, delivered when the user presses Ctrl-Break. + Break = 21i, + /// Equivalent to SIGHUP, delivered when the user closes the terminal + /// window. On delivery of HangUp, the program is given approximately + /// 10 seconds to perfom any cleanup. After that, Windows will + /// unconditionally terminate it. + HangUp = 1i, + /// Equivalent to SIGINT, delivered when the user presses Ctrl-c. + Interrupt = 2i, + /// Equivalent to SIGQUIT, delivered when the user presses Ctrl-\. + Quit = 3i, + /// Equivalent to SIGTSTP, delivered when the user presses Ctrl-z. + StopTemporarily = 20i, + /// Equivalent to SIGUSR1. + User1 = 10i, + /// Equivalent to SIGUSR2. + User2 = 12i, + /// Equivalent to SIGWINCH, delivered when the console has been resized. + /// WindowSizeChange may not be delivered in a timely manner; size change + /// will only be detected when the cursor is being moved. + WindowSizeChange = 28i, +} + +/// Listener provides a port to listen for registered signals. +/// +/// Listener automatically unregisters its handles once it is out of scope. +/// However, clients can still unregister signums manually. +/// +/// # Example +/// +/// ```rust +/// use std::rt::io::signal::{Listener, Interrupt}; +/// +/// let mut listener = Listener::new(); +/// listener.register(signal::Interrupt); +/// +/// do spawn { +/// loop { +/// match listener.port.recv() { +/// Interrupt => println("Got Interrupt'ed"), +/// _ => (), +/// } +/// } +/// } +/// +/// ``` +pub struct Listener { + /// A map from signums to handles to keep the handles in memory + priv handles: hashmap::HashMap, + /// chan is where all the handles send signums, which are received by + /// the clients from port. + priv chan: SharedChan, + + /// Clients of Listener can `recv()` from this port. This is exposed to + /// allow selection over this port as well as manipulation of the port + /// directly. + port: Port, +} + +impl Listener { + /// Creates a new listener for signals. Once created, signals are bound via + /// the `register` method (otherwise nothing will ever be received) + pub fn new() -> Listener { + let (port, chan) = stream(); + Listener { + chan: SharedChan::new(chan), + port: port, + handles: hashmap::HashMap::new(), + } + } + + /// Listen for a signal, returning true when successfully registered for + /// signum. Signals can be received using `recv()`. + /// + /// Once a signal is registered, this listener will continue to receive + /// notifications of signals until it is unregistered. This occurs + /// regardless of the number of other listeners registered in other tasks + /// (or on this task). + /// + /// Signals are still received if there is no task actively waiting for + /// a signal, and a later call to `recv` will return the signal that was + /// received while no task was waiting on it. + /// + /// # Failure + /// + /// If this function fails to register a signal handler, then an error will + /// be raised on the `io_error` condition and the function will return + /// false. + pub fn register(&mut self, signum: Signum) -> bool { + if self.handles.contains_key(&signum) { + return true; // self is already listening to signum, so succeed + } + do with_local_io |io| { + match io.signal(signum, self.chan.clone()) { + Ok(w) => { + self.handles.insert(signum, w); + Some(()) + }, + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + }.is_some() + } + + /// Unregisters a signal. If this listener currently had a handler + /// registered for the signal, then it will stop receiving any more + /// notification about the signal. If the signal has already been received, + /// it may still be returned by `recv`. + pub fn unregister(&mut self, signum: Signum) { + self.handles.pop(&signum); + } +} + +#[cfg(test)] +mod test { + use libc; + use rt::io::timer; + use rt::io; + use super::*; + + // kill is only available on Unixes + #[cfg(unix)] + #[fixed_stack_segment] + fn sigint() { + unsafe { + libc::funcs::posix88::signal::kill(libc::getpid(), libc::SIGINT); + } + } + + #[test] #[cfg(unix)] + fn test_io_signal_smoketest() { + let mut signal = Listener::new(); + signal.register(Interrupt); + sigint(); + timer::sleep(10); + match signal.port.recv() { + Interrupt => (), + s => fail!("Expected Interrupt, got {:?}", s), + } + } + + #[test] #[cfg(unix)] + fn test_io_signal_two_signal_one_signum() { + let mut s1 = Listener::new(); + let mut s2 = Listener::new(); + s1.register(Interrupt); + s2.register(Interrupt); + sigint(); + timer::sleep(10); + match s1.port.recv() { + Interrupt => (), + s => fail!("Expected Interrupt, got {:?}", s), + } + match s1.port.recv() { + Interrupt => (), + s => fail!("Expected Interrupt, got {:?}", s), + } + } + + #[test] #[cfg(unix)] + fn test_io_signal_unregister() { + let mut s1 = Listener::new(); + let mut s2 = Listener::new(); + s1.register(Interrupt); + s2.register(Interrupt); + s2.unregister(Interrupt); + sigint(); + timer::sleep(10); + if s2.port.peek() { + fail!("Unexpected {:?}", s2.port.recv()); + } + } + + #[cfg(windows)] + #[test] + fn test_io_signal_invalid_signum() { + let mut s = Listener::new(); + let mut called = false; + do io::io_error::cond.trap(|_| { + called = true; + }).inside { + if s.register(User1) { + fail!("Unexpected successful registry of signum {:?}", User1); + } + } + assert!(called); + } +} diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index e6dd9a480998e..b922e6400cc50 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -8,23 +8,90 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + +This modules provides bindings to the local event loop's TTY interface, using it +to have synchronous, but non-blocking versions of stdio. These handles can be +inspected for information about terminal dimensions or related information +about the stream or terminal that it is attached to. + +# Example + +```rust +use std::rt::io; + +let mut out = io::stdout(); +out.write(bytes!("Hello, world!")); +``` + +*/ + use fmt; use libc; use option::{Option, Some, None}; use result::{Ok, Err}; -use rt::local::Local; -use rt::rtio::{RtioFileStream, IoFactoryObject, IoFactory}; -use super::{Reader, Writer, io_error}; +use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io, + CloseAsynchronously}; +use super::{Reader, Writer, io_error, IoError, OtherIoError}; + +// And so begins the tale of acquiring a uv handle to a stdio stream on all +// platforms in all situations. Our story begins by splitting the world into two +// categories, windows and unix. Then one day the creators of unix said let +// there be redirection! And henceforth there was redirection away from the +// console for standard I/O streams. +// +// After this day, the world split into four factions: +// +// 1. Unix with stdout on a terminal. +// 2. Unix with stdout redirected. +// 3. Windows with stdout on a terminal. +// 4. Windows with stdout redirected. +// +// Many years passed, and then one day the nation of libuv decided to unify this +// world. After months of toiling, uv created three ideas: TTY, Pipe, File. +// These three ideas propagated throughout the lands and the four great factions +// decided to settle among them. +// +// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon +// doing so, they even enhanced themselves further then their Pipe/File +// brethren, becoming the dominant powers. +// +// The group of 4, however, decided to work independently. They abandoned the +// common TTY belief throughout, and even abandoned the fledgling Pipe belief. +// The members of the 4th faction decided to only align themselves with File. +// +// tl;dr; TTY works on everything but when windows stdout is redirected, in that +// case pipe also doesn't work, but magically file does! +enum StdSource { + TTY(~RtioTTY), + File(~RtioFileStream), +} + +#[fixed_stack_segment] #[inline(never)] +fn src(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T { + do with_local_io |io| { + let fd = unsafe { libc::dup(fd) }; + match io.tty_open(fd, readable) { + Ok(tty) => Some(f(TTY(tty))), + Err(_) => { + // It's not really that desirable if these handles are closed + // synchronously, and because they're squirreled away in a task + // structure the destructors will be run when the task is + // attempted to get destroyed. This means that if we run a + // synchronous destructor we'll attempt to do some scheduling + // operations which will just result in sadness. + Some(f(File(io.fs_from_raw_fd(fd, CloseAsynchronously)))) + } + } + }.unwrap() +} /// Creates a new non-blocking handle to the stdin of the current process. /// /// See `stdout()` for notes about this function. +#[fixed_stack_segment] #[inline(never)] pub fn stdin() -> StdReader { - let stream = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_from_raw_fd(libc::STDIN_FILENO, false) - }; - StdReader { inner: stream } + do src(libc::STDIN_FILENO, true) |src| { StdReader { inner: src } } } /// Creates a new non-blocking handle to the stdout of the current process. @@ -34,22 +101,14 @@ pub fn stdin() -> StdReader { /// task context because the stream returned will be a non-blocking object using /// the local scheduler to perform the I/O. pub fn stdout() -> StdWriter { - let stream = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_from_raw_fd(libc::STDOUT_FILENO, false) - }; - StdWriter { inner: stream } + do src(libc::STDOUT_FILENO, false) |src| { StdWriter { inner: src } } } /// Creates a new non-blocking handle to the stderr of the current process. /// /// See `stdout()` for notes about this function. pub fn stderr() -> StdWriter { - let stream = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_from_raw_fd(libc::STDERR_FILENO, false) - }; - StdWriter { inner: stream } + do src(libc::STDERR_FILENO, false) |src| { StdWriter { inner: src } } } /// Prints a string to the stdout of the current process. No newline is emitted @@ -87,12 +146,16 @@ pub fn println_args(fmt: &fmt::Arguments) { /// Representation of a reader of a standard input stream pub struct StdReader { - priv inner: ~RtioFileStream + priv inner: StdSource } impl Reader for StdReader { fn read(&mut self, buf: &mut [u8]) -> Option { - match self.inner.read(buf) { + let ret = match self.inner { + TTY(ref mut tty) => tty.read(buf), + File(ref mut file) => file.read(buf).map_move(|i| i as uint), + }; + match ret { Ok(amt) => Some(amt as uint), Err(e) => { io_error::cond.raise(e); @@ -106,21 +169,102 @@ impl Reader for StdReader { /// Representation of a writer to a standard output stream pub struct StdWriter { - priv inner: ~RtioFileStream + priv inner: StdSource +} + +impl StdWriter { + /// Gets the size of this output window, if possible. This is typically used + /// when the writer is attached to something like a terminal, this is used + /// to fetch the dimensions of the terminal. + /// + /// If successful, returns Some((width, height)). + /// + /// # Failure + /// + /// This function will raise on the `io_error` condition if an error + /// happens. + pub fn winsize(&mut self) -> Option<(int, int)> { + match self.inner { + TTY(ref mut tty) => { + match tty.get_winsize() { + Ok(p) => Some(p), + Err(e) => { + io_error::cond.raise(e); + None + } + } + } + File(*) => { + io_error::cond.raise(IoError { + kind: OtherIoError, + desc: "stream is not a tty", + detail: None, + }); + None + } + } + } + + /// Controls whether this output stream is a "raw stream" or simply a normal + /// stream. + /// + /// # Failure + /// + /// This function will raise on the `io_error` condition if an error + /// happens. + pub fn set_raw(&mut self, raw: bool) { + match self.inner { + TTY(ref mut tty) => { + match tty.set_raw(raw) { + Ok(()) => {}, + Err(e) => io_error::cond.raise(e), + } + } + File(*) => { + io_error::cond.raise(IoError { + kind: OtherIoError, + desc: "stream is not a tty", + detail: None, + }); + } + } + } + + /// Returns whether this tream is attached to a TTY instance or not. + /// + /// This is similar to libc's isatty() function + pub fn isatty(&self) -> bool { + match self.inner { + TTY(ref tty) => tty.isatty(), + File(*) => false, + } + } } impl Writer for StdWriter { fn write(&mut self, buf: &[u8]) { - match self.inner.write(buf) { + let ret = match self.inner { + TTY(ref mut tty) => tty.write(buf), + File(ref mut file) => file.write(buf), + }; + match ret { Ok(()) => {} Err(e) => io_error::cond.raise(e) } } - fn flush(&mut self) { - match self.inner.flush() { - Ok(()) => {} - Err(e) => io_error::cond.raise(e) - } + fn flush(&mut self) { /* nothing to do */ } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn smoke() { + // Just make sure we can acquire handles + stdin(); + stdout(); + stderr(); } } diff --git a/src/libstd/rt/io/support.rs b/src/libstd/rt/io/support.rs deleted file mode 100644 index 31040bc51a135..0000000000000 --- a/src/libstd/rt/io/support.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::*; - -pub trait PathLike { - fn path_as_str(&self, f: &fn(&str) -> T) -> T; -} - -impl<'self> PathLike for &'self str { - fn path_as_str(&self, f: &fn(&str) -> T) -> T { - f(*self) - } -} - -impl PathLike for Path { - fn path_as_str(&self, f: &fn(&str) -> T) -> T { - let s = self.as_str().unwrap(); - f(s) - } -} - -#[cfg(test)] -mod test { - use path::*; - use super::PathLike; - - #[test] - fn path_like_smoke_test() { - let expected = if cfg!(unix) { "/home" } else { "C:\\" }; - let path = Path::new(expected); - path.path_as_str(|p| assert!(p == expected)); - path.path_as_str(|p| assert!(p == expected)); - } -} diff --git a/src/libstd/rt/io/timer.rs b/src/libstd/rt/io/timer.rs index b41d7541a6074..fab0062ee0054 100644 --- a/src/libstd/rt/io/timer.rs +++ b/src/libstd/rt/io/timer.rs @@ -10,13 +10,11 @@ use option::{Option, Some, None}; use result::{Ok, Err}; -use rt::io::{io_error}; -use rt::rtio::{IoFactory, IoFactoryObject, - RtioTimer, RtioTimerObject}; -use rt::local::Local; +use rt::io::io_error; +use rt::rtio::{IoFactory, RtioTimer, with_local_io}; pub struct Timer { - priv obj: ~RtioTimerObject + priv obj: ~RtioTimer } /// Sleep the current task for `msecs` milliseconds. @@ -28,20 +26,19 @@ pub fn sleep(msecs: u64) { impl Timer { + /// Creates a new timer which can be used to put the current task to sleep + /// for a number of milliseconds. pub fn new() -> Option { - let timer = unsafe { - rtdebug!("Timer::init: borrowing io to init timer"); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - rtdebug!("about to init timer"); - (*io).timer_init() - }; - match timer { - Ok(t) => Some(Timer { obj: t }), - Err(ioerr) => { - rtdebug!("Timer::init: failed to init: {:?}", ioerr); - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.timer_init() { + Ok(t) => Some(Timer { obj: t }), + Err(ioerr) => { + rtdebug!("Timer::init: failed to init: {:?}", ioerr); + io_error::cond.raise(ioerr); + None + } } + } } diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs index d4f31879c003a..1ddc2f86f4bc4 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -12,8 +12,6 @@ use option::{Option, Some, None}; use rt::sched::Scheduler; use rt::task::Task; use rt::local_ptr; -use rt::rtio::{EventLoop, IoFactoryObject}; -//use borrow::to_uint; use cell::Cell; pub trait Local { @@ -122,24 +120,6 @@ impl Local for Scheduler { } } -// XXX: This formulation won't work once ~IoFactoryObject is a real trait pointer -impl Local for IoFactoryObject { - fn put(_value: ~IoFactoryObject) { rtabort!("unimpl") } - fn take() -> ~IoFactoryObject { rtabort!("unimpl") } - fn exists(_: Option) -> bool { rtabort!("unimpl") } - fn borrow(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") } - unsafe fn unsafe_take() -> ~IoFactoryObject { rtabort!("unimpl") } - unsafe fn unsafe_borrow() -> *mut IoFactoryObject { - let sched: *mut Scheduler = Local::unsafe_borrow(); - let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap(); - return io; - } - unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { - rtabort!("unimpl") - } -} - - #[cfg(test)] mod test { use option::None; diff --git a/src/libstd/rt/logging.rs b/src/libstd/rt/logging.rs index 660d1cd43595f..31650ede7000d 100644 --- a/src/libstd/rt/logging.rs +++ b/src/libstd/rt/logging.rs @@ -12,6 +12,7 @@ use fmt; use from_str::from_str; use libc::exit; use option::{Some, None, Option}; +use rt::io; use rt::crate_map::{ModEntry, CrateMap, iter_crate_map, get_crate_map}; use str::StrSlice; use u32; @@ -166,14 +167,23 @@ pub trait Logger { fn log(&mut self, args: &fmt::Arguments); } -pub struct StdErrLogger; +/// This logger emits output to the stderr of the process, and contains a lazily +/// initialized event-loop driven handle to the stream. +pub struct StdErrLogger { + priv handle: Option, +} + +impl StdErrLogger { + pub fn new() -> StdErrLogger { StdErrLogger { handle: None } } +} impl Logger for StdErrLogger { fn log(&mut self, args: &fmt::Arguments) { - // FIXME(#6846): this should not call the blocking version of println, - // or at least the default loggers for tasks shouldn't do - // that - ::rt::util::dumb_println(args); + // First time logging? Get a handle to the stderr of this process. + if self.handle.is_none() { + self.handle = Some(io::stderr()); + } + fmt::writeln(self.handle.get_mut_ref() as &mut io::Writer, args); } } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 9ea7b734d248c..66d7a6bf48823 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -279,7 +279,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { rtdebug!("inserting a regular scheduler"); // Every scheduler is driven by an I/O event loop. - let loop_ = ~UvEventLoop::new(); + let loop_ = ~UvEventLoop::new() as ~rtio::EventLoop; let mut sched = ~Scheduler::new(loop_, work_queue.clone(), work_queues.clone(), @@ -303,7 +303,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { // set. let work_queue = WorkQueue::new(); - let main_loop = ~UvEventLoop::new(); + let main_loop = ~UvEventLoop::new() as ~rtio::EventLoop; let mut main_sched = ~Scheduler::new_special(main_loop, work_queue, work_queues.clone(), diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 501def8b06079..66a0676a2f410 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -11,40 +11,29 @@ use libc; use option::*; use result::*; +use comm::SharedChan; use libc::c_int; +use c_str::CString; +use ai = rt::io::net::addrinfo; use rt::io::IoError; +use rt::io::signal::Signum; use super::io::process::ProcessConfig; use super::io::net::ip::{IpAddr, SocketAddr}; -use rt::uv::uvio; use path::Path; -use super::io::support::PathLike; use super::io::{SeekStyle}; use super::io::{FileMode, FileAccess, FileStat}; -// XXX: ~object doesn't work currently so these are some placeholder -// types to use instead -pub type EventLoopObject = uvio::UvEventLoop; -pub type RemoteCallbackObject = uvio::UvRemoteCallback; -pub type IoFactoryObject = uvio::UvIoFactory; -pub type RtioTcpStreamObject = uvio::UvTcpStream; -pub type RtioTcpAcceptorObject = uvio::UvTcpAcceptor; -pub type RtioTcpListenerObject = uvio::UvTcpListener; -pub type RtioUdpSocketObject = uvio::UvUdpSocket; -pub type RtioTimerObject = uvio::UvTimer; -pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback; -pub type RtioPipeObject = uvio::UvPipeStream; -pub type RtioUnboundPipeObject = uvio::UvUnboundPipe; -pub type RtioProcessObject = uvio::UvProcess; - pub trait EventLoop { fn run(&mut self); fn callback(&mut self, ~fn()); fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback; fn callback_ms(&mut self, ms: u64, ~fn()); - fn remote_callback(&mut self, ~fn()) -> ~RemoteCallbackObject; + fn remote_callback(&mut self, ~fn()) -> ~RemoteCallback; + /// The asynchronous I/O services. Not all event loops may provide one - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject>; + // FIXME(#9382) this is an awful interface + fn io<'a>(&'a mut self, f: &fn(&'a mut IoFactory)); } pub trait RemoteCallback { @@ -69,32 +58,74 @@ pub struct FileOpenConfig { priv mode: int } +/// Description of what to do when a file handle is closed +pub enum CloseBehavior { + /// Do not close this handle when the object is destroyed + DontClose, + /// Synchronously close the handle, meaning that the task will block when + /// the handle is destroyed until it has been fully closed. + CloseSynchronously, + /// Asynchronously closes a handle, meaning that the task will *not* block + /// when the handle is destroyed, but the handle will still get deallocated + /// and cleaned up (but this will happen asynchronously on the local event + /// loop). + CloseAsynchronously, +} + +pub fn with_local_io(f: &fn(&mut IoFactory) -> Option) -> Option { + use rt::sched::Scheduler; + use rt::local::Local; + use rt::io::{io_error, standard_error, IoUnavailable}; + + unsafe { + let sched: *mut Scheduler = Local::unsafe_borrow(); + let mut io = None; + (*sched).event_loop.io(|i| io = Some(i)); + match io { + Some(io) => f(io), + None => { + io_error::cond.raise(standard_error(IoUnavailable)); + None + } + } + } +} + pub trait IoFactory { - fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStreamObject, IoError>; - fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError>; - fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>; - fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>; - fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream; - fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) + fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError>; + fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListener, IoError>; + fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError>; + fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, + hint: Option) -> Result<~[ai::Info], IoError>; + fn timer_init(&mut self) -> Result<~RtioTimer, IoError>; + fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream; + fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; - fn fs_unlink(&mut self, path: &P) -> Result<(), IoError>; - fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>; - fn fs_stat(&mut self, path: &P) -> Result; - fn fs_mkdir(&mut self, path: &P) -> Result<(), IoError>; - fn fs_rmdir(&mut self, path: &P) -> Result<(), IoError>; - fn fs_readdir(&mut self, path: &P, flags: c_int) -> + fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError>; + fn fs_stat(&mut self, path: &CString) -> Result; + fn fs_mkdir(&mut self, path: &CString) -> Result<(), IoError>; + fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError>; + fn fs_readdir(&mut self, path: &CString, flags: c_int) -> Result<~[Path], IoError>; - fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError>; fn spawn(&mut self, config: ProcessConfig) - -> Result<(~RtioProcessObject, ~[Option]), IoError>; + -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError>; + + fn pipe_open(&mut self, fd: c_int) -> Result<~RtioPipe, IoError>; + fn unix_bind(&mut self, path: &CString) -> + Result<~RtioUnixListener, IoError>; + fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; + fn tty_open(&mut self, fd: c_int, readable: bool) + -> Result<~RtioTTY, IoError>; + fn signal(&mut self, signal: Signum, channel: SharedChan) + -> Result<~RtioSignal, IoError>; } pub trait RtioTcpListener : RtioSocket { - fn listen(self) -> Result<~RtioTcpAcceptorObject, IoError>; + fn listen(~self) -> Result<~RtioTcpAcceptor, IoError>; } pub trait RtioTcpAcceptor : RtioSocket { - fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError>; + fn accept(&mut self) -> Result<~RtioTcpStream, IoError>; fn accept_simultaneously(&mut self) -> Result<(), IoError>; fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>; } @@ -154,3 +185,30 @@ pub trait RtioPipe { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; } + +pub trait RtioUnixListener { + fn listen(~self) -> Result<~RtioUnixAcceptor, IoError>; +} + +pub trait RtioUnixAcceptor { + fn accept(&mut self) -> Result<~RtioPipe, IoError>; + fn accept_simultaneously(&mut self) -> Result<(), IoError>; + fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>; +} + +pub trait RtioTTY { + fn read(&mut self, buf: &mut [u8]) -> Result; + fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; + fn set_raw(&mut self, raw: bool) -> Result<(), IoError>; + fn get_winsize(&mut self) -> Result<(int, int), IoError>; + fn isatty(&self) -> bool; +} + +pub trait PausibleIdleCallback { + fn start(&mut self, f: ~fn()); + fn pause(&mut self); + fn resume(&mut self); + fn close(&mut self); +} + +pub trait RtioSignal {} diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index ee163bab3c062..6e66188461617 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -16,7 +16,7 @@ use unstable::raw; use super::sleeper_list::SleeperList; use super::work_queue::WorkQueue; use super::stack::{StackPool}; -use super::rtio::{EventLoop, EventLoopObject, RemoteCallbackObject}; +use super::rtio::EventLoop; use super::context::Context; use super::task::{Task, AnySched, Sched}; use super::message_queue::MessageQueue; @@ -63,7 +63,7 @@ pub struct Scheduler { no_sleep: bool, stack_pool: StackPool, /// The event loop used to drive the scheduler and perform I/O - event_loop: ~EventLoopObject, + event_loop: ~EventLoop, /// The scheduler runs on a special task. When it is not running /// it is stored here instead of the work queue. priv sched_task: Option<~Task>, @@ -107,7 +107,7 @@ impl Scheduler { // * Initialization Functions - pub fn new(event_loop: ~EventLoopObject, + pub fn new(event_loop: ~EventLoop, work_queue: WorkQueue<~Task>, work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList) @@ -119,7 +119,7 @@ impl Scheduler { } - pub fn new_special(event_loop: ~EventLoopObject, + pub fn new_special(event_loop: ~EventLoop, work_queue: WorkQueue<~Task>, work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList, @@ -227,7 +227,7 @@ impl Scheduler { // mutable reference to the event_loop to give it the "run" // command. unsafe { - let event_loop: *mut ~EventLoopObject = &mut self_sched.event_loop; + let event_loop: *mut ~EventLoop = &mut self_sched.event_loop; // Our scheduler must be in the task before the event loop // is started. @@ -793,7 +793,7 @@ pub enum SchedMessage { } pub struct SchedHandle { - priv remote: ~RemoteCallbackObject, + priv remote: ~RemoteCallback, priv queue: MessageQueue, sched_id: uint } @@ -905,6 +905,7 @@ mod test { use cell::Cell; use rt::thread::Thread; use rt::task::{Task, Sched}; + use rt::rtio::EventLoop; use rt::util; use option::{Some}; @@ -1020,7 +1021,7 @@ mod test { // Our normal scheduler let mut normal_sched = ~Scheduler::new( - ~UvEventLoop::new(), + ~UvEventLoop::new() as ~EventLoop, normal_queue, queues.clone(), sleepers.clone()); @@ -1031,7 +1032,7 @@ mod test { // Our special scheduler let mut special_sched = ~Scheduler::new_special( - ~UvEventLoop::new(), + ~UvEventLoop::new() as ~EventLoop, special_queue.clone(), queues.clone(), sleepers.clone(), @@ -1202,7 +1203,7 @@ mod test { let queues = ~[queue.clone()]; let mut sched = ~Scheduler::new( - ~UvEventLoop::new(), + ~UvEventLoop::new() as ~EventLoop, queue, queues.clone(), sleepers.clone()); diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index c4f352501a08b..1ea68bb52d7e0 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -132,7 +132,7 @@ impl Task { heap: LocalHeap::new(), gc: GarbageCollector, storage: LocalStorage(None), - logger: StdErrLogger, + logger: StdErrLogger::new(), unwinder: Unwinder { unwinding: false }, taskgroup: None, death: Death::new(), @@ -166,7 +166,7 @@ impl Task { heap: LocalHeap::new(), gc: GarbageCollector, storage: LocalStorage(None), - logger: StdErrLogger, + logger: StdErrLogger::new(), unwinder: Unwinder { unwinding: false }, taskgroup: None, death: Death::new(), @@ -188,7 +188,7 @@ impl Task { heap: LocalHeap::new(), gc: GarbageCollector, storage: LocalStorage(None), - logger: StdErrLogger, + logger: StdErrLogger::new(), unwinder: Unwinder { unwinding: false }, taskgroup: None, // FIXME(#7544) make watching optional @@ -479,7 +479,6 @@ pub extern "C" fn rust_stack_exhausted() { use rt::in_green_task_context; use rt::task::Task; use rt::local::Local; - use rt::logging::Logger; use unstable::intrinsics; unsafe { @@ -529,8 +528,12 @@ pub extern "C" fn rust_stack_exhausted() { do Local::borrow |task: &mut Task| { let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or(""); - format_args!(|args| { task.logger.log(args) }, - "task '{}' has overflowed its stack", n); + // See the message below for why this is not emitted to the + // task's logger. This has the additional conundrum of the + // logger may not be initialized just yet, meaning that an FFI + // call would happen to initialized it (calling out to libuv), + // and the FFI call needs 2MB of stack when we just ran out. + rterrln!("task '{}' has overflowed its stack", n); } } else { rterrln!("stack overflow in non-task context"); @@ -546,9 +549,9 @@ pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! { use rt::in_green_task_context; use rt::task::Task; use rt::local::Local; - use rt::logging::Logger; use str::Str; use c_str::CString; + use unstable::intrinsics; unsafe { let msg = CString::new(msg, false); @@ -557,35 +560,35 @@ pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! { Some(s) => s, None => rtabort!("message wasn't utf8?") }; - if in_green_task_context() { - // Be careful not to allocate in this block, if we're failing we may - // have been failing due to a lack of memory in the first place... - do Local::borrow |task: &mut Task| { - let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or(""); - - match file.as_str() { - Some(file) => { - format_args!(|args| { task.logger.log(args) }, - "task '{}' failed at '{}', {}:{}", - n, msg, file, line); - } - None => { - format_args!(|args| { task.logger.log(args) }, - "task '{}' failed at '{}'", n, msg); - } - } - } - } else { + if !in_green_task_context() { match file.as_str() { Some(file) => { rterrln!("failed in non-task context at '{}', {}:{}", msg, file, line as int); } - None => rterrln!("failed in non-task context at '{}'", msg), + None => rterrln!("failed in non-task context at '{}'", msg) } + intrinsics::abort(); } + // Be careful not to allocate in this block, if we're failing we may + // have been failing due to a lack of memory in the first place... let task: *mut Task = Local::unsafe_borrow(); + let n = (*task).name.as_ref().map(|n| n.as_slice()).unwrap_or(""); + + // XXX: this should no get forcibly printed to the console, this should + // either be sent to the parent task (ideally), or get printed to + // the task's logger. Right now the logger is actually a uvio + // instance, which uses unkillable blocks internally for various + // reasons. This will cause serious trouble if the task is failing + // due to mismanagment of its own kill flag, so calling our own + // logger in its current state is a bit of a problem. + match file.as_str() { + Some(file) => { + rterrln!("task '{}' failed at '{}', {}:{}", n, msg, file, line); + } + None => rterrln!("task '{}' failed at '{}'", n, msg), + } if (*task).unwinder.unwinding { rtabort!("unwinding again"); } diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 4f7ebb4a72195..c238b1dfba16a 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rand; +use rand::Rng; +use os; use libc; use option::{Some, None}; +use path::Path; use cell::Cell; use clone::Clone; use container::Container; @@ -18,6 +22,7 @@ use super::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr}; use vec::{OwnedVector, MutableVector, ImmutableVector}; use path::GenericPath; use rt::sched::Scheduler; +use rt::rtio::EventLoop; use unstable::{run_in_bare_thread}; use rt::thread::Thread; use rt::task::Task; @@ -32,7 +37,7 @@ pub fn new_test_uv_sched() -> Scheduler { let queue = WorkQueue::new(); let queues = ~[queue.clone()]; - let mut sched = Scheduler::new(~UvEventLoop::new(), + let mut sched = Scheduler::new(~UvEventLoop::new() as ~EventLoop, queue, queues, SleeperList::new()); @@ -191,7 +196,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { } for i in range(0u, nthreads) { - let loop_ = ~UvEventLoop::new(); + let loop_ = ~UvEventLoop::new() as ~EventLoop; let mut sched = ~Scheduler::new(loop_, work_queues[i].clone(), work_queues.clone(), @@ -327,6 +332,12 @@ pub fn next_test_port() -> u16 { } } +/// Get a temporary path which could be the location of a unix socket +#[fixed_stack_segment] #[inline(never)] +pub fn next_test_unix() -> Path { + os::tmpdir().join(rand::task_rng().gen_ascii_str(20)) +} + /// Get a unique IPv4 localhost:port pair starting at 9600 pub fn next_test_ip4() -> SocketAddr { SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: next_test_port() } diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 647d88c26f2f5..070985fb0a5cf 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -71,9 +71,24 @@ pub fn default_sched_threads() -> uint { pub fn dumb_println(args: &fmt::Arguments) { use rt::io::native::stdio::stderr; - use rt::io::Writer; + use rt::io::{Writer, io_error, ResourceUnavailable}; + use rt::task::Task; + use rt::local::Local; + let mut out = stderr(); - fmt::writeln(&mut out as &mut Writer, args); + if Local::exists(None::) { + let mut again = true; + do io_error::cond.trap(|e| { + again = e.kind == ResourceUnavailable; + }).inside { + while again { + again = false; + fmt::writeln(&mut out as &mut Writer, args); + } + } + } else { + fmt::writeln(&mut out as &mut Writer, args); + } } pub fn abort(msg: &str) -> ! { diff --git a/src/libstd/rt/uv/addrinfo.rs b/src/libstd/rt/uv/addrinfo.rs index f2abcd3aca7e3..a1593d5c8db73 100644 --- a/src/libstd/rt/uv/addrinfo.rs +++ b/src/libstd/rt/uv/addrinfo.rs @@ -18,9 +18,10 @@ use rt::uv::uvll; use rt::uv::uvll::UV_GETADDRINFO; use rt::uv::{Loop, UvError, NativeHandle}; use rt::uv::status_to_maybe_uv_error; -use rt::uv::net::UvAddrInfo; +use rt::uv::net; +use ai = rt::io::net::addrinfo; -type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option); +type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &net::UvAddrInfo, Option); pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t); @@ -38,7 +39,7 @@ impl GetAddrInfoRequest { } pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>, - service: Option<&str>, hints: Option, + service: Option<&str>, hints: Option, cb: GetAddrInfoCallback) { assert!(node.is_some() || service.is_some()); @@ -72,8 +73,41 @@ impl GetAddrInfoRequest { cb(req, addrinfo, err) }; - // XXX: Implement hints - assert!(hints.is_none()); + let hint = hints.map(|hint| { + let mut flags = 0; + do each_ai_flag |cval, aival| { + if hint.flags & (aival as uint) != 0 { + flags |= cval as i32; + } + } + /* XXX: do we really want to support these? + let socktype = match hint.socktype { + Some(ai::Stream) => uvll::rust_SOCK_STREAM(), + Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(), + Some(ai::Raw) => uvll::rust_SOCK_RAW(), + None => 0, + }; + let protocol = match hint.protocol { + Some(ai::UDP) => uvll::rust_IPPROTO_UDP(), + Some(ai::TCP) => uvll::rust_IPPROTO_TCP(), + _ => 0, + }; + */ + let socktype = 0; + let protocol = 0; + + uvll::addrinfo { + ai_flags: flags, + ai_family: hint.family as c_int, + ai_socktype: socktype, + ai_protocol: protocol, + ai_addrlen: 0, + ai_canonname: null(), + ai_addr: null(), + ai_next: null(), + } + }); + let hint_ptr = hint.as_ref().map_default(null(), |x| x as *uvll::addrinfo); self.get_req_data().getaddrinfo_cb = Some(wrapper_cb); @@ -83,7 +117,7 @@ impl GetAddrInfoRequest { getaddrinfo_cb, c_node_ptr, c_service_ptr, - null())); + hint_ptr)); } extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t, @@ -91,7 +125,7 @@ impl GetAddrInfoRequest { res: *uvll::addrinfo) { let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req); let err = status_to_maybe_uv_error(status); - let addrinfo = UvAddrInfo(res); + let addrinfo = net::UvAddrInfo(res); let data = req.get_req_data(); (*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err); unsafe { @@ -137,6 +171,72 @@ impl GetAddrInfoRequest { } } +fn each_ai_flag(_f: &fn(c_int, ai::Flag)) { + /* XXX: do we really want to support these? + unsafe { + f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig); + f(uvll::rust_AI_ALL(), ai::All); + f(uvll::rust_AI_CANONNAME(), ai::CanonName); + f(uvll::rust_AI_NUMERICHOST(), ai::NumericHost); + f(uvll::rust_AI_NUMERICSERV(), ai::NumericServ); + f(uvll::rust_AI_PASSIVE(), ai::Passive); + f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped); + } + */ +} + +// Traverse the addrinfo linked list, producing a vector of Rust socket addresses +pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] { + unsafe { + let &net::UvAddrInfo(addr) = addr; + let mut addr = addr; + + let mut addrs = ~[]; + loop { + let uvaddr = net::sockaddr_to_UvSocketAddr((*addr).ai_addr); + let rustaddr = net::uv_socket_addr_to_socket_addr(uvaddr); + + let mut flags = 0; + do each_ai_flag |cval, aival| { + if (*addr).ai_flags & cval != 0 { + flags |= aival as uint; + } + } + + /* XXX: do we really want to support these + let protocol = match (*addr).ai_protocol { + p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP), + p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP), + _ => None, + }; + let socktype = match (*addr).ai_socktype { + p if p == uvll::rust_SOCK_STREAM() => Some(ai::Stream), + p if p == uvll::rust_SOCK_DGRAM() => Some(ai::Datagram), + p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw), + _ => None, + }; + */ + let protocol = None; + let socktype = None; + + addrs.push(ai::Info { + address: rustaddr, + family: (*addr).ai_family as uint, + socktype: socktype, + protocol: protocol, + flags: flags, + }); + if (*addr).ai_next.is_not_null() { + addr = (*addr).ai_next; + } else { + break; + } + } + + return addrs; + } +} + impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest { fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest { GetAddrInfoRequest(handle) @@ -150,7 +250,6 @@ impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest { mod test { use option::{Some, None}; use rt::uv::Loop; - use rt::uv::net::accum_sockaddrs; use rt::io::net::ip::{SocketAddr, Ipv4Addr}; use super::*; @@ -159,14 +258,14 @@ mod test { let mut loop_ = Loop::new(); let mut req = GetAddrInfoRequest::new(); do req.getaddrinfo(&loop_, Some("localhost"), None, None) |_, addrinfo, _| { - let sockaddrs = accum_sockaddrs(addrinfo); + let sockaddrs = accum_addrinfo(addrinfo); let mut found_local = false; let local_addr = &SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 0 }; for addr in sockaddrs.iter() { - found_local = found_local || addr == local_addr; + found_local = found_local || addr.address == *local_addr; } assert!(found_local); } diff --git a/src/libstd/rt/uv/async.rs b/src/libstd/rt/uv/async.rs index ff7bb9dd03abc..108aef43c3c9a 100644 --- a/src/libstd/rt/uv/async.rs +++ b/src/libstd/rt/uv/async.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::{c_int, c_void}; +use libc::c_int; use option::Some; use rt::uv::uvll; use rt::uv::uvll::UV_ASYNC; -use rt::uv::{Watcher, Loop, NativeHandle, AsyncCallback, NullCallback}; +use rt::uv::{Watcher, Loop, NativeHandle, AsyncCallback}; use rt::uv::WatcherInterop; use rt::uv::status_to_maybe_uv_error; @@ -47,27 +47,6 @@ impl AsyncWatcher { uvll::async_send(handle); } } - - pub fn close(self, cb: NullCallback) { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - - unsafe { - uvll::close(self.native_handle(), close_cb); - } - - extern fn close_cb(handle: *uvll::uv_stream_t) { - let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle); - { - let data = watcher.get_watcher_data(); - data.close_cb.take_unwrap()(); - } - watcher.drop_watcher_data(); - unsafe { uvll::free_handle(handle as *c_void); } - } - } } impl NativeHandle<*uvll::uv_async_t> for AsyncWatcher { diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 5d64ca4d755ce..d2ca15959b025 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -10,12 +10,13 @@ use prelude::*; use ptr::null; +use c_str; +use c_str::CString; use libc::c_void; use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, status_to_maybe_uv_error, UvError}; use rt::uv::uvll; use rt::uv::uvll::*; -use super::super::io::support::PathLike; use cast::transmute; use libc; use libc::{c_int}; @@ -36,74 +37,67 @@ impl FsRequest { fs_req } - pub fn open(self, loop_: &Loop, path: &P, flags: int, mode: int, - cb: FsCallback) { + pub fn open(self, loop_: &Loop, path: &CString, flags: int, mode: int, + cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_open(loop_.native_handle(), self.native_handle(), p, flags, mode, complete_cb_ptr) - }) }); + assert_eq!(ret, 0); } - pub fn open_sync(self, loop_: &Loop, path: &P, - flags: int, mode: int) -> Result { + pub fn open_sync(self, loop_: &Loop, path: &CString, + flags: int, mode: int) -> Result { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(None) }; - let result = path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + let result = path.with_ref(|p| unsafe { uvll::fs_open(loop_.native_handle(), self.native_handle(), p, flags, mode, complete_cb_ptr) - }) }); self.sync_cleanup(result) } - pub fn unlink(self, loop_: &Loop, path: &P, cb: FsCallback) { + pub fn unlink(self, loop_: &Loop, path: &CString, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { - uvll::fs_unlink(loop_.native_handle(), - self.native_handle(), p, complete_cb_ptr) - }) + let ret = path.with_ref(|p| unsafe { + uvll::fs_unlink(loop_.native_handle(), + self.native_handle(), p, complete_cb_ptr) }); + assert_eq!(ret, 0); } - pub fn unlink_sync(self, loop_: &Loop, path: &P) + pub fn unlink_sync(self, loop_: &Loop, path: &CString) -> Result { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(None) }; - let result = path.path_as_str(|p| { - p.with_c_str(|p| unsafe { - uvll::fs_unlink(loop_.native_handle(), - self.native_handle(), p, complete_cb_ptr) - }) + let result = path.with_ref(|p| unsafe { + uvll::fs_unlink(loop_.native_handle(), + self.native_handle(), p, complete_cb_ptr) }); self.sync_cleanup(result) } - pub fn stat(self, loop_: &Loop, path: &P, cb: FsCallback) { + pub fn stat(self, loop_: &Loop, path: &CString, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { - uvll::fs_stat(loop_.native_handle(), - self.native_handle(), p, complete_cb_ptr) - }) + let ret = path.with_ref(|p| unsafe { + uvll::fs_stat(loop_.native_handle(), + self.native_handle(), p, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) { @@ -113,11 +107,12 @@ impl FsRequest { }; let base_ptr = buf.base as *c_void; let len = buf.len as uint; - unsafe { + let ret = unsafe { uvll::fs_write(loop_.native_handle(), self.native_handle(), fd, base_ptr, len, offset, complete_cb_ptr) }; + assert_eq!(ret, 0); } pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) -> Result { @@ -142,11 +137,12 @@ impl FsRequest { }; let buf_ptr = buf.base as *c_void; let len = buf.len as uint; - unsafe { + let ret = unsafe { uvll::fs_read(loop_.native_handle(), self.native_handle(), fd, buf_ptr, len, offset, complete_cb_ptr) }; + assert_eq!(ret, 0); } pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) -> Result { @@ -169,10 +165,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - unsafe { + let ret = unsafe { uvll::fs_close(loop_.native_handle(), self.native_handle(), fd, complete_cb_ptr) }; + assert_eq!(ret, 0); } pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result { let complete_cb_ptr = { @@ -186,44 +183,41 @@ impl FsRequest { self.sync_cleanup(result) } - pub fn mkdir(self, loop_: &Loop, path: &P, mode: int, cb: FsCallback) { + pub fn mkdir(self, loop_: &Loop, path: &CString, mode: int, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_mkdir(loop_.native_handle(), - self.native_handle(), p, mode, complete_cb_ptr) - }) + self.native_handle(), p, mode, complete_cb_ptr) }); + assert_eq!(ret, 0); } - pub fn rmdir(self, loop_: &Loop, path: &P, cb: FsCallback) { + pub fn rmdir(self, loop_: &Loop, path: &CString, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_rmdir(loop_.native_handle(), - self.native_handle(), p, complete_cb_ptr) - }) + self.native_handle(), p, complete_cb_ptr) }); + assert_eq!(ret, 0); } - pub fn readdir(self, loop_: &Loop, path: &P, - flags: c_int, cb: FsCallback) { + pub fn readdir(self, loop_: &Loop, path: &CString, + flags: c_int, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_readdir(loop_.native_handle(), - self.native_handle(), p, flags, complete_cb_ptr) - }) + self.native_handle(), p, flags, complete_cb_ptr) }); + assert_eq!(ret, 0); } // accessors/utility funcs @@ -286,13 +280,10 @@ impl FsRequest { } } - pub fn get_paths(&mut self) -> ~[~str] { - use str; + pub fn each_path(&mut self, f: &fn(&CString)) { let ptr = self.get_ptr(); match self.get_result() { - n if (n <= 0) => { - ~[] - }, + n if (n <= 0) => {} n => { let n_len = n as uint; // we pass in the len that uv tells us is there @@ -301,11 +292,10 @@ impl FsRequest { // correctly delimited and we stray into garbage memory? // in any case, passing Some(n_len) fixes it and ensures // good results - let raw_path_strs = unsafe { - str::raw::from_c_multistring(ptr as *libc::c_char, Some(n_len)) }; - let raw_len = raw_path_strs.len(); - assert_eq!(raw_len, n_len); - raw_path_strs + unsafe { + c_str::from_c_multistring(ptr as *libc::c_char, + Some(n_len), f); + } } } } @@ -368,7 +358,6 @@ mod test { use vec; use str; use unstable::run_in_bare_thread; - use path::Path; use rt::uv::{Loop, Buf, slice_to_uv_buf}; use libc::{O_CREAT, O_RDWR, O_RDONLY, S_IWUSR, S_IRUSR}; @@ -391,10 +380,9 @@ mod test { let read_mem = vec::from_elem(read_buf_len, 0u8); let read_buf = slice_to_uv_buf(read_mem); let read_buf_ptr: *Buf = &read_buf; - let p = Path::new(path_str); let open_req = FsRequest::new(); - do open_req.open(&loop_, &p, create_flags as int, mode as int) - |req, uverr| { + do open_req.open(&loop_, &path_str.to_c_str(), create_flags as int, + mode as int) |req, uverr| { assert!(uverr.is_none()); let fd = req.get_result(); let buf = unsafe { *write_buf_ptr }; @@ -405,8 +393,8 @@ mod test { assert!(uverr.is_none()); let loop_ = req.get_loop(); let open_req = FsRequest::new(); - do open_req.open(&loop_, &Path::new(path_str), read_flags as int,0) - |req, uverr| { + do open_req.open(&loop_, &path_str.to_c_str(), + read_flags as int,0) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let fd = req.get_result(); @@ -431,7 +419,8 @@ mod test { assert!(uverr.is_none()); let loop_ = &req.get_loop(); let unlink_req = FsRequest::new(); - do unlink_req.unlink(loop_, &Path::new(path_str)) + do unlink_req.unlink(loop_, + &path_str.to_c_str()) |_,uverr| { assert!(uverr.is_none()); }; @@ -465,8 +454,8 @@ mod test { let write_buf = slice_to_uv_buf(write_val); // open/create let open_req = FsRequest::new(); - let result = open_req.open_sync(&loop_, &Path::new(path_str), - create_flags as int, mode as int); + let result = open_req.open_sync(&loop_, &path_str.to_c_str(), + create_flags as int, mode as int); assert!(result.is_ok()); let fd = result.unwrap(); // write @@ -479,7 +468,7 @@ mod test { assert!(result.is_ok()); // re-open let open_req = FsRequest::new(); - let result = open_req.open_sync(&loop_, &Path::new(path_str), + let result = open_req.open_sync(&loop_, &path_str.to_c_str(), read_flags as int,0); assert!(result.is_ok()); let len = 1028; @@ -503,7 +492,7 @@ mod test { assert!(result.is_ok()); // unlink let unlink_req = FsRequest::new(); - let result = unlink_req.unlink_sync(&loop_, &Path::new(path_str)); + let result = unlink_req.unlink_sync(&loop_, &path_str.to_c_str()); assert!(result.is_ok()); } else { fail!("nread was 0.. wudn't expectin' that."); } loop_.close(); @@ -539,8 +528,8 @@ mod test { let write_buf = slice_to_uv_buf(write_val); let write_buf_ptr: *Buf = &write_buf; let open_req = FsRequest::new(); - do open_req.open(&loop_, &path, create_flags as int, mode as int) - |req, uverr| { + do open_req.open(&loop_, &path.to_c_str(), create_flags as int, + mode as int) |req, uverr| { assert!(uverr.is_none()); let fd = req.get_result(); let buf = unsafe { *write_buf_ptr }; @@ -549,7 +538,7 @@ mod test { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat_req = FsRequest::new(); - do stat_req.stat(&loop_, &path) |req, uverr| { + do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat = req.get_stat(); @@ -560,11 +549,13 @@ mod test { assert!(uverr.is_none()); let loop_ = req.get_loop(); let unlink_req = FsRequest::new(); - do unlink_req.unlink(&loop_, &path) |req,uverr| { + do unlink_req.unlink(&loop_, + &path.to_c_str()) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat_req = FsRequest::new(); - do stat_req.stat(&loop_, &path) |_, uverr| { + do stat_req.stat(&loop_, + &path.to_c_str()) |_, uverr| { // should cause an error because the // file doesn't exist anymore assert!(uverr.is_some()); @@ -587,22 +578,23 @@ mod test { let mode = S_IWUSR | S_IRUSR; let mkdir_req = FsRequest::new(); - do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| { + do mkdir_req.mkdir(&loop_, &path.to_c_str(), + mode as int) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat_req = FsRequest::new(); - do stat_req.stat(&loop_, &path) |req, uverr| { + do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat = req.get_stat(); naive_print(&loop_, format!("{:?}", stat)); assert!(stat.is_dir()); let rmdir_req = FsRequest::new(); - do rmdir_req.rmdir(&loop_, &path) |req,uverr| { + do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat_req = FsRequest::new(); - do stat_req.stat(&loop_, &path) |_req, uverr| { + do stat_req.stat(&loop_, &path.to_c_str()) |_req, uverr| { assert!(uverr.is_some()); } } @@ -620,16 +612,17 @@ mod test { let mode = S_IWUSR | S_IRUSR; let mkdir_req = FsRequest::new(); - do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| { + do mkdir_req.mkdir(&loop_, &path.to_c_str(), mode as int) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let mkdir_req = FsRequest::new(); - do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| { + do mkdir_req.mkdir(&loop_, &path.to_c_str(), + mode as int) |req,uverr| { assert!(uverr.is_some()); let loop_ = req.get_loop(); let _stat = req.get_stat(); let rmdir_req = FsRequest::new(); - do rmdir_req.rmdir(&loop_, &path) |req,uverr| { + do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| { assert!(uverr.is_none()); let _loop = req.get_loop(); } @@ -645,7 +638,7 @@ mod test { let mut loop_ = Loop::new(); let path = "./tmp/never_existed_dir"; let rmdir_req = FsRequest::new(); - do rmdir_req.rmdir(&loop_, &path) |_req, uverr| { + do rmdir_req.rmdir(&loop_, &path.to_c_str()) |_req, uverr| { assert!(uverr.is_some()); } loop_.run(); diff --git a/src/libstd/rt/uv/idle.rs b/src/libstd/rt/uv/idle.rs index 8cbcd7b77c082..40f0750b2d074 100644 --- a/src/libstd/rt/uv/idle.rs +++ b/src/libstd/rt/uv/idle.rs @@ -11,7 +11,7 @@ use libc::c_int; use option::Some; use rt::uv::uvll; -use rt::uv::{Watcher, Loop, NativeHandle, IdleCallback, NullCallback}; +use rt::uv::{Watcher, Loop, NativeHandle, IdleCallback}; use rt::uv::status_to_maybe_uv_error; pub struct IdleWatcher(*uvll::uv_idle_t); @@ -20,9 +20,9 @@ impl Watcher for IdleWatcher { } impl IdleWatcher { pub fn new(loop_: &mut Loop) -> IdleWatcher { unsafe { - let handle = uvll::idle_new(); + let handle = uvll::malloc_handle(uvll::UV_IDLE); assert!(handle.is_not_null()); - assert!(0 == uvll::idle_init(loop_.native_handle(), handle)); + assert_eq!(uvll::idle_init(loop_.native_handle(), handle), 0); let mut watcher: IdleWatcher = NativeHandle::from_native_handle(handle); watcher.install_watcher_data(); return watcher @@ -36,29 +36,14 @@ impl IdleWatcher { } unsafe { - assert!(0 == uvll::idle_start(self.native_handle(), idle_cb)) - }; - - extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { - let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); - let data = idle_watcher.get_watcher_data(); - let cb: &IdleCallback = data.idle_cb.get_ref(); - let status = status_to_maybe_uv_error(status); - (*cb)(idle_watcher, status); + assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0) } } pub fn restart(&mut self) { unsafe { - assert!(0 == uvll::idle_start(self.native_handle(), idle_cb)) - }; - - extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { - let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); - let data = idle_watcher.get_watcher_data(); - let cb: &IdleCallback = data.idle_cb.get_ref(); - let status = status_to_maybe_uv_error(status); - (*cb)(idle_watcher, status); + assert!(self.get_watcher_data().idle_cb.is_some()); + assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0) } } @@ -68,30 +53,7 @@ impl IdleWatcher { // free unsafe { - assert!(0 == uvll::idle_stop(self.native_handle())); - } - } - - pub fn close(self, cb: NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb) }; - - extern fn close_cb(handle: *uvll::uv_idle_t) { - unsafe { - let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); - { - let data = idle_watcher.get_watcher_data(); - data.close_cb.take_unwrap()(); - } - idle_watcher.drop_watcher_data(); - uvll::idle_delete(handle); - } + assert_eq!(uvll::idle_stop(self.native_handle()), 0); } } } @@ -105,6 +67,14 @@ impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher { } } +extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { + let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); + let data = idle_watcher.get_watcher_data(); + let cb: &IdleCallback = data.idle_cb.get_ref(); + let status = status_to_maybe_uv_error(status); + (*cb)(idle_watcher, status); +} + #[cfg(test)] mod test { diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 3a6a3acbc5342..c92a54425bf4f 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -48,6 +48,7 @@ use cast::transmute; use ptr::null; use unstable::finally::Finally; use rt::io::net::ip::SocketAddr; +use rt::io::signal::Signum; use rt::io::IoError; @@ -60,6 +61,7 @@ pub use self::timer::TimerWatcher; pub use self::async::AsyncWatcher; pub use self::process::Process; pub use self::pipe::Pipe; +pub use self::signal::SignalWatcher; /// The implementation of `rtio` for libuv pub mod uvio; @@ -75,6 +77,8 @@ pub mod async; pub mod addrinfo; pub mod process; pub mod pipe; +pub mod tty; +pub mod signal; /// XXX: Loop(*handle) is buggy with destructors. Normal structs /// with dtors may not be destructured, but tuple structs can, @@ -83,6 +87,14 @@ pub struct Loop { priv handle: *uvll::uv_loop_t } +pub struct Handle(*uvll::uv_handle_t); + +impl Watcher for Handle {} +impl NativeHandle<*uvll::uv_handle_t> for Handle { + fn from_native_handle(h: *uvll::uv_handle_t) -> Handle { Handle(h) } + fn native_handle(&self) -> *uvll::uv_handle_t { **self } +} + /// The trait implemented by uv 'watchers' (handles). Watchers are /// non-owning wrappers around the uv handles and are not completely /// safe - there may be multiple instances for a single underlying @@ -137,6 +149,7 @@ pub type TimerCallback = ~fn(TimerWatcher, Option); pub type AsyncCallback = ~fn(AsyncWatcher, Option); pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option); pub type UdpSendCallback = ~fn(UdpWatcher, Option); +pub type SignalCallback = ~fn(SignalWatcher, Signum); /// Callbacks used by StreamWatchers, set as custom data on the foreign handle. @@ -153,6 +166,7 @@ struct WatcherData { udp_recv_cb: Option, udp_send_cb: Option, exit_cb: Option, + signal_cb: Option, } pub trait WatcherInterop { @@ -160,6 +174,8 @@ pub trait WatcherInterop { fn install_watcher_data(&mut self); fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData; fn drop_watcher_data(&mut self); + fn close(self, cb: NullCallback); + fn close_async(self); } impl> WatcherInterop for W { @@ -186,6 +202,7 @@ impl> WatcherInterop for W { udp_recv_cb: None, udp_send_cb: None, exit_cb: None, + signal_cb: None, }; let data = transmute::<~WatcherData, *c_void>(data); uvll::set_data_for_uv_handle(self.native_handle(), data); @@ -207,6 +224,34 @@ impl> WatcherInterop for W { uvll::set_data_for_uv_handle(self.native_handle(), null::<()>()); } } + + fn close(self, cb: NullCallback) { + let mut this = self; + { + let data = this.get_watcher_data(); + assert!(data.close_cb.is_none()); + data.close_cb = Some(cb); + } + + unsafe { uvll::close(this.native_handle(), close_cb); } + + extern fn close_cb(handle: *uvll::uv_handle_t) { + let mut h: Handle = NativeHandle::from_native_handle(handle); + h.get_watcher_data().close_cb.take_unwrap()(); + h.drop_watcher_data(); + unsafe { uvll::free_handle(handle as *c_void) } + } + } + + fn close_async(self) { + unsafe { uvll::close(self.native_handle(), close_cb); } + + extern fn close_cb(handle: *uvll::uv_handle_t) { + let mut h: Handle = NativeHandle::from_native_handle(handle); + h.drop_watcher_data(); + unsafe { uvll::free_handle(handle as *c_void) } + } + } } // XXX: Need to define the error constants like EOF so they can be @@ -297,6 +342,13 @@ pub fn status_to_maybe_uv_error(status: c_int) -> Option /// The uv buffer type pub type Buf = uvll::uv_buf_t; +pub fn empty_buf() -> Buf { + uvll::uv_buf_t { + base: null(), + len: 0, + } +} + /// Borrow a slice to a Buf pub fn slice_to_uv_buf(v: &[u8]) -> Buf { let data = vec::raw::to_ptr(v); diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index a2608bf6b2406..77de8348c1461 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -13,8 +13,8 @@ use libc::{size_t, ssize_t, c_int, c_void, c_uint}; use rt::uv::uvll; use rt::uv::uvll::*; use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback, UdpReceiveCallback, UdpSendCallback}; -use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback, - status_to_maybe_uv_error, vec_to_uv_buf}; +use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, + status_to_maybe_uv_error, empty_buf}; use rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr}; use vec; use str; @@ -27,7 +27,7 @@ pub enum UvSocketAddr { UvIpv6SocketAddr(*sockaddr_in6), } -fn sockaddr_to_UvSocketAddr(addr: *uvll::sockaddr) -> UvSocketAddr { +pub fn sockaddr_to_UvSocketAddr(addr: *uvll::sockaddr) -> UvSocketAddr { unsafe { assert!((is_ip4_addr(addr) || is_ip6_addr(addr))); assert!(!(is_ip4_addr(addr) && is_ip6_addr(addr))); @@ -96,28 +96,6 @@ pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr { uv_socket_addr_as_socket_addr(addr, util::id) } -// Traverse the addrinfo linked list, producing a vector of Rust socket addresses -pub fn accum_sockaddrs(addr: &UvAddrInfo) -> ~[SocketAddr] { - unsafe { - let &UvAddrInfo(addr) = addr; - let mut addr = addr; - - let mut addrs = ~[]; - loop { - let uvaddr = sockaddr_to_UvSocketAddr((*addr).ai_addr); - let rustaddr = uv_socket_addr_to_socket_addr(uvaddr); - addrs.push(rustaddr); - if (*addr).ai_next.is_not_null() { - addr = (*addr).ai_next; - } else { - break; - } - } - - return addrs; - } -} - #[cfg(test)] #[test] fn test_ip4_conversion() { @@ -141,23 +119,17 @@ impl Watcher for StreamWatcher { } impl StreamWatcher { pub fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) { - { - let data = self.get_watcher_data(); - data.alloc_cb = Some(alloc); - data.read_cb = Some(cb); - } - - let ret = unsafe { uvll::read_start(self.native_handle(), alloc_cb, read_cb) }; - - if ret != 0 { - // uvll::read_start failed, so read_cb will not be called. - // Call it manually for scheduling. - call_read_cb(self.native_handle(), ret as ssize_t); - } - - fn call_read_cb(stream: *uvll::uv_stream_t, errno: ssize_t) { - #[fixed_stack_segment]; #[inline(never)]; - read_cb(stream, errno, vec_to_uv_buf(~[])); + unsafe { + match uvll::read_start(self.native_handle(), alloc_cb, read_cb) { + 0 => { + let data = self.get_watcher_data(); + data.alloc_cb = Some(alloc); + data.read_cb = Some(cb); + } + n => { + cb(*self, 0, empty_buf(), Some(UvError(n))) + } + } } extern fn alloc_cb(stream: *uvll::uv_stream_t, suggested_size: size_t) -> Buf { @@ -181,20 +153,25 @@ impl StreamWatcher { // but read_stop may be called from inside one of them and we // would end up freeing the in-use environment let handle = self.native_handle(); - unsafe { uvll::read_stop(handle); } + unsafe { assert_eq!(uvll::read_stop(handle), 0); } } pub fn write(&mut self, buf: Buf, cb: ConnectionCallback) { - { - let data = self.get_watcher_data(); - assert!(data.write_cb.is_none()); - data.write_cb = Some(cb); - } - let req = WriteRequest::new(); - unsafe { - assert_eq!(0, uvll::write(req.native_handle(), self.native_handle(), [buf], write_cb)); - } + return unsafe { + match uvll::write(req.native_handle(), self.native_handle(), + [buf], write_cb) { + 0 => { + let data = self.get_watcher_data(); + assert!(data.write_cb.is_none()); + data.write_cb = Some(cb); + } + n => { + req.delete(); + cb(*self, Some(UvError(n))) + } + } + }; extern fn write_cb(req: *uvll::uv_write_t, status: c_int) { let write_request: WriteRequest = NativeHandle::from_native_handle(req); @@ -206,30 +183,36 @@ impl StreamWatcher { } } - pub fn accept(&mut self, stream: StreamWatcher) { - let self_handle = self.native_handle() as *c_void; - let stream_handle = stream.native_handle() as *c_void; - assert_eq!(0, unsafe { uvll::accept(self_handle, stream_handle) } ); - } - pub fn close(self, cb: NullCallback) { + pub fn listen(&mut self, cb: ConnectionCallback) -> Result<(), UvError> { { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); + let data = self.get_watcher_data(); + assert!(data.connect_cb.is_none()); + data.connect_cb = Some(cb); } - unsafe { uvll::close(self.native_handle(), close_cb); } + return unsafe { + static BACKLOG: c_int = 128; // XXX should be configurable + match uvll::listen(self.native_handle(), BACKLOG, connection_cb) { + 0 => Ok(()), + n => Err(UvError(n)) + } + }; - extern fn close_cb(handle: *uvll::uv_stream_t) { + extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) { + rtdebug!("connection_cb"); let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - let cb = stream_watcher.get_watcher_data().close_cb.take_unwrap(); - stream_watcher.drop_watcher_data(); - unsafe { free_handle(handle as *c_void) } - cb(); + let cb = stream_watcher.get_watcher_data().connect_cb.get_ref(); + let status = status_to_maybe_uv_error(status); + (*cb)(stream_watcher, status); } } + + pub fn accept(&mut self, stream: StreamWatcher) { + let self_handle = self.native_handle() as *c_void; + let stream_handle = stream.native_handle() as *c_void; + assert_eq!(0, unsafe { uvll::accept(self_handle, stream_handle) } ); + } } impl NativeHandle<*uvll::uv_stream_t> for StreamWatcher { @@ -300,28 +283,6 @@ impl TcpWatcher { } } - pub fn listen(&mut self, cb: ConnectionCallback) { - { - let data = self.get_watcher_data(); - assert!(data.connect_cb.is_none()); - data.connect_cb = Some(cb); - } - - unsafe { - static BACKLOG: c_int = 128; // XXX should be configurable - // XXX: This can probably fail - assert_eq!(0, uvll::listen(self.native_handle(), BACKLOG, connection_cb)); - } - - extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) { - rtdebug!("connection_cb"); - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - let cb = stream_watcher.get_watcher_data().connect_cb.get_ref(); - let status = status_to_maybe_uv_error(status); - (*cb)(stream_watcher, status); - } - } - pub fn as_stream(&self) -> StreamWatcher { NativeHandle::from_native_handle(self.native_handle() as *uvll::uv_stream_t) } @@ -433,25 +394,6 @@ impl UdpWatcher { cb(udp_watcher, status); } } - - pub fn close(self, cb: NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb); } - - extern fn close_cb(handle: *uvll::uv_udp_t) { - let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); - let cb = udp_watcher.get_watcher_data().close_cb.take_unwrap(); - udp_watcher.drop_watcher_data(); - unsafe { free_handle(handle as *c_void) } - cb(); - } - } } impl NativeHandle<*uvll::uv_udp_t> for UdpWatcher { @@ -464,12 +406,12 @@ impl NativeHandle<*uvll::uv_udp_t> for UdpWatcher { } // uv_connect_t is a subclass of uv_req_t -struct ConnectRequest(*uvll::uv_connect_t); +pub struct ConnectRequest(*uvll::uv_connect_t); impl Request for ConnectRequest { } impl ConnectRequest { - fn new() -> ConnectRequest { + pub fn new() -> ConnectRequest { let connect_handle = unsafe { malloc_req(UV_CONNECT) }; assert!(connect_handle.is_not_null()); ConnectRequest(connect_handle as *uvll::uv_connect_t) @@ -644,7 +586,8 @@ mod test { server_tcp_watcher.bind(addr); let loop_ = loop_; rtdebug!("listening"); - do server_tcp_watcher.listen |mut server_stream_watcher, status| { + let mut stream = server_tcp_watcher.as_stream(); + let res = do stream.listen |mut server_stream_watcher, status| { rtdebug!("listened!"); assert!(status.is_none()); let mut loop_ = loop_; @@ -678,7 +621,9 @@ mod test { } count_cell.put_back(count); } - } + }; + + assert!(res.is_ok()); let client_thread = do Thread::start { rtdebug!("starting client thread"); @@ -705,7 +650,7 @@ mod test { loop_.run(); loop_.close(); client_thread.join(); - } + }; } #[test] @@ -718,7 +663,8 @@ mod test { server_tcp_watcher.bind(addr); let loop_ = loop_; rtdebug!("listening"); - do server_tcp_watcher.listen |mut server_stream_watcher, status| { + let mut stream = server_tcp_watcher.as_stream(); + let res = do stream.listen |mut server_stream_watcher, status| { rtdebug!("listened!"); assert!(status.is_none()); let mut loop_ = loop_; @@ -754,7 +700,8 @@ mod test { } count_cell.put_back(count); } - } + }; + assert!(res.is_ok()); let client_thread = do Thread::start { rtdebug!("starting client thread"); diff --git a/src/libstd/rt/uv/pipe.rs b/src/libstd/rt/uv/pipe.rs index 1147c731a60c5..74b9312954c83 100644 --- a/src/libstd/rt/uv/pipe.rs +++ b/src/libstd/rt/uv/pipe.rs @@ -10,6 +10,7 @@ use prelude::*; use libc; +use c_str::CString; use rt::uv; use rt::uv::net; @@ -37,23 +38,54 @@ impl Pipe { net::StreamWatcher(**self as *uvll::uv_stream_t) } - pub fn close(self, cb: uv::NullCallback) { + #[fixed_stack_segment] #[inline(never)] + pub fn open(&mut self, file: libc::c_int) -> Result<(), uv::UvError> { + match unsafe { uvll::pipe_open(self.native_handle(), file) } { + 0 => Ok(()), + n => Err(uv::UvError(n)) + } + } + + #[fixed_stack_segment] #[inline(never)] + pub fn bind(&mut self, name: &CString) -> Result<(), uv::UvError> { + do name.with_ref |name| { + match unsafe { uvll::pipe_bind(self.native_handle(), name) } { + 0 => Ok(()), + n => Err(uv::UvError(n)) + } + } + } + + #[fixed_stack_segment] #[inline(never)] + pub fn connect(&mut self, name: &CString, cb: uv::ConnectionCallback) { { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); + let data = self.get_watcher_data(); + assert!(data.connect_cb.is_none()); + data.connect_cb = Some(cb); } - unsafe { uvll::close(self.native_handle(), close_cb); } + let connect = net::ConnectRequest::new(); + let name = do name.with_ref |p| { p }; - extern fn close_cb(handle: *uvll::uv_pipe_t) { - let mut process: Pipe = uv::NativeHandle::from_native_handle(handle); - process.get_watcher_data().close_cb.take_unwrap()(); - process.drop_watcher_data(); - unsafe { uvll::free_handle(handle as *libc::c_void) } + unsafe { + uvll::pipe_connect(connect.native_handle(), + self.native_handle(), + name, + connect_cb) + } + + extern "C" fn connect_cb(req: *uvll::uv_connect_t, status: libc::c_int) { + let connect_request: net::ConnectRequest = + uv::NativeHandle::from_native_handle(req); + let mut stream_watcher = connect_request.stream(); + connect_request.delete(); + + let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap(); + let status = uv::status_to_maybe_uv_error(status); + cb(stream_watcher, status); } } + } impl uv::NativeHandle<*uvll::uv_pipe_t> for Pipe { diff --git a/src/libstd/rt/uv/process.rs b/src/libstd/rt/uv/process.rs index 176754de8f745..f0d0afeb6aa40 100644 --- a/src/libstd/rt/uv/process.rs +++ b/src/libstd/rt/uv/process.rs @@ -12,12 +12,11 @@ use prelude::*; use cell::Cell; use libc; use ptr; -use util; use vec; use rt::io::process::*; use rt::uv; -use rt::uv::uvio::UvPipeStream; +use rt::uv::uvio::{UvPipeStream, UvUnboundPipe}; use rt::uv::uvll; /// A process wraps the handle of the underlying uv_process_t. @@ -42,9 +41,9 @@ impl Process { /// /// Returns either the corresponding process object or an error which /// occurred. - pub fn spawn(&mut self, loop_: &uv::Loop, mut config: ProcessConfig, + pub fn spawn(&mut self, loop_: &uv::Loop, config: ProcessConfig, exit_cb: uv::ExitCallback) - -> Result<~[Option], uv::UvError> + -> Result<~[Option<~UvPipeStream>], uv::UvError> { let cwd = config.cwd.map(|s| s.to_c_str()); @@ -62,13 +61,14 @@ impl Process { err); } - let io = util::replace(&mut config.io, ~[]); + let io = config.io; let mut stdio = vec::with_capacity::(io.len()); let mut ret_io = vec::with_capacity(io.len()); unsafe { vec::raw::set_len(&mut stdio, io.len()); - for (slot, other) in stdio.iter().zip(io.move_iter()) { - let io = set_stdio(slot as *uvll::uv_stdio_container_t, other); + for (slot, other) in stdio.iter().zip(io.iter()) { + let io = set_stdio(slot as *uvll::uv_stdio_container_t, other, + loop_); ret_io.push(io); } } @@ -122,30 +122,12 @@ impl Process { pub fn pid(&self) -> libc::pid_t { unsafe { uvll::process_pid(**self) as libc::pid_t } } - - /// Closes this handle, invoking the specified callback once closed - pub fn close(self, cb: uv::NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb); } - - extern fn close_cb(handle: *uvll::uv_process_t) { - let mut process: Process = uv::NativeHandle::from_native_handle(handle); - process.get_watcher_data().close_cb.take_unwrap()(); - process.drop_watcher_data(); - unsafe { uvll::free_handle(handle as *libc::c_void) } - } - } } unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, - io: StdioContainer) -> Option { - match io { + io: &StdioContainer, + loop_: &uv::Loop) -> Option<~UvPipeStream> { + match *io { Ignored => { uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE); None @@ -155,7 +137,7 @@ unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, uvll::set_stdio_container_fd(dst, fd); None } - CreatePipe(pipe, readable, writable) => { + CreatePipe(readable, writable) => { let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int; if readable { flags |= uvll::STDIO_READABLE_PIPE as libc::c_int; @@ -163,10 +145,11 @@ unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, if writable { flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int; } + let pipe = UvUnboundPipe::new(loop_); let handle = pipe.pipe.as_stream().native_handle(); uvll::set_stdio_container_flags(dst, flags); uvll::set_stdio_container_stream(dst, handle); - Some(pipe.bind()) + Some(~UvPipeStream::new(pipe)) } } } diff --git a/src/libstd/rt/uv/signal.rs b/src/libstd/rt/uv/signal.rs new file mode 100644 index 0000000000000..3252c89673d6b --- /dev/null +++ b/src/libstd/rt/uv/signal.rs @@ -0,0 +1,73 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cast; +use option::Some; +use libc::c_int; +use result::{Err, Ok, Result}; +use rt::io::signal::Signum; +use rt::uv::{Loop, NativeHandle, SignalCallback, UvError, Watcher}; +use rt::uv::uvll; + +pub struct SignalWatcher(*uvll::uv_signal_t); + +impl Watcher for SignalWatcher { } + +impl SignalWatcher { + pub fn new(loop_: &mut Loop) -> SignalWatcher { + unsafe { + let handle = uvll::malloc_handle(uvll::UV_SIGNAL); + assert!(handle.is_not_null()); + assert!(0 == uvll::signal_init(loop_.native_handle(), handle)); + let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle); + watcher.install_watcher_data(); + return watcher; + } + } + + pub fn start(&mut self, signum: Signum, callback: SignalCallback) + -> Result<(), UvError> + { + return unsafe { + match uvll::signal_start(self.native_handle(), signal_cb, + signum as c_int) { + 0 => { + let data = self.get_watcher_data(); + data.signal_cb = Some(callback); + Ok(()) + } + n => Err(UvError(n)), + } + }; + + extern fn signal_cb(handle: *uvll::uv_signal_t, signum: c_int) { + let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle); + let data = watcher.get_watcher_data(); + let cb = data.signal_cb.get_ref(); + (*cb)(watcher, unsafe { cast::transmute(signum as int) }); + } + } + + pub fn stop(&mut self) { + unsafe { + uvll::signal_stop(self.native_handle()); + } + } +} + +impl NativeHandle<*uvll::uv_signal_t> for SignalWatcher { + fn from_native_handle(handle: *uvll::uv_signal_t) -> SignalWatcher { + SignalWatcher(handle) + } + + fn native_handle(&self) -> *uvll::uv_signal_t { + match self { &SignalWatcher(ptr) => ptr } + } +} diff --git a/src/libstd/rt/uv/timer.rs b/src/libstd/rt/uv/timer.rs index 7b09cf2eb0e3a..fb3c84df39f9b 100644 --- a/src/libstd/rt/uv/timer.rs +++ b/src/libstd/rt/uv/timer.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::{c_void, c_int}; +use libc::c_int; use option::Some; use rt::uv::uvll; -use rt::uv::{Watcher, Loop, NativeHandle, TimerCallback, NullCallback}; +use rt::uv::{Watcher, Loop, NativeHandle, TimerCallback}; use rt::uv::status_to_maybe_uv_error; pub struct TimerWatcher(*uvll::uv_timer_t); @@ -53,31 +53,6 @@ impl TimerWatcher { uvll::timer_stop(self.native_handle()); } } - - pub fn close(self, cb: NullCallback) { - let mut watcher = self; - { - let data = watcher.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { - uvll::close(watcher.native_handle(), close_cb); - } - - extern fn close_cb(handle: *uvll::uv_timer_t) { - let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle); - { - let data = watcher.get_watcher_data(); - data.close_cb.take_unwrap()(); - } - watcher.drop_watcher_data(); - unsafe { - uvll::free_handle(handle as *c_void); - } - } - } } impl NativeHandle<*uvll::uv_timer_t> for TimerWatcher { diff --git a/src/libstd/rt/uv/tty.rs b/src/libstd/rt/uv/tty.rs new file mode 100644 index 0000000000000..f44c5ae8eff61 --- /dev/null +++ b/src/libstd/rt/uv/tty.rs @@ -0,0 +1,84 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use prelude::*; +use libc; + +use rt::uv; +use rt::uv::net; +use rt::uv::uvll; + +/// A process wraps the handle of the underlying uv_process_t. +pub struct TTY(*uvll::uv_tty_t); + +impl uv::Watcher for TTY {} + +impl TTY { + #[fixed_stack_segment] #[inline(never)] + pub fn new(loop_: &uv::Loop, fd: libc::c_int, readable: bool) -> + Result + { + let handle = unsafe { uvll::malloc_handle(uvll::UV_TTY) }; + assert!(handle.is_not_null()); + + let ret = unsafe { + uvll::tty_init(loop_.native_handle(), handle, fd as libc::c_int, + readable as libc::c_int) + }; + match ret { + 0 => { + let mut ret: TTY = uv::NativeHandle::from_native_handle(handle); + ret.install_watcher_data(); + Ok(ret) + } + n => { + unsafe { uvll::free_handle(handle); } + Err(uv::UvError(n)) + } + } + } + + pub fn as_stream(&self) -> net::StreamWatcher { + net::StreamWatcher(**self as *uvll::uv_stream_t) + } + + #[fixed_stack_segment] #[inline(never)] + pub fn set_mode(&self, raw: bool) -> Result<(), uv::UvError> { + let raw = raw as libc::c_int; + match unsafe { uvll::tty_set_mode(self.native_handle(), raw) } { + 0 => Ok(()), + n => Err(uv::UvError(n)) + } + } + + #[fixed_stack_segment] #[inline(never)] #[allow(unused_mut)] + pub fn get_winsize(&self) -> Result<(int, int), uv::UvError> { + let mut width: libc::c_int = 0; + let mut height: libc::c_int = 0; + let widthptr: *libc::c_int = &width; + let heightptr: *libc::c_int = &width; + + match unsafe { uvll::tty_get_winsize(self.native_handle(), + widthptr, heightptr) } { + 0 => Ok((width as int, height as int)), + n => Err(uv::UvError(n)) + } + } +} + +impl uv::NativeHandle<*uvll::uv_tty_t> for TTY { + fn from_native_handle(handle: *uvll::uv_tty_t) -> TTY { + TTY(handle) + } + fn native_handle(&self) -> *uvll::uv_tty_t { + match self { &TTY(ptr) => ptr } + } +} + diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 8dd0f8a6b106e..29370c484eb5a 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -8,17 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use c_str::ToCStr; +use c_str::{ToCStr, CString}; use cast::transmute; use cast; use cell::Cell; use clone::Clone; +use comm::{SendDeferred, SharedChan}; use libc::{c_int, c_uint, c_void, pid_t}; use ops::Drop; use option::*; use ptr; use str; -use str::Str; use result::*; use rt::io::IoError; use rt::io::net::ip::{SocketAddr, IpAddr}; @@ -32,17 +32,18 @@ use rt::tube::Tube; use rt::task::SchedHome; use rt::uv::*; use rt::uv::idle::IdleWatcher; -use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr, accum_sockaddrs}; -use rt::uv::addrinfo::GetAddrInfoRequest; +use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; +use rt::uv::addrinfo::{GetAddrInfoRequest, accum_addrinfo}; use unstable::sync::Exclusive; use path::{GenericPath, Path}; -use super::super::io::support::PathLike; use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, S_IRUSR, S_IWUSR, S_IRWXU}; use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create, CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite, FileStat}; +use rt::io::signal::Signum; use task; +use ai = rt::io::net::addrinfo; #[cfg(test)] use container::Container; #[cfg(test)] use unstable::run_in_bare_thread; @@ -214,11 +215,11 @@ impl EventLoop for UvEventLoop { fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback { let idle_watcher = IdleWatcher::new(self.uvio.uv_loop()); - return ~UvPausibleIdleCallback { + ~UvPausibleIdleCallback { watcher: idle_watcher, idle_flag: false, closed: false - }; + } as ~PausibleIdleCallback } fn callback_ms(&mut self, ms: u64, f: ~fn()) { @@ -230,12 +231,12 @@ impl EventLoop for UvEventLoop { } } - fn remote_callback(&mut self, f: ~fn()) -> ~RemoteCallbackObject { - ~UvRemoteCallback::new(self.uvio.uv_loop(), f) + fn remote_callback(&mut self, f: ~fn()) -> ~RemoteCallback { + ~UvRemoteCallback::new(self.uvio.uv_loop(), f) as ~RemoteCallback } - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { - Some(&mut self.uvio) + fn io<'a>(&'a mut self, f: &fn(&'a mut IoFactory)) { + f(&mut self.uvio as &mut IoFactory) } } @@ -245,30 +246,30 @@ pub struct UvPausibleIdleCallback { priv closed: bool } -impl UvPausibleIdleCallback { +impl PausibleIdleCallback for UvPausibleIdleCallback { #[inline] - pub fn start(&mut self, f: ~fn()) { + fn start(&mut self, f: ~fn()) { do self.watcher.start |_idle_watcher, _status| { f(); }; self.idle_flag = true; } #[inline] - pub fn pause(&mut self) { + fn pause(&mut self) { if self.idle_flag == true { self.watcher.stop(); self.idle_flag = false; } } #[inline] - pub fn resume(&mut self) { + fn resume(&mut self) { if self.idle_flag == false { self.watcher.restart(); self.idle_flag = true; } } #[inline] - pub fn close(&mut self) { + fn close(&mut self) { self.pause(); if !self.closed { self.closed = true; @@ -414,9 +415,9 @@ impl UvIoFactory { /// Helper for a variety of simple uv_fs_* functions that /// have no ret val -fn uv_fs_helper(loop_: &mut Loop, path: &P, - cb: ~fn(&mut FsRequest, &mut Loop, &P, - ~fn(&FsRequest, Option))) +fn uv_fs_helper(loop_: &mut Loop, path: &CString, + cb: ~fn(&mut FsRequest, &mut Loop, &CString, + ~fn(&FsRequest, Option))) -> Result<(), IoError> { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -446,11 +447,11 @@ impl IoFactory for UvIoFactory { // Connect to an address and return a new stream // NB: This blocks the task waiting on the connection. // It would probably be better to return a future - fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStreamObject, IoError> { + fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError> { // Create a cell in the task to hold the result. We will fill // the cell before resuming the task. let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; + let result_cell_ptr: *Cell> = &result_cell; // Block this task and take ownership, switch to scheduler context do task::unkillable { // FIXME(#8674) @@ -466,7 +467,8 @@ impl IoFactory for UvIoFactory { None => { let tcp = NativeHandle::from_native_handle(stream.native_handle()); let home = get_handle_to_current_scheduler!(); - let res = Ok(~UvTcpStream { watcher: tcp, home: home }); + let res = Ok(~UvTcpStream { watcher: tcp, home: home } + as ~RtioTcpStream); // Store the stream in the task's stack unsafe { (*result_cell_ptr).put_back(res); } @@ -493,12 +495,12 @@ impl IoFactory for UvIoFactory { return result_cell.take(); } - fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError> { + fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListener, IoError> { let mut watcher = TcpWatcher::new(self.uv_loop()); match watcher.bind(addr) { Ok(_) => { let home = get_handle_to_current_scheduler!(); - Ok(~UvTcpListener::new(watcher, home)) + Ok(~UvTcpListener::new(watcher, home) as ~RtioTcpListener) } Err(uverr) => { do task::unkillable { // FIXME(#8674) @@ -516,12 +518,12 @@ impl IoFactory for UvIoFactory { } } - fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError> { + fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError> { let mut watcher = UdpWatcher::new(self.uv_loop()); match watcher.bind(addr) { Ok(_) => { let home = get_handle_to_current_scheduler!(); - Ok(~UvUdpSocket { watcher: watcher, home: home }) + Ok(~UvUdpSocket { watcher: watcher, home: home } as ~RtioUdpSocket) } Err(uverr) => { do task::unkillable { // FIXME(#8674) @@ -539,19 +541,19 @@ impl IoFactory for UvIoFactory { } } - fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError> { + fn timer_init(&mut self) -> Result<~RtioTimer, IoError> { let watcher = TimerWatcher::new(self.uv_loop()); let home = get_handle_to_current_scheduler!(); - Ok(~UvTimer::new(watcher, home)) + Ok(~UvTimer::new(watcher, home) as ~RtioTimer) } - fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream { + fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream { let loop_ = Loop {handle: self.uv_loop().native_handle()}; let home = get_handle_to_current_scheduler!(); - ~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream + ~UvFileStream::new(loop_, fd, close, home) as ~RtioFileStream } - fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) + fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError> { let mut flags = match fm { Open => 0, @@ -588,7 +590,7 @@ impl IoFactory for UvIoFactory { let home = get_handle_to_current_scheduler!(); let fd = req.get_result() as c_int; let fs = ~UvFileStream::new( - loop_, fd, true, home) as ~RtioFileStream; + loop_, fd, CloseSynchronously, home) as ~RtioFileStream; let res = Ok(fs); unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); @@ -606,14 +608,14 @@ impl IoFactory for UvIoFactory { return result_cell.take(); } - fn fs_unlink(&mut self, path: &P) -> Result<(), IoError> { + fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError> { do uv_fs_helper(self.uv_loop(), path) |unlink_req, l, p, cb| { do unlink_req.unlink(l, p) |req, err| { cb(req, err) }; } } - fn fs_stat(&mut self, path: &P) -> Result { + fn fs_stat(&mut self, path: &CString) -> Result { use str::StrSlice; let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell { let stat = req.get_stat(); Ok(FileStat { - path: Path::new(path_str.as_slice()), + path: path_instance.take(), is_file: stat.is_file(), is_dir: stat.is_dir(), device: stat.st_dev, @@ -658,12 +661,16 @@ impl IoFactory for UvIoFactory { return result_cell.take(); } - fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError> { + fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, + hint: Option) -> Result<~[ai::Info], IoError> { let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; - let host_ptr: *&str = &host; + let result_cell_ptr: *Cell> = &result_cell; + let host_ptr: *Option<&str> = &host; + let servname_ptr: *Option<&str> = &servname; + let hint_ptr: *Option = &hint; let addrinfo_req = GetAddrInfoRequest::new(); let addrinfo_req_cell = Cell::new(addrinfo_req); + do task::unkillable { // FIXME(#8674) let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_, task| { @@ -671,10 +678,10 @@ impl IoFactory for UvIoFactory { let mut addrinfo_req = addrinfo_req_cell.take(); unsafe { do addrinfo_req.getaddrinfo(self.uv_loop(), - Some(*host_ptr), - None, None) |_, addrinfo, err| { + *host_ptr, *servname_ptr, + *hint_ptr) |_, addrinfo, err| { let res = match err { - None => Ok(accum_sockaddrs(addrinfo).map(|addr| addr.ip.clone())), + None => Ok(accum_addrinfo(addrinfo)), Some(err) => Err(uv_error_to_io_error(err)) }; (*result_cell_ptr).put_back(res); @@ -688,7 +695,7 @@ impl IoFactory for UvIoFactory { assert!(!result_cell.is_empty()); return result_cell.take(); } - fn fs_mkdir(&mut self, path: &P) -> Result<(), IoError> { + fn fs_mkdir(&mut self, path: &CString) -> Result<(), IoError> { let mode = S_IRWXU as int; do uv_fs_helper(self.uv_loop(), path) |mkdir_req, l, p, cb| { do mkdir_req.mkdir(l, p, mode as int) |req, err| { @@ -696,14 +703,14 @@ impl IoFactory for UvIoFactory { }; } } - fn fs_rmdir(&mut self, path: &P) -> Result<(), IoError> { + fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError> { do uv_fs_helper(self.uv_loop(), path) |rmdir_req, l, p, cb| { do rmdir_req.rmdir(l, p) |req, err| { cb(req, err) }; } } - fn fs_readdir(&mut self, path: &P, flags: c_int) -> + fn fs_readdir(&mut self, path: &CString, flags: c_int) -> Result<~[Path], IoError> { use str::StrSlice; let result_cell = Cell::new_empty(); @@ -716,17 +723,17 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - let path_str = path.path_as_str(|p| p.to_owned()); - do stat_req.readdir(self.uv_loop(), path, flags) - |req,err| { + // Don't pick up the null byte + let slice = path.as_bytes().slice(0, path.len()); + let path_parent = Cell::new(Path::new(slice)); + do stat_req.readdir(self.uv_loop(), path, flags) |req,err| { + let parent = path_parent.take(); let res = match err { None => { - let rel_paths = req.get_paths(); let mut paths = ~[]; - for r in rel_paths.iter() { - let mut p = Path::new(path_str.as_slice()); - p.push(r.as_slice()); - paths.push(p); + do req.each_path |rel_path| { + let p = rel_path.as_bytes(); + paths.push(parent.join(p.slice_to(rel_path.len()))); } Ok(paths) }, @@ -744,13 +751,8 @@ impl IoFactory for UvIoFactory { return result_cell.take(); } - fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError> { - let home = get_handle_to_current_scheduler!(); - Ok(~UvUnboundPipe { pipe: Pipe::new(self.uv_loop(), ipc), home: home }) - } - fn spawn(&mut self, config: ProcessConfig) - -> Result<(~RtioProcessObject, ~[Option]), IoError> + -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError> { // Sadly, we must create the UvProcess before we actually call uv_spawn // so that the exit_cb can close over it and notify it when the process @@ -792,7 +794,8 @@ impl IoFactory for UvIoFactory { Ok(io) => { // Only now do we actually get a handle to this scheduler. ret.home = Some(get_handle_to_current_scheduler!()); - Ok((ret, io)) + Ok((ret as ~RtioProcess, + io.move_iter().map(|p| p.map(|p| p as ~RtioPipe)).collect())) } Err(uverr) => { // We still need to close the process handle we created, but @@ -801,6 +804,76 @@ impl IoFactory for UvIoFactory { } } } + + fn unix_bind(&mut self, path: &CString) -> + Result<~RtioUnixListener, IoError> { + let mut pipe = UvUnboundPipe::new(self.uv_loop()); + match pipe.pipe.bind(path) { + Ok(()) => Ok(~UvUnixListener::new(pipe) as ~RtioUnixListener), + Err(e) => Err(uv_error_to_io_error(e)), + } + } + + fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError> { + let pipe = UvUnboundPipe::new(self.uv_loop()); + let mut rawpipe = pipe.pipe; + + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + let pipe_cell = Cell::new(pipe); + let pipe_cell_ptr: *Cell = &pipe_cell; + + let scheduler: ~Scheduler = Local::take(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do rawpipe.connect(path) |_stream, err| { + let res = match err { + None => { + let pipe = unsafe { (*pipe_cell_ptr).take() }; + Ok(~UvPipeStream::new(pipe) as ~RtioPipe) + } + Some(e) => Err(uv_error_to_io_error(e)), + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + + assert!(!result_cell.is_empty()); + return result_cell.take(); + } + + fn tty_open(&mut self, fd: c_int, readable: bool) + -> Result<~RtioTTY, IoError> { + match tty::TTY::new(self.uv_loop(), fd, readable) { + Ok(tty) => Ok(~UvTTY { + home: get_handle_to_current_scheduler!(), + tty: tty, + fd: fd, + } as ~RtioTTY), + Err(e) => Err(uv_error_to_io_error(e)) + } + } + + fn pipe_open(&mut self, fd: c_int) -> Result<~RtioPipe, IoError> { + let mut pipe = UvUnboundPipe::new(self.uv_loop()); + match pipe.pipe.open(fd) { + Ok(()) => Ok(~UvPipeStream::new(pipe) as ~RtioPipe), + Err(e) => Err(uv_error_to_io_error(e)) + } + } + + fn signal(&mut self, signum: Signum, channel: SharedChan) + -> Result<~RtioSignal, IoError> { + let watcher = SignalWatcher::new(self.uv_loop()); + let home = get_handle_to_current_scheduler!(); + let mut signal = ~UvSignal::new(watcher, home); + match signal.watcher.start(signum, |_, _| channel.send_deferred(signum)) { + Ok(()) => Ok(signal as ~RtioSignal), + Err(e) => Err(uv_error_to_io_error(e)), + } + } } pub struct UvTcpListener { @@ -841,11 +914,12 @@ impl RtioSocket for UvTcpListener { } impl RtioTcpListener for UvTcpListener { - fn listen(self) -> Result<~RtioTcpAcceptorObject, IoError> { + fn listen(~self) -> Result<~RtioTcpAcceptor, IoError> { do self.home_for_io_consume |self_| { - let mut acceptor = ~UvTcpAcceptor::new(self_); + let acceptor = ~UvTcpAcceptor::new(self_); let incoming = Cell::new(acceptor.incoming.clone()); - do acceptor.listener.watcher.listen |mut server, status| { + let mut stream = acceptor.listener.watcher.as_stream(); + let res = do stream.listen |mut server, status| { do incoming.with_mut_ref |incoming| { let inc = match status { Some(_) => Err(standard_error(OtherIoError)), @@ -854,20 +928,24 @@ impl RtioTcpListener for UvTcpListener { // first accept call in the callback guarenteed to succeed server.accept(inc.as_stream()); let home = get_handle_to_current_scheduler!(); - Ok(~UvTcpStream { watcher: inc, home: home }) + Ok(~UvTcpStream { watcher: inc, home: home } + as ~RtioTcpStream) } }; incoming.send(inc); } }; - Ok(acceptor) + match res { + Ok(()) => Ok(acceptor as ~RtioTcpAcceptor), + Err(e) => Err(uv_error_to_io_error(e)), + } } } } pub struct UvTcpAcceptor { priv listener: UvTcpListener, - priv incoming: Tube>, + priv incoming: Tube>, } impl HomingIO for UvTcpAcceptor { @@ -888,8 +966,19 @@ impl RtioSocket for UvTcpAcceptor { } } +fn accept_simultaneously(stream: StreamWatcher, a: int) -> Result<(), IoError> { + let r = unsafe { + uvll::tcp_simultaneous_accepts(stream.native_handle(), a as c_int) + }; + + match status_to_maybe_uv_error(r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } +} + impl RtioTcpAcceptor for UvTcpAcceptor { - fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> { + fn accept(&mut self) -> Result<~RtioTcpStream, IoError> { do self.home_for_io |self_| { self_.incoming.recv() } @@ -897,27 +986,13 @@ impl RtioTcpAcceptor for UvTcpAcceptor { fn accept_simultaneously(&mut self) -> Result<(), IoError> { do self.home_for_io |self_| { - let r = unsafe { - uvll::tcp_simultaneous_accepts(self_.listener.watcher.native_handle(), 1 as c_int) - }; - - match status_to_maybe_uv_error(r) { - Some(err) => Err(uv_error_to_io_error(err)), - None => Ok(()) - } + accept_simultaneously(self_.listener.watcher.as_stream(), 1) } } fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> { do self.home_for_io |self_| { - let r = unsafe { - uvll::tcp_simultaneous_accepts(self_.listener.watcher.native_handle(), 0 as c_int) - }; - - match status_to_maybe_uv_error(r) { - Some(err) => Err(uv_error_to_io_error(err)), - None => Ok(()) - } + accept_simultaneously(self_.listener.watcher.as_stream(), 0) } } } @@ -994,6 +1069,17 @@ pub struct UvUnboundPipe { priv home: SchedHandle, } +impl UvUnboundPipe { + /// Creates a new unbound pipe homed to the current scheduler, placed on the + /// specified event loop + pub fn new(loop_: &Loop) -> UvUnboundPipe { + UvUnboundPipe { + pipe: Pipe::new(loop_, false), + home: get_handle_to_current_scheduler!(), + } + } +} + impl HomingIO for UvUnboundPipe { fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home } } @@ -1013,18 +1099,12 @@ impl Drop for UvUnboundPipe { } } -impl UvUnboundPipe { - pub unsafe fn bind(~self) -> UvPipeStream { - UvPipeStream { inner: self } - } -} - pub struct UvPipeStream { - priv inner: ~UvUnboundPipe, + priv inner: UvUnboundPipe, } impl UvPipeStream { - pub fn new(inner: ~UvUnboundPipe) -> UvPipeStream { + pub fn new(inner: UvUnboundPipe) -> UvPipeStream { UvPipeStream { inner: inner } } } @@ -1402,8 +1482,8 @@ impl RtioTimer for UvTimer { pub struct UvFileStream { priv loop_: Loop, priv fd: c_int, - priv close_on_drop: bool, - priv home: SchedHandle + priv close: CloseBehavior, + priv home: SchedHandle, } impl HomingIO for UvFileStream { @@ -1411,13 +1491,13 @@ impl HomingIO for UvFileStream { } impl UvFileStream { - fn new(loop_: Loop, fd: c_int, close_on_drop: bool, + fn new(loop_: Loop, fd: c_int, close: CloseBehavior, home: SchedHandle) -> UvFileStream { UvFileStream { loop_: loop_, fd: fd, - close_on_drop: close_on_drop, - home: home + close: close, + home: home, } } fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result { @@ -1437,9 +1517,9 @@ impl UvFileStream { unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; - }; + } + } + } result_cell.take() } fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { @@ -1459,9 +1539,9 @@ impl UvFileStream { unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; - }; + } + } + } result_cell.take() } fn seek_common(&mut self, pos: i64, whence: c_int) -> @@ -1484,16 +1564,23 @@ impl UvFileStream { impl Drop for UvFileStream { fn drop(&mut self) { - if self.close_on_drop { - do self.home_for_io_with_sched |self_, scheduler| { - do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell::new(task); - let close_req = file::FsRequest::new(); - do close_req.close(&self_.loop_, self_.fd) |_,_| { - let scheduler: ~Scheduler = Local::take(); - scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; + match self.close { + DontClose => {} + CloseAsynchronously => { + let close_req = file::FsRequest::new(); + do close_req.close(&self.loop_, self.fd) |_,_| {} + } + CloseSynchronously => { + do self.home_for_io_with_sched |self_, scheduler| { + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let close_req = file::FsRequest::new(); + do close_req.close(&self_.loop_, self_.fd) |_,_| { + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + } } } } @@ -1612,13 +1699,185 @@ impl RtioProcess for UvProcess { } } +pub struct UvUnixListener { + priv inner: UvUnboundPipe +} + +impl HomingIO for UvUnixListener { + fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.inner.home() } +} + +impl UvUnixListener { + fn new(pipe: UvUnboundPipe) -> UvUnixListener { + UvUnixListener { inner: pipe } + } +} + +impl RtioUnixListener for UvUnixListener { + fn listen(~self) -> Result<~RtioUnixAcceptor, IoError> { + do self.home_for_io_consume |self_| { + let acceptor = ~UvUnixAcceptor::new(self_); + let incoming = Cell::new(acceptor.incoming.clone()); + let mut stream = acceptor.listener.inner.pipe.as_stream(); + let res = do stream.listen |mut server, status| { + do incoming.with_mut_ref |incoming| { + let inc = match status { + Some(e) => Err(uv_error_to_io_error(e)), + None => { + let pipe = UvUnboundPipe::new(&server.event_loop()); + server.accept(pipe.pipe.as_stream()); + Ok(~UvPipeStream::new(pipe) as ~RtioPipe) + } + }; + incoming.send(inc); + } + }; + match res { + Ok(()) => Ok(acceptor as ~RtioUnixAcceptor), + Err(e) => Err(uv_error_to_io_error(e)), + } + } + } +} + +pub struct UvTTY { + tty: tty::TTY, + home: SchedHandle, + fd: c_int, +} + +impl HomingIO for UvTTY { + fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home } +} + +impl Drop for UvTTY { + fn drop(&mut self) { + // TTY handles are used for the logger in a task, so this destructor is + // run when a task is destroyed. When a task is being destroyed, a local + // scheduler isn't available, so we can't do the normal "take the + // scheduler and resume once close is done". Instead close operations on + // a TTY are asynchronous. + self.tty.close_async(); + } +} + +impl RtioTTY for UvTTY { + fn read(&mut self, buf: &mut [u8]) -> Result { + do self.home_for_io_with_sched |self_, scheduler| { + read_stream(self_.tty.as_stream(), scheduler, buf) + } + } + + fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + do self.home_for_io_with_sched |self_, scheduler| { + write_stream(self_.tty.as_stream(), scheduler, buf) + } + } + + fn set_raw(&mut self, raw: bool) -> Result<(), IoError> { + do self.home_for_io |self_| { + match self_.tty.set_mode(raw) { + Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e)) + } + } + } + + fn get_winsize(&mut self) -> Result<(int, int), IoError> { + do self.home_for_io |self_| { + match self_.tty.get_winsize() { + Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e)) + } + } + } + + fn isatty(&self) -> bool { + unsafe { uvll::guess_handle(self.fd) == uvll::UV_TTY } + } +} + +pub struct UvUnixAcceptor { + listener: UvUnixListener, + incoming: Tube>, +} + +impl HomingIO for UvUnixAcceptor { + fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.listener.home() } +} + +impl UvUnixAcceptor { + fn new(listener: UvUnixListener) -> UvUnixAcceptor { + UvUnixAcceptor { listener: listener, incoming: Tube::new() } + } +} + +impl RtioUnixAcceptor for UvUnixAcceptor { + fn accept(&mut self) -> Result<~RtioPipe, IoError> { + do self.home_for_io |self_| { + self_.incoming.recv() + } + } + + fn accept_simultaneously(&mut self) -> Result<(), IoError> { + do self.home_for_io |self_| { + accept_simultaneously(self_.listener.inner.pipe.as_stream(), 1) + } + } + + fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> { + do self.home_for_io |self_| { + accept_simultaneously(self_.listener.inner.pipe.as_stream(), 0) + } + } +} + +pub struct UvSignal { + watcher: signal::SignalWatcher, + home: SchedHandle, +} + +impl HomingIO for UvSignal { + fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home } +} + +impl UvSignal { + fn new(w: signal::SignalWatcher, home: SchedHandle) -> UvSignal { + UvSignal { watcher: w, home: home } + } +} + +impl RtioSignal for UvSignal {} + +impl Drop for UvSignal { + fn drop(&mut self) { + do self.home_for_io_with_sched |self_, scheduler| { + rtdebug!("closing UvSignal"); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do self_.watcher.close { + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + } + } +} + +// this function is full of lies +unsafe fn local_io() -> &'static mut IoFactory { + do Local::borrow |sched: &mut Scheduler| { + let mut io = None; + sched.event_loop.io(|i| io = Some(i)); + cast::transmute(io.unwrap()) + } +} + #[test] fn test_simple_io_no_connect() { do run_in_mt_newsched_task { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); + let io = local_io(); let addr = next_test_ip4(); - let maybe_chan = (*io).tcp_connect(addr); + let maybe_chan = io.tcp_connect(addr); assert!(maybe_chan.is_err()); } } @@ -1628,9 +1887,9 @@ fn test_simple_io_no_connect() { fn test_simple_udp_io_bind_only() { do run_in_mt_newsched_task { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); + let io = local_io(); let addr = next_test_ip4(); - let maybe_socket = (*io).udp_bind(addr); + let maybe_socket = io.udp_bind(addr); assert!(maybe_socket.is_ok()); } } @@ -1649,9 +1908,11 @@ fn test_simple_homed_udp_io_bind_then_move_task_then_home_and_close() { let work_queue2 = WorkQueue::new(); let queues = ~[work_queue1.clone(), work_queue2.clone()]; - let mut sched1 = ~Scheduler::new(~UvEventLoop::new(), work_queue1, queues.clone(), + let loop1 = ~UvEventLoop::new() as ~EventLoop; + let mut sched1 = ~Scheduler::new(loop1, work_queue1, queues.clone(), sleepers.clone()); - let mut sched2 = ~Scheduler::new(~UvEventLoop::new(), work_queue2, queues.clone(), + let loop2 = ~UvEventLoop::new() as ~EventLoop; + let mut sched2 = ~Scheduler::new(loop2, work_queue2, queues.clone(), sleepers.clone()); let handle1 = Cell::new(sched1.make_handle()); @@ -1665,11 +1926,9 @@ fn test_simple_homed_udp_io_bind_then_move_task_then_home_and_close() { }; let test_function: ~fn() = || { - let io: *mut IoFactoryObject = unsafe { - Local::unsafe_borrow() - }; + let io = unsafe { local_io() }; let addr = next_test_ip4(); - let maybe_socket = unsafe { (*io).udp_bind(addr) }; + let maybe_socket = io.udp_bind(addr); // this socket is bound to this event loop assert!(maybe_socket.is_ok()); @@ -1728,9 +1987,11 @@ fn test_simple_homed_udp_io_bind_then_move_handle_then_home_and_close() { let work_queue2 = WorkQueue::new(); let queues = ~[work_queue1.clone(), work_queue2.clone()]; - let mut sched1 = ~Scheduler::new(~UvEventLoop::new(), work_queue1, queues.clone(), + let loop1 = ~UvEventLoop::new() as ~EventLoop; + let mut sched1 = ~Scheduler::new(loop1, work_queue1, queues.clone(), sleepers.clone()); - let mut sched2 = ~Scheduler::new(~UvEventLoop::new(), work_queue2, queues.clone(), + let loop2 = ~UvEventLoop::new() as ~EventLoop; + let mut sched2 = ~Scheduler::new(loop2, work_queue2, queues.clone(), sleepers.clone()); let handle1 = Cell::new(sched1.make_handle()); @@ -1741,11 +2002,9 @@ fn test_simple_homed_udp_io_bind_then_move_handle_then_home_and_close() { let chan = Cell::new(chan); let body1: ~fn() = || { - let io: *mut IoFactoryObject = unsafe { - Local::unsafe_borrow() - }; + let io = unsafe { local_io() }; let addr = next_test_ip4(); - let socket = unsafe { (*io).udp_bind(addr) }; + let socket = io.udp_bind(addr); assert!(socket.is_ok()); chan.take().send(socket); }; @@ -1799,8 +2058,8 @@ fn test_simple_tcp_server_and_client() { // Start the server first so it's listening when we connect do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let listener = (*io).tcp_bind(addr).unwrap(); + let io = local_io(); + let listener = io.tcp_bind(addr).unwrap(); let mut acceptor = listener.listen().unwrap(); chan.take().send(()); let mut stream = acceptor.accept().unwrap(); @@ -1817,8 +2076,8 @@ fn test_simple_tcp_server_and_client() { do spawntask { unsafe { port.take().recv(); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut stream = (*io).tcp_connect(addr).unwrap(); + let io = local_io(); + let mut stream = io.tcp_connect(addr).unwrap(); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); } } @@ -1842,9 +2101,11 @@ fn test_simple_tcp_server_and_client_on_diff_threads() { let client_work_queue = WorkQueue::new(); let queues = ~[server_work_queue.clone(), client_work_queue.clone()]; - let mut server_sched = ~Scheduler::new(~UvEventLoop::new(), server_work_queue, + let sloop = ~UvEventLoop::new() as ~EventLoop; + let mut server_sched = ~Scheduler::new(sloop, server_work_queue, queues.clone(), sleepers.clone()); - let mut client_sched = ~Scheduler::new(~UvEventLoop::new(), client_work_queue, + let cloop = ~UvEventLoop::new() as ~EventLoop; + let mut client_sched = ~Scheduler::new(cloop, client_work_queue, queues.clone(), sleepers.clone()); let server_handle = Cell::new(server_sched.make_handle()); @@ -1861,8 +2122,8 @@ fn test_simple_tcp_server_and_client_on_diff_threads() { }; let server_fn: ~fn() = || { - let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() }; - let listener = unsafe { (*io).tcp_bind(server_addr).unwrap() }; + let io = unsafe { local_io() }; + let listener = io.tcp_bind(server_addr).unwrap(); let mut acceptor = listener.listen().unwrap(); let mut stream = acceptor.accept().unwrap(); let mut buf = [0, .. 2048]; @@ -1874,12 +2135,10 @@ fn test_simple_tcp_server_and_client_on_diff_threads() { }; let client_fn: ~fn() = || { - let io: *mut IoFactoryObject = unsafe { - Local::unsafe_borrow() - }; - let mut stream = unsafe { (*io).tcp_connect(client_addr) }; + let io = unsafe { local_io() }; + let mut stream = io.tcp_connect(client_addr); while stream.is_err() { - stream = unsafe { (*io).tcp_connect(client_addr) }; + stream = io.tcp_connect(client_addr); } stream.unwrap().write([0, 1, 2, 3, 4, 5, 6, 7]); }; @@ -1918,8 +2177,8 @@ fn test_simple_udp_server_and_client() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut server_socket = (*io).udp_bind(server_addr).unwrap(); + let io = local_io(); + let mut server_socket = io.udp_bind(server_addr).unwrap(); chan.take().send(()); let mut buf = [0, .. 2048]; let (nread,src) = server_socket.recvfrom(buf).unwrap(); @@ -1934,8 +2193,8 @@ fn test_simple_udp_server_and_client() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut client_socket = (*io).udp_bind(client_addr).unwrap(); + let io = local_io(); + let mut client_socket = io.udp_bind(client_addr).unwrap(); port.take().recv(); client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr); } @@ -1952,8 +2211,8 @@ fn test_read_and_block() { let chan = Cell::new(chan); do spawntask { - let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() }; - let listener = unsafe { (*io).tcp_bind(addr).unwrap() }; + let io = unsafe { local_io() }; + let listener = io.tcp_bind(addr).unwrap(); let mut acceptor = listener.listen().unwrap(); chan.take().send(()); let mut stream = acceptor.accept().unwrap(); @@ -1991,8 +2250,8 @@ fn test_read_and_block() { do spawntask { unsafe { port.take().recv(); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut stream = (*io).tcp_connect(addr).unwrap(); + let io = local_io(); + let mut stream = io.tcp_connect(addr).unwrap(); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); @@ -2014,8 +2273,8 @@ fn test_read_read_read() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let listener = (*io).tcp_bind(addr).unwrap(); + let io = local_io(); + let listener = io.tcp_bind(addr).unwrap(); let mut acceptor = listener.listen().unwrap(); chan.take().send(()); let mut stream = acceptor.accept().unwrap(); @@ -2031,8 +2290,8 @@ fn test_read_read_read() { do spawntask { unsafe { port.take().recv(); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut stream = (*io).tcp_connect(addr).unwrap(); + let io = local_io(); + let mut stream = io.tcp_connect(addr).unwrap(); let mut buf = [0, .. 2048]; let mut total_bytes_read = 0; while total_bytes_read < MAX { @@ -2060,8 +2319,8 @@ fn test_udp_twice() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut client = (*io).udp_bind(client_addr).unwrap(); + let io = local_io(); + let mut client = io.udp_bind(client_addr).unwrap(); port.take().recv(); assert!(client.sendto([1], server_addr).is_ok()); assert!(client.sendto([2], server_addr).is_ok()); @@ -2070,8 +2329,8 @@ fn test_udp_twice() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut server = (*io).udp_bind(server_addr).unwrap(); + let io = local_io(); + let mut server = io.udp_bind(server_addr).unwrap(); chan.take().send(()); let mut buf1 = [0]; let mut buf2 = [0]; @@ -2105,9 +2364,9 @@ fn test_udp_many_read() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut server_out = (*io).udp_bind(server_out_addr).unwrap(); - let mut server_in = (*io).udp_bind(server_in_addr).unwrap(); + let io = local_io(); + let mut server_out = io.udp_bind(server_out_addr).unwrap(); + let mut server_in = io.udp_bind(server_in_addr).unwrap(); let (port, chan) = first.take(); chan.send(()); port.recv(); @@ -2131,9 +2390,9 @@ fn test_udp_many_read() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut client_out = (*io).udp_bind(client_out_addr).unwrap(); - let mut client_in = (*io).udp_bind(client_in_addr).unwrap(); + let io = local_io(); + let mut client_out = io.udp_bind(client_out_addr).unwrap(); + let mut client_in = io.udp_bind(client_in_addr).unwrap(); let (port, chan) = second.take(); port.recv(); chan.send(()); @@ -2163,8 +2422,8 @@ fn test_udp_many_read() { fn test_timer_sleep_simple() { do run_in_mt_newsched_task { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let timer = (*io).timer_init(); + let io = local_io(); + let timer = io.timer_init(); do timer.map_move |mut t| { t.sleep(1) }; } } @@ -2174,29 +2433,28 @@ fn file_test_uvio_full_simple_impl() { use str::StrSlice; // why does this have to be explicitly imported to work? // compiler was complaining about no trait for str that // does .as_bytes() .. - use path::Path; use rt::io::{Open, Create, ReadWrite, Read}; unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); + let io = local_io(); let write_val = "hello uvio!"; let path = "./tmp/file_test_uvio_full.txt"; { let create_fm = Create; let create_fa = ReadWrite; - let mut fd = (*io).fs_open(&Path::new(path), create_fm, create_fa).unwrap(); + let mut fd = io.fs_open(&path.to_c_str(), create_fm, create_fa).unwrap(); let write_buf = write_val.as_bytes(); fd.write(write_buf); } { let ro_fm = Open; let ro_fa = Read; - let mut fd = (*io).fs_open(&Path::new(path), ro_fm, ro_fa).unwrap(); + let mut fd = io.fs_open(&path.to_c_str(), ro_fm, ro_fa).unwrap(); let mut read_vec = [0, .. 1028]; let nread = fd.read(read_vec).unwrap(); let read_val = str::from_utf8(read_vec.slice(0, nread as uint)); assert!(read_val == write_val.to_owned()); } - (*io).fs_unlink(&Path::new(path)); + io.fs_unlink(&path.to_c_str()); } } @@ -2211,9 +2469,9 @@ fn uvio_naive_print(input: &str) { use str::StrSlice; unsafe { use libc::{STDOUT_FILENO}; - let io: *mut IoFactoryObject = Local::unsafe_borrow(); + let io = local_io(); { - let mut fd = (*io).fs_from_raw_fd(STDOUT_FILENO, false); + let mut fd = io.fs_from_raw_fd(STDOUT_FILENO, DontClose); let write_buf = input.as_bytes(); fd.write(write_buf); } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 367585b0f0ee4..75e6a0c6ca552 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -131,6 +131,8 @@ pub type uv_udp_send_t = c_void; pub type uv_getaddrinfo_t = c_void; pub type uv_process_t = c_void; pub type uv_pipe_t = c_void; +pub type uv_tty_t = c_void; +pub type uv_signal_t = c_void; pub struct uv_timespec_t { tv_sec: libc::c_long, @@ -218,6 +220,8 @@ pub type uv_getaddrinfo_cb = extern "C" fn(req: *uv_getaddrinfo_t, pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t, exit_status: c_int, term_signal: c_int); +pub type uv_signal_cb = extern "C" fn(handle: *uv_signal_t, + signum: c_int); pub type sockaddr = c_void; pub type sockaddr_in = c_void; @@ -231,37 +235,37 @@ pub type socklen_t = c_int; #[cfg(target_os = "android")] #[cfg(target_os = "linux")] pub struct addrinfo { - priv ai_flags: c_int, - priv ai_family: c_int, - priv ai_socktype: c_int, - priv ai_protocol: c_int, - priv ai_addrlen: socklen_t, + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: socklen_t, ai_addr: *sockaddr, - priv ai_canonname: *char, + ai_canonname: *char, ai_next: *addrinfo } #[cfg(target_os = "macos")] #[cfg(target_os = "freebsd")] pub struct addrinfo { - priv ai_flags: c_int, - priv ai_family: c_int, - priv ai_socktype: c_int, - priv ai_protocol: c_int, - priv ai_addrlen: socklen_t, - priv ai_canonname: *char, + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: socklen_t, + ai_canonname: *char, ai_addr: *sockaddr, ai_next: *addrinfo } #[cfg(windows)] pub struct addrinfo { - priv ai_flags: c_int, - priv ai_family: c_int, - priv ai_socktype: c_int, - priv ai_protocol: c_int, - priv ai_addrlen: size_t, - priv ai_canonname: *char, + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: *char, ai_addr: *sockaddr, ai_next: *addrinfo } @@ -419,18 +423,6 @@ pub unsafe fn walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void) { rust_uv_walk(loop_handle, cb, arg); } -pub unsafe fn idle_new() -> *uv_idle_t { - #[fixed_stack_segment]; #[inline(never)]; - - rust_uv_idle_new() -} - -pub unsafe fn idle_delete(handle: *uv_idle_t) { - #[fixed_stack_segment]; #[inline(never)]; - - rust_uv_idle_delete(handle) -} - pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int { #[fixed_stack_segment]; #[inline(never)]; @@ -958,6 +950,52 @@ pub unsafe fn freeaddrinfo(ai: *addrinfo) { #[fixed_stack_segment]; #[inline(never)]; rust_uv_freeaddrinfo(ai); } +pub unsafe fn pipe_open(pipe: *uv_pipe_t, file: c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_pipe_open(pipe, file) +} +pub unsafe fn pipe_bind(pipe: *uv_pipe_t, name: *c_char) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_pipe_bind(pipe, name) +} +pub unsafe fn pipe_connect(req: *uv_connect_t, handle: *uv_pipe_t, + name: *c_char, cb: uv_connect_cb) { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_pipe_connect(req, handle, name, cb) +} +pub unsafe fn tty_init(loop_ptr: *uv_loop_t, tty: *uv_tty_t, fd: c_int, + readable: c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_tty_init(loop_ptr, tty, fd, readable) +} +pub unsafe fn tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_tty_set_mode(tty, mode) +} +pub unsafe fn tty_get_winsize(tty: *uv_tty_t, width: *c_int, + height: *c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_tty_get_winsize(tty, width, height) +} +pub unsafe fn guess_handle(fd: c_int) -> uv_handle_type { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_guess_handle(fd) +} + +pub unsafe fn signal_init(loop_: *uv_loop_t, handle: *uv_signal_t) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + return rust_uv_signal_init(loop_, handle); +} +pub unsafe fn signal_start(handle: *uv_signal_t, + signal_cb: uv_signal_cb, + signum: c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + return rust_uv_signal_start(handle, signal_cb, signum); +} +pub unsafe fn signal_stop(handle: *uv_signal_t) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + return rust_uv_signal_stop(handle); +} pub struct uv_err_data { priv err_name: ~str, @@ -978,8 +1016,6 @@ extern { fn rust_uv_close(handle: *c_void, cb: uv_close_cb); fn rust_uv_walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void); - fn rust_uv_idle_new() -> *uv_idle_t; - fn rust_uv_idle_delete(handle: *uv_idle_t); fn rust_uv_idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int; fn rust_uv_idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int; fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int; @@ -1102,4 +1138,36 @@ extern { fn rust_set_stdio_container_stream(c: *uv_stdio_container_t, stream: *uv_stream_t); fn rust_uv_pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int; + + fn rust_uv_pipe_open(pipe: *uv_pipe_t, file: c_int) -> c_int; + fn rust_uv_pipe_bind(pipe: *uv_pipe_t, name: *c_char) -> c_int; + fn rust_uv_pipe_connect(req: *uv_connect_t, handle: *uv_pipe_t, + name: *c_char, cb: uv_connect_cb); + fn rust_uv_tty_init(loop_ptr: *uv_loop_t, tty: *uv_tty_t, fd: c_int, + readable: c_int) -> c_int; + fn rust_uv_tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int; + fn rust_uv_tty_get_winsize(tty: *uv_tty_t, width: *c_int, + height: *c_int) -> c_int; + fn rust_uv_guess_handle(fd: c_int) -> uv_handle_type; + + // XXX: see comments in addrinfo.rs + // These should all really be constants... + //#[rust_stack] pub fn rust_SOCK_STREAM() -> c_int; + //#[rust_stack] pub fn rust_SOCK_DGRAM() -> c_int; + //#[rust_stack] pub fn rust_SOCK_RAW() -> c_int; + //#[rust_stack] pub fn rust_IPPROTO_UDP() -> c_int; + //#[rust_stack] pub fn rust_IPPROTO_TCP() -> c_int; + //#[rust_stack] pub fn rust_AI_ADDRCONFIG() -> c_int; + //#[rust_stack] pub fn rust_AI_ALL() -> c_int; + //#[rust_stack] pub fn rust_AI_CANONNAME() -> c_int; + //#[rust_stack] pub fn rust_AI_NUMERICHOST() -> c_int; + //#[rust_stack] pub fn rust_AI_NUMERICSERV() -> c_int; + //#[rust_stack] pub fn rust_AI_PASSIVE() -> c_int; + //#[rust_stack] pub fn rust_AI_V4MAPPED() -> c_int; + + fn rust_uv_signal_init(loop_: *uv_loop_t, handle: *uv_signal_t) -> c_int; + fn rust_uv_signal_start(handle: *uv_signal_t, + signal_cb: uv_signal_cb, + signum: c_int) -> c_int; + fn rust_uv_signal_stop(handle: *uv_signal_t) -> c_int; } diff --git a/src/libstd/run.rs b/src/libstd/run.rs index c4cb8be2061f9..615ba60e066c0 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -17,8 +17,9 @@ use comm::{stream, SharedChan}; use libc::{pid_t, c_int}; use libc; use prelude::*; -use rt::io::native::process; +use rt::io::process; use rt::io; +use rt::io::extensions::ReaderUtil; use task; /** @@ -121,8 +122,24 @@ impl Process { */ pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> Process { let ProcessOptions { env, dir, in_fd, out_fd, err_fd } = options; - let inner = process::Process::new(prog, args, env, dir, - in_fd, out_fd, err_fd); + let env = env.as_ref().map(|a| a.as_slice()); + let cwd = dir.as_ref().map(|a| a.as_str().unwrap()); + fn rtify(fd: Option, input: bool) -> process::StdioContainer { + match fd { + Some(fd) => process::InheritFd(fd), + None => process::CreatePipe(input, !input), + } + } + let rtio = [rtify(in_fd, true), rtify(out_fd, false), + rtify(err_fd, false)]; + let rtconfig = process::ProcessConfig { + program: prog, + args: args, + env: env, + cwd: cwd, + io: rtio, + }; + let inner = process::Process::new(rtconfig).unwrap(); Process { inner: inner } } @@ -135,7 +152,9 @@ impl Process { * Fails if there is no stdin available (it's already been removed by * take_input) */ - pub fn input<'a>(&'a mut self) -> &'a mut io::Writer { self.inner.input() } + pub fn input<'a>(&'a mut self) -> &'a mut io::Writer { + self.inner.io[0].get_mut_ref() as &mut io::Writer + } /** * Returns an io::Reader that can be used to read from this Process's stdout. @@ -143,7 +162,9 @@ impl Process { * Fails if there is no stdout available (it's already been removed by * take_output) */ - pub fn output<'a>(&'a mut self) -> &'a mut io::Reader { self.inner.output() } + pub fn output<'a>(&'a mut self) -> &'a mut io::Reader { + self.inner.io[1].get_mut_ref() as &mut io::Reader + } /** * Returns an io::Reader that can be used to read from this Process's stderr. @@ -151,18 +172,20 @@ impl Process { * Fails if there is no stderr available (it's already been removed by * take_error) */ - pub fn error<'a>(&'a mut self) -> &'a mut io::Reader { self.inner.error() } + pub fn error<'a>(&'a mut self) -> &'a mut io::Reader { + self.inner.io[2].get_mut_ref() as &mut io::Reader + } /** * Closes the handle to the child process's stdin. */ pub fn close_input(&mut self) { - self.inner.take_input(); + self.inner.io[0].take(); } fn close_outputs(&mut self) { - self.inner.take_output(); - self.inner.take_error(); + self.inner.io[1].take(); + self.inner.io[2].take(); } /** @@ -185,21 +208,9 @@ impl Process { * were redirected to existing file descriptors. */ pub fn finish_with_output(&mut self) -> ProcessOutput { - self.inner.take_input(); // close stdin - let output = Cell::new(self.inner.take_output()); - let error = Cell::new(self.inner.take_error()); - - fn read_everything(r: &mut io::Reader) -> ~[u8] { - let mut ret = ~[]; - let mut buf = [0, ..1024]; - loop { - match r.read(buf) { - Some(n) => { ret.push_all(buf.slice_to(n)); } - None => break - } - } - return ret; - } + self.close_input(); + let output = Cell::new(self.inner.io[1].take()); + let error = Cell::new(self.inner.io[2].take()); // Spawn two entire schedulers to read both stdout and sterr // in parallel so we don't deadlock while blocking on one @@ -208,16 +219,27 @@ impl Process { let (p, ch) = stream(); let ch = SharedChan::new(ch); let ch_clone = ch.clone(); - do task::spawn_sched(task::SingleThreaded) { - match error.take() { - Some(ref mut e) => ch.send((2, read_everything(*e))), - None => ch.send((2, ~[])) + + // FIXME(#910, #8674): right now I/O is incredibly brittle when it comes + // to linked failure, so these tasks must be spawn so they're not + // affected by linked failure. If these are removed, then the + // runtime may never exit because linked failure will cause some + // SchedHandle structures to not get destroyed, meaning that + // there's always an async watcher available. + do task::spawn_unlinked { + do io::ignore_io_error { + match error.take() { + Some(ref mut e) => ch.send((2, e.read_to_end())), + None => ch.send((2, ~[])) + } } } - do task::spawn_sched(task::SingleThreaded) { - match output.take() { - Some(ref mut e) => ch_clone.send((1, read_everything(*e))), - None => ch_clone.send((1, ~[])) + do task::spawn_unlinked { + do io::ignore_io_error { + match output.take() { + Some(ref mut e) => ch_clone.send((1, e.read_to_end())), + None => ch_clone.send((1, ~[])) + } } } @@ -311,6 +333,7 @@ mod tests { use path::Path; use run; use str; + use task::spawn; use unstable::running_on_valgrind; use rt::io::native::file; use rt::io::{Writer, Reader}; @@ -383,6 +406,7 @@ mod tests { } #[test] + #[ignore] // FIXME(#10016) cat never sees stdin close fn test_pipes() { let pipe_in = os::pipe(); @@ -401,13 +425,14 @@ mod tests { os::close(pipe_out.out); os::close(pipe_err.out); - let expected = ~"test"; - writeclose(pipe_in.out, expected); + do spawn { + writeclose(pipe_in.out, ~"test"); + } let actual = readclose(pipe_out.input); readclose(pipe_err.input); proc.finish(); - assert_eq!(expected, actual); + assert_eq!(~"test", actual); } fn writeclose(fd: c_int, s: &str) { diff --git a/src/libstd/std.rs b/src/libstd/std.rs index 8c72e083f882f..12316cb5ead2a 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -148,7 +148,6 @@ pub mod iter; pub mod to_str; pub mod to_bytes; pub mod clone; -pub mod io; pub mod hash; pub mod container; pub mod default; diff --git a/src/libstd/str.rs b/src/libstd/str.rs index f134788942cdb..053076c5d89ec 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -1018,7 +1018,6 @@ static TAG_CONT_U8: u8 = 128u8; /// Unsafe operations pub mod raw { - use option::{Option, Some}; use cast; use libc; use ptr; @@ -1172,34 +1171,6 @@ pub mod raw { vec::raw::set_len(as_owned_vec(s), new_len) } - /// Parses a C "multistring", eg windows env values or - /// the req->ptr result in a uv_fs_readdir() call. - /// Optionally, a `count` can be passed in, limiting the - /// parsing to only being done `count`-times. - #[inline] - pub unsafe fn from_c_multistring(buf: *libc::c_char, count: Option) -> ~[~str] { - #[fixed_stack_segment]; #[inline(never)]; - - let mut curr_ptr: uint = buf as uint; - let mut result = ~[]; - let mut ctr = 0; - let (limited_count, limit) = match count { - Some(limit) => (true, limit), - None => (false, 0) - }; - while(((limited_count && ctr < limit) || !limited_count) - && *(curr_ptr as *libc::c_char) != 0 as libc::c_char) { - let env_pair = from_c_str( - curr_ptr as *libc::c_char); - result.push(env_pair); - curr_ptr += - libc::strlen(curr_ptr as *libc::c_char) as uint - + 1; - ctr += 1; - } - result - } - /// Sets the length of a string /// /// This will explicitly set the size of the string, without actually @@ -1214,26 +1185,6 @@ pub mod raw { assert_eq!(c, ~"AAA"); } } - - #[test] - fn test_str_multistring_parsing() { - use option::None; - unsafe { - let input = bytes!("zero", "\x00", "one", "\x00", "\x00"); - let ptr = vec::raw::to_ptr(input); - let result = from_c_multistring(ptr as *libc::c_char, None); - assert!(result.len() == 2); - let mut ctr = 0; - for x in result.iter() { - match ctr { - 0 => assert_eq!(x, &~"zero"), - 1 => assert_eq!(x, &~"one"), - _ => fail!("shouldn't happen!") - } - ctr += 1; - } - } - } } /* diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index dec13eded3983..fbe2988f77c71 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -89,7 +89,7 @@ use unstable::sync::Exclusive; use rt::in_green_task_context; use rt::local::Local; use rt::task::{Task, Sched}; -use rt::shouldnt_be_public::{Scheduler, KillHandle, WorkQueue, Thread}; +use rt::shouldnt_be_public::{Scheduler, KillHandle, WorkQueue, Thread, EventLoop}; use rt::uv::uvio::UvEventLoop; #[cfg(test)] use task::default_task_opts; @@ -607,7 +607,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) { let work_queue = WorkQueue::new(); // Create a new scheduler to hold the new task - let new_loop = ~UvEventLoop::new(); + let new_loop = ~UvEventLoop::new() as ~EventLoop; let mut new_sched = ~Scheduler::new_special(new_loop, work_queue, (*sched).work_queues.clone(), diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index 4d5da19dafda9..8c78e34528bde 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -16,8 +16,6 @@ The `ToBytes` and `IterBytes` traits use cast; use container::Container; -use io; -use io::Writer; use iter::Iterator; use option::{None, Option, Some}; use str::{Str, StrSlice}; @@ -360,7 +358,10 @@ pub trait ToBytes { impl ToBytes for A { fn to_bytes(&self, lsb0: bool) -> ~[u8] { - do io::with_bytes_writer |wr| { + use rt::io::mem; + use rt::io::Writer; + + do mem::with_mem_writer |wr| { do self.iter_bytes(lsb0) |bytes| { wr.write(bytes); true diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 1d9d5512ff424..456d344b838c5 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -962,7 +962,6 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo mod test { use ast::*; use super::*; - use std::io; use opt_vec; use std::hashmap::HashMap; @@ -1137,7 +1136,7 @@ mod test { // - two renames of the same var.. can only happen if you use // local-expand to prevent the inner binding from being renamed // during the rename-pass caused by the first: - io::println("about to run bad test"); + println("about to run bad test"); { let sc = unfold_test_sc(~[R(id(a,EMPTY_CTXT),50), R(id(a,EMPTY_CTXT),51)], EMPTY_CTXT,&mut t); diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index bbbaf2a2f6042..736f92910af20 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -11,7 +11,7 @@ use codemap::{Pos, Span}; use codemap; -use std::io; +use std::rt::io; use std::local_data; use extra::term; @@ -199,9 +199,14 @@ fn diagnosticcolor(lvl: level) -> term::color::Color { fn print_maybe_styled(msg: &str, color: term::attr::Attr) { local_data_key!(tls_terminal: @Option) - let stderr = io::stderr(); + let stderr = @mut io::stderr() as @mut io::Writer; + fn is_stderr_screen() -> bool { + #[fixed_stack_segment]; + use std::libc; + unsafe { libc::isatty(libc::STDERR_FILENO) != 0 } + } - if stderr.get_type() == io::Screen { + if is_stderr_screen() { let t = match local_data::get(tls_terminal, |v| v.map(|k| *k)) { None => { let t = term::Terminal::new(stderr); @@ -218,21 +223,21 @@ fn print_maybe_styled(msg: &str, color: term::attr::Attr) { match t { &Some(ref term) => { term.attr(color); - stderr.write_str(msg); + write!(stderr, "{}", msg); term.reset(); }, - _ => stderr.write_str(msg) + _ => write!(stderr, "{}", msg) } } else { - stderr.write_str(msg); + write!(stderr, "{}", msg); } } fn print_diagnostic(topic: &str, lvl: level, msg: &str) { - let stderr = io::stderr(); + let mut stderr = io::stderr(); if !topic.is_empty() { - stderr.write_str(format!("{} ", topic)); + write!(&mut stderr as &mut io::Writer, "{} ", topic); } print_maybe_styled(format!("{}: ", diagnosticstr(lvl)), @@ -266,6 +271,8 @@ fn highlight_lines(cm: @codemap::CodeMap, lvl: level, lines: @codemap::FileLines) { let fm = lines.file; + let mut err = io::stderr(); + let err = &mut err as &mut io::Writer; // arbitrarily only print up to six lines of the error let max_lines = 6u; @@ -277,21 +284,12 @@ fn highlight_lines(cm: @codemap::CodeMap, } // Print the offending lines for line in display_lines.iter() { - io::stderr().write_str(format!("{}:{} ", fm.name, *line + 1u)); - let s = fm.get_line(*line as int) + "\n"; - io::stderr().write_str(s); + write!(err, "{}:{} {}\n", fm.name, *line + 1, fm.get_line(*line as int)); } if elided { let last_line = display_lines[display_lines.len() - 1u]; let s = format!("{}:{} ", fm.name, last_line + 1u); - let mut indent = s.len(); - let mut out = ~""; - while indent > 0u { - out.push_char(' '); - indent -= 1u; - } - out.push_str("...\n"); - io::stderr().write_str(out); + write!(err, "{0:1$}...\n", "", s.len()); } // FIXME (#3260) @@ -325,7 +323,7 @@ fn highlight_lines(cm: @codemap::CodeMap, _ => s.push_char(' '), }; } - io::stderr().write_str(s); + write!(err, "{}", s); let mut s = ~"^"; let hi = cm.lookup_char_pos(sp.hi); if hi.col != lo.col { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1018e79aabc6e..99bcb36eedbf5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1524,7 +1524,8 @@ mod test { } fn fake_print_crate(crate: &ast::Crate) { - let s = pprust::rust_printer(std::io::stderr(),get_ident_interner()); + let out = @mut std::rt::io::stderr() as @mut std::rt::io::Writer; + let s = pprust::rust_printer(out, get_ident_interner()); pprust::print_crate_(s, crate); } @@ -1536,7 +1537,7 @@ mod test { //fn expand_and_resolve(crate_str: @str) -> ast::crate { //let expanded_ast = expand_crate_str(crate_str); - // std::io::println(format!("expanded: {:?}\n",expanded_ast)); + // println(format!("expanded: {:?}\n",expanded_ast)); //mtwt_resolve_crate(expanded_ast) //} //fn expand_and_resolve_and_pretty_print (crate_str : @str) -> ~str { @@ -1645,9 +1646,9 @@ mod test { let varref_marks = mtwt_marksof(varref.segments[0].identifier.ctxt, invalid_name); if (!(varref_name==binding_name)){ - std::io::println("uh oh, should match but doesn't:"); - std::io::println(format!("varref: {:?}",varref)); - std::io::println(format!("binding: {:?}", bindings[binding_idx])); + println("uh oh, should match but doesn't:"); + println!("varref: {:?}",varref); + println!("binding: {:?}", bindings[binding_idx]); ast_util::display_sctable(get_sctable()); } assert_eq!(varref_name,binding_name); @@ -1665,12 +1666,12 @@ mod test { println!("text of test case: \"{}\"", teststr); println!(""); println!("uh oh, matches but shouldn't:"); - std::io::println(format!("varref: {:?}",varref)); + println!("varref: {:?}",varref); // good lord, you can't make a path with 0 segments, can you? println!("varref's first segment's uint: {}, and string: \"{}\"", varref.segments[0].identifier.name, ident_to_str(&varref.segments[0].identifier)); - std::io::println(format!("binding: {:?}", bindings[binding_idx])); + println!("binding: {:?}", bindings[binding_idx]); ast_util::display_sctable(get_sctable()); } assert!(!fail); @@ -1703,17 +1704,17 @@ foo_module!() && (@"xx" == (ident_to_str(&p.segments[0].identifier))) }).enumerate() { if (mtwt_resolve(v.segments[0].identifier) != resolved_binding) { - std::io::println("uh oh, xx binding didn't match xx varref:"); - std::io::println(format!("this is xx varref \\# {:?}",idx)); - std::io::println(format!("binding: {:?}",cxbind)); - std::io::println(format!("resolves to: {:?}",resolved_binding)); - std::io::println(format!("varref: {:?}",v.segments[0].identifier)); - std::io::println(format!("resolves to: {:?}", - mtwt_resolve(v.segments[0].identifier))); + println("uh oh, xx binding didn't match xx varref:"); + println!("this is xx varref \\# {:?}",idx); + println!("binding: {:?}",cxbind); + println!("resolves to: {:?}",resolved_binding); + println!("varref: {:?}",v.segments[0].identifier); + println!("resolves to: {:?}", + mtwt_resolve(v.segments[0].identifier)); let table = get_sctable(); - std::io::println("SC table:"); + println("SC table:"); for (idx,val) in table.table.iter().enumerate() { - std::io::println(format!("{:4u} : {:?}",idx,val)); + println!("{:4u} : {:?}",idx,val); } } assert_eq!(mtwt_resolve(v.segments[0].identifier),resolved_binding); diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index 52807009073b1..3e07b16221ec1 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -15,15 +15,13 @@ use ext::base; use print; use parse::token::{get_ident_interner}; -use std::io; - pub fn expand_syntax_ext(cx: @ExtCtxt, sp: codemap::Span, tt: &[ast::token_tree]) -> base::MacResult { cx.print_backtrace(); - io::stdout().write_line( + println( print::pprust::tt_to_str( &ast::tt_delim(@mut tt.to_owned()), get_ident_interner())); diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index dcfeb99365a7b..119a74cccd6d5 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -19,8 +19,10 @@ use parse; use parse::token::{get_ident_interner}; use print::pprust; -use std::io; -use std::result; +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::file::FileInfo; +use std::str; // These macros all relate to the file system; they either return // the column/row/filename of the expression, or they include @@ -89,14 +91,23 @@ pub fn expand_include(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) pub fn expand_include_str(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> base::MacResult { let file = get_single_str_from_tts(cx, sp, tts, "include_str!"); - let res = io::read_whole_file_str(&res_rel_file(cx, sp, &Path::new(file))); - match res { - result::Ok(res) => { - base::MRExpr(cx.expr_str(sp, res.to_managed())) - } - result::Err(e) => { - cx.span_fatal(sp, e); - } + let file = res_rel_file(cx, sp, &Path::new(file)); + let mut error = None; + let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { + file.open_reader(io::Open).read_to_end() + }; + match error { + Some(e) => { + cx.span_fatal(sp, format!("couldn't read {}: {}", + file.display(), e.desc)); + } + None => {} + } + match str::from_utf8_owned_opt(bytes) { + Some(s) => base::MRExpr(cx.expr_str(sp, s.to_managed())), + None => { + cx.span_fatal(sp, format!("{} wasn't a utf-8 file", file.display())); + } } } @@ -106,13 +117,20 @@ pub fn expand_include_bin(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) use std::at_vec; let file = get_single_str_from_tts(cx, sp, tts, "include_bin!"); - match io::read_whole_file(&res_rel_file(cx, sp, &Path::new(file))) { - result::Ok(src) => { - let v = at_vec::to_managed_move(src); - base::MRExpr(cx.expr_lit(sp, ast::lit_binary(v))) + let file = res_rel_file(cx, sp, &Path::new(file)); + + let mut error = None; + let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { + file.open_reader(io::Open).read_to_end() + }; + match error { + Some(e) => { + cx.span_fatal(sp, format!("couldn't read {}: {}", + file.display(), e.desc)); } - result::Err(ref e) => { - cx.parse_sess().span_diagnostic.handler().fatal((*e)) + None => { + let bytes = at_vec::to_managed_move(bytes); + base::MRExpr(cx.expr_lit(sp, ast::lit_binary(bytes))) } } } diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs index 38921648a2bc6..e9e6eb872c86f 100644 --- a/src/libsyntax/parse/comments.rs +++ b/src/libsyntax/parse/comments.rs @@ -18,7 +18,8 @@ use parse::lexer; use parse::token; use parse::token::{get_ident_interner}; -use std::io; +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; use std::str; use std::uint; @@ -346,9 +347,9 @@ pub struct lit { pub fn gather_comments_and_literals(span_diagnostic: @mut diagnostic::span_handler, path: @str, - srdr: @io::Reader) + mut srdr: &mut io::Reader) -> (~[cmnt], ~[lit]) { - let src = str::from_utf8(srdr.read_whole_stream()).to_managed(); + let src = str::from_utf8(srdr.read_to_end()).to_managed(); let cm = CodeMap::new(); let filemap = cm.new_filemap(path, src); let rdr = lexer::new_low_level_string_reader(span_diagnostic, filemap); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c9405d72464bb..fad9eab754200 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -19,8 +19,11 @@ use parse::attr::parser_attr; use parse::lexer::reader; use parse::parser::Parser; -use std::io; use std::path::Path; +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::file::FileInfo; +use std::str; pub mod lexer; pub mod parser; @@ -260,16 +263,32 @@ pub fn new_parser_from_tts(sess: @mut ParseSess, /// add the path to the session's codemap and return the new filemap. pub fn file_to_filemap(sess: @mut ParseSess, path: &Path, spanopt: Option) -> @FileMap { - match io::read_whole_file_str(path) { - // FIXME (#9639): This needs to handle non-utf8 paths - Ok(src) => string_to_filemap(sess, src.to_managed(), path.as_str().unwrap().to_managed()), - Err(e) => { - match spanopt { - Some(span) => sess.span_diagnostic.span_fatal(span, e), - None => sess.span_diagnostic.handler().fatal(e) - } + let err = |msg: &str| { + match spanopt { + Some(sp) => sess.span_diagnostic.span_fatal(sp, msg), + None => sess.span_diagnostic.handler().fatal(msg), + } + }; + let mut error = None; + let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { + path.open_reader(io::Open).read_to_end() + }; + match error { + Some(e) => { + err(format!("couldn't read {}: {}", path.display(), e.desc)); + } + None => {} + } + match str::from_utf8_owned_opt(bytes) { + Some(s) => { + return string_to_filemap(sess, s.to_managed(), + path.as_str().unwrap().to_managed()); + } + None => { + err(format!("{} is not UTF-8 encoded", path.display())) } } + unreachable!() } // given a session and a string, add the string to @@ -318,7 +337,10 @@ mod test { use super::*; use extra::serialize::Encodable; use extra; - use std::io; + use std::rt::io; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; + use std::str; use codemap::{Span, BytePos, Spanned}; use opt_vec; use ast; @@ -330,10 +352,10 @@ mod test { use util::parser_testing::string_to_stmt; #[cfg(test)] fn to_json_str>(val: @E) -> ~str { - do io::with_str_writer |writer| { - let mut encoder = extra::json::Encoder(writer); - val.encode(&mut encoder); - } + let writer = @mut MemWriter::new(); + let mut encoder = extra::json::Encoder(writer as @mut io::Writer); + val.encode(&mut encoder); + str::from_utf8(*writer.inner_ref()) } // produce a codemap::span diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 871584003b51e..4801fa21fc493 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -61,7 +61,7 @@ * avoid combining it with other lines and making matters even worse. */ -use std::io; +use std::rt::io; use std::vec; #[deriving(Clone, Eq)] @@ -148,7 +148,7 @@ pub struct print_stack_elt { pub static size_infinity: int = 0xffff; -pub fn mk_printer(out: @io::Writer, linewidth: uint) -> @mut Printer { +pub fn mk_printer(out: @mut io::Writer, linewidth: uint) -> @mut Printer { // Yes 3, it makes the ring buffers big enough to never // fall behind. let n: uint = 3 * linewidth; @@ -157,7 +157,7 @@ pub fn mk_printer(out: @io::Writer, linewidth: uint) -> @mut Printer { let size: ~[int] = vec::from_elem(n, 0); let scan_stack: ~[uint] = vec::from_elem(n, 0u); @mut Printer { - out: @out, + out: out, buf_len: n, margin: linewidth as int, space: linewidth as int, @@ -255,7 +255,7 @@ pub fn mk_printer(out: @io::Writer, linewidth: uint) -> @mut Printer { * called 'print'. */ pub struct Printer { - out: @@io::Writer, + out: @mut io::Writer, buf_len: uint, margin: int, // width of lines we're constrained to space: int, // number of spaces left on line @@ -452,7 +452,7 @@ impl Printer { } pub fn print_newline(&mut self, amount: int) { debug!("NEWLINE {}", amount); - (*self.out).write_str("\n"); + write!(self.out, "\n"); self.pending_indentation = 0; self.indent(amount); } @@ -474,10 +474,10 @@ impl Printer { } pub fn print_str(&mut self, s: &str) { while self.pending_indentation > 0 { - (*self.out).write_str(" "); + write!(self.out, " "); self.pending_indentation -= 1; } - (*self.out).write_str(s); + write!(self.out, "{}", s); } pub fn print(&mut self, x: token, L: int) { debug!("print {} {} (remaining line space={})", tok_str(x), L, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0e330da31e623..400ff80448523 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -28,7 +28,10 @@ use print::pp; use print::pprust; use std::char; -use std::io; +use std::str; +use std::rt::io; +use std::rt::io::Decorator; +use std::rt::io::mem::MemWriter; // The @ps is stored here to prevent recursive type. pub enum ann_node<'self> { @@ -83,11 +86,11 @@ pub fn end(s: @ps) { pp::end(s.s); } -pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps { +pub fn rust_printer(writer: @mut io::Writer, intr: @ident_interner) -> @ps { return rust_printer_annotated(writer, intr, @no_ann::new() as @pp_ann); } -pub fn rust_printer_annotated(writer: @io::Writer, +pub fn rust_printer_annotated(writer: @mut io::Writer, intr: @ident_interner, ann: @pp_ann) -> @ps { @@ -118,8 +121,8 @@ pub fn print_crate(cm: @CodeMap, span_diagnostic: @mut diagnostic::span_handler, crate: &ast::Crate, filename: @str, - input: @io::Reader, - out: @io::Writer, + input: @mut io::Reader, + out: @mut io::Writer, ann: @pp_ann, is_expanded: bool) { let (cmnts, lits) = comments::gather_comments_and_literals( @@ -200,26 +203,26 @@ pub fn path_to_str(p: &ast::Path, intr: @ident_interner) -> ~str { pub fn fun_to_str(decl: &ast::fn_decl, purity: ast::purity, name: ast::Ident, opt_explicit_self: Option, generics: &ast::Generics, intr: @ident_interner) -> ~str { - do io::with_str_writer |wr| { - let s = rust_printer(wr, intr); - print_fn(s, decl, Some(purity), AbiSet::Rust(), - name, generics, opt_explicit_self, ast::inherited); - end(s); // Close the head box - end(s); // Close the outer box - eof(s.s); - } + let wr = @mut MemWriter::new(); + let s = rust_printer(wr as @mut io::Writer, intr); + print_fn(s, decl, Some(purity), AbiSet::Rust(), + name, generics, opt_explicit_self, ast::inherited); + end(s); // Close the head box + end(s); // Close the outer box + eof(s.s); + str::from_utf8(*wr.inner_ref()) } pub fn block_to_str(blk: &ast::Block, intr: @ident_interner) -> ~str { - do io::with_str_writer |wr| { - let s = rust_printer(wr, intr); - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-ibox, will be closed by print-block after { - ibox(s, 0u); - print_block(s, blk); - eof(s.s); - } + let wr = @mut MemWriter::new(); + let s = rust_printer(wr as @mut io::Writer, intr); + // containing cbox, will be closed by print-block at } + cbox(s, indent_unit); + // head-ibox, will be closed by print-block after { + ibox(s, 0u); + print_block(s, blk); + eof(s.s); + str::from_utf8(*wr.inner_ref()) } pub fn meta_item_to_str(mi: &ast::MetaItem, intr: @ident_interner) -> ~str { @@ -2196,11 +2199,11 @@ pub fn print_string(s: @ps, st: &str, style: ast::StrStyle) { } pub fn to_str(t: &T, f: &fn(@ps, &T), intr: @ident_interner) -> ~str { - do io::with_str_writer |wr| { - let s = rust_printer(wr, intr); - f(s, t); - eof(s.s); - } + let wr = @mut MemWriter::new(); + let s = rust_printer(wr as @mut io::Writer, intr); + f(s, t); + eof(s.s); + str::from_utf8(*wr.inner_ref()) } pub fn next_comment(s: @ps) -> Option { diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 3e9b8ba136eaa..0cbbb58d02c66 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -466,16 +466,6 @@ rust_uv_addrinfo_as_sockaddr_in6(addrinfo* input) { return (sockaddr_in6*)input->ai_addr; } -extern "C" uv_idle_t* -rust_uv_idle_new() { - return new uv_idle_t; -} - -extern "C" void -rust_uv_idle_delete(uv_idle_t* handle) { - delete handle; -} - extern "C" int rust_uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) { return uv_idle_init(loop, idle); @@ -637,3 +627,54 @@ extern "C" int rust_uv_pipe_init(uv_loop_t *loop, uv_pipe_t* p, int ipc) { return uv_pipe_init(loop, p, ipc); } + +extern "C" int +rust_uv_pipe_open(uv_pipe_t *pipe, int file) { + return uv_pipe_open(pipe, file); +} + +extern "C" int +rust_uv_pipe_bind(uv_pipe_t *pipe, char *name) { + return uv_pipe_bind(pipe, name); +} + +extern "C" void +rust_uv_pipe_connect(uv_connect_t *req, uv_pipe_t *handle, + char *name, uv_connect_cb cb) { + uv_pipe_connect(req, handle, name, cb); +} + +extern "C" int +rust_uv_tty_init(uv_loop_t *loop, uv_tty_t *tty, int fd, int readable) { + return uv_tty_init(loop, tty, fd, readable); +} + +extern "C" int +rust_uv_tty_set_mode(uv_tty_t *tty, int mode) { + return uv_tty_set_mode(tty, mode); +} + +extern "C" int +rust_uv_tty_get_winsize(uv_tty_t *tty, int *width, int *height) { + return uv_tty_get_winsize(tty, width, height); +} + +extern "C" uv_handle_type +rust_uv_guess_handle(int fd) { + return uv_guess_handle(fd); +} + +extern "C" int +rust_uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + return uv_signal_init(loop, handle); +} + +extern "C" int +rust_uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + return uv_signal_start(handle, signal_cb, signum); +} + +extern "C" int +rust_uv_signal_stop(uv_signal_t* handle) { + return uv_signal_stop(handle); +} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 7323397508e2e..269da8e7882ac 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -98,8 +98,6 @@ rust_uv_get_base_from_buf rust_uv_get_len_from_buf rust_uv_getaddrinfo rust_uv_freeaddrinfo -rust_uv_idle_new -rust_uv_idle_delete rust_uv_idle_init rust_uv_idle_start rust_uv_idle_stop @@ -191,6 +189,9 @@ rust_set_stdio_container_fd rust_set_stdio_container_stream rust_uv_process_pid rust_uv_pipe_init +rust_uv_signal_init +rust_uv_signal_start +rust_uv_signal_stop sdhtml_renderer sd_markdown_new sd_markdown_render @@ -199,3 +200,10 @@ bufrelease bufnew rust_take_dlerror_lock rust_drop_dlerror_lock +rust_uv_pipe_open +rust_uv_pipe_bind +rust_uv_pipe_connect +rust_uv_tty_init +rust_uv_tty_set_mode +rust_uv_tty_get_winsize +rust_uv_guess_handle diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 2d209e40e4249..f91327b6a6521 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -13,7 +13,6 @@ extern mod extra; use extra::time; use extra::treemap::TreeMap; use std::hashmap::{HashMap, HashSet}; -use std::io; use std::os; use std::rand::{Rng, IsaacRng, SeedableRng}; use std::trie::TrieMap; @@ -28,7 +27,7 @@ fn timed(label: &str, f: &fn()) { } fn ascending>(map: &mut M, n_keys: uint) { - io::println(" Ascending integers:"); + println(" Ascending integers:"); do timed("insert") { for i in range(0u, n_keys) { @@ -50,7 +49,7 @@ fn ascending>(map: &mut M, n_keys: uint) { } fn descending>(map: &mut M, n_keys: uint) { - io::println(" Descending integers:"); + println(" Descending integers:"); do timed("insert") { for i in range(0, n_keys).invert() { @@ -118,7 +117,7 @@ fn main() { println!("{} keys", n_keys); - io::println("\nTreeMap:"); + println("\nTreeMap:"); { let mut map: TreeMap = TreeMap::new(); @@ -131,12 +130,12 @@ fn main() { } { - io::println(" Random integers:"); + println(" Random integers:"); let mut map: TreeMap = TreeMap::new(); vector(&mut map, n_keys, rand); } - io::println("\nHashMap:"); + println("\nHashMap:"); { let mut map: HashMap = HashMap::new(); @@ -149,12 +148,12 @@ fn main() { } { - io::println(" Random integers:"); + println(" Random integers:"); let mut map: HashMap = HashMap::new(); vector(&mut map, n_keys, rand); } - io::println("\nTrieMap:"); + println("\nTrieMap:"); { let mut map: TrieMap = TrieMap::new(); @@ -167,7 +166,7 @@ fn main() { } { - io::println(" Random integers:"); + println(" Random integers:"); let mut map: TrieMap = TrieMap::new(); vector(&mut map, n_keys, rand); } diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index b9a8e74668fa9..9f65dc1e5555b 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -13,7 +13,6 @@ extern mod extra; use extra::bitv::BitvSet; use extra::treemap::TreeSet; use std::hashmap::HashSet; -use std::io; use std::os; use std::rand; use std::uint; @@ -123,12 +122,11 @@ impl Results { } fn write_header(header: &str) { - io::stdout().write_str(header); - io::stdout().write_str("\n"); + println(header); } fn write_row(label: &str, value: f64) { - io::stdout().write_str(format!("{:30s} {} s\n", label, value)); + println!("{:30s} {} s\n", label, value); } fn write_results(label: &str, results: &Results) { diff --git a/src/test/bench/msgsend-pipes-shared.rs b/src/test/bench/msgsend-pipes-shared.rs index 97479fc133a67..2a5971be216b8 100644 --- a/src/test/bench/msgsend-pipes-shared.rs +++ b/src/test/bench/msgsend-pipes-shared.rs @@ -22,7 +22,6 @@ extern mod extra; use std::comm::{Port, Chan, SharedChan}; use std::comm; -use std::io; use std::os; use std::task; use std::uint; @@ -90,10 +89,10 @@ fn run(args: &[~str]) { let result = from_child.recv(); let end = extra::time::precise_time_s(); let elapsed = end - start; - io::stdout().write_str(format!("Count is {:?}\n", result)); - io::stdout().write_str(format!("Test took {:?} seconds\n", elapsed)); + print!("Count is {:?}\n", result); + print!("Test took {:?} seconds\n", elapsed); let thruput = ((size / workers * workers) as f64) / (elapsed as f64); - io::stdout().write_str(format!("Throughput={} per sec\n", thruput)); + print!("Throughput={} per sec\n", thruput); assert_eq!(result, num_bytes * size); } diff --git a/src/test/bench/msgsend-pipes.rs b/src/test/bench/msgsend-pipes.rs index 584a8b8befcc6..1ff531324b358 100644 --- a/src/test/bench/msgsend-pipes.rs +++ b/src/test/bench/msgsend-pipes.rs @@ -17,7 +17,6 @@ extern mod extra; use std::comm::{SharedChan, Chan, stream}; -use std::io; use std::os; use std::task; use std::uint; @@ -84,10 +83,10 @@ fn run(args: &[~str]) { let result = from_child.recv(); let end = extra::time::precise_time_s(); let elapsed = end - start; - io::stdout().write_str(format!("Count is {:?}\n", result)); - io::stdout().write_str(format!("Test took {:?} seconds\n", elapsed)); + print!("Count is {:?}\n", result); + print!("Test took {:?} seconds\n", elapsed); let thruput = ((size / workers * workers) as f64) / (elapsed as f64); - io::stdout().write_str(format!("Throughput={} per sec\n", thruput)); + print!("Throughput={} per sec\n", thruput); assert_eq!(result, num_bytes * size); } diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 96e87788b70d8..6bfb731badd5b 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -14,7 +14,6 @@ extern mod extra; use std::cell::Cell; use std::comm::{stream, SharedChan}; -use std::io; use std::option; use std::os; use std::task; @@ -191,15 +190,15 @@ fn rendezvous(nn: uint, set: ~[color]) { } // print each color in the set - io::println(show_color_list(set)); + println(show_color_list(set)); // print each creature's stats for rep in report.iter() { - io::println(*rep); + println(*rep); } // print the total number of creatures met - io::println(show_number(creatures_met)); + println(show_number(creatures_met)); } fn main() { @@ -215,10 +214,10 @@ fn main() { let nn = from_str::(args[1]).unwrap(); print_complements(); - io::println(""); + println(""); rendezvous(nn, ~[Blue, Red, Yellow]); - io::println(""); + println(""); rendezvous(nn, ~[Blue, Red, Yellow, Red, Yellow, Blue, Red, Yellow, Red, Blue]); diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index ef1061c780efd..52f068b8b1cdd 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -18,7 +18,7 @@ extern mod extra; use std::int; -use std::io; +use std::rt::io; use std::os; use std::rand::Rng; use std::rand; @@ -68,12 +68,12 @@ fn select_random(r: u32, genelist: ~[AminoAcids]) -> char { bisect(genelist.clone(), 0, genelist.len() - 1, r) } -fn make_random_fasta(wr: @io::Writer, +fn make_random_fasta(wr: @mut io::Writer, id: ~str, desc: ~str, genelist: ~[AminoAcids], n: int) { - wr.write_line(~">" + id + " " + desc); + writeln!(wr, ">{} {}", id, desc); let mut rng = rand::rng(); let rng = @mut MyRandom { last: rng.gen() @@ -83,26 +83,26 @@ fn make_random_fasta(wr: @io::Writer, op.push_char(select_random(myrandom_next(rng, 100u32), genelist.clone())); if op.len() >= LINE_LENGTH { - wr.write_line(op); + writeln!(wr, "{}", op); op = ~""; } } - if op.len() > 0u { wr.write_line(op); } + if op.len() > 0u { writeln!(wr, "{}", op); } } -fn make_repeat_fasta(wr: @io::Writer, id: ~str, desc: ~str, s: ~str, n: int) { - wr.write_line(~">" + id + " " + desc); +fn make_repeat_fasta(wr: @mut io::Writer, id: ~str, desc: ~str, s: ~str, n: int) { + writeln!(wr, ">{} {}", id, desc); let mut op = str::with_capacity( LINE_LENGTH ); let sl = s.len(); for i in range(0u, n as uint) { if (op.len() >= LINE_LENGTH) { - wr.write_line( op ); + writeln!(wr, "{}", op); op = str::with_capacity( LINE_LENGTH ); } op.push_char( s[i % sl] as char ); } if op.len() > 0 { - wr.write_line(op) + writeln!(wr, "{}", op); } } @@ -111,6 +111,7 @@ fn acid(ch: char, prob: u32) -> AminoAcids { } fn main() { + use std::rt::io::file::FileInfo; let args = os::args(); let args = if os::getenv("RUST_BENCH").is_some() { // alioth tests k-nucleotide with this data at 25,000,000 @@ -122,10 +123,10 @@ fn main() { }; let writer = if os::getenv("RUST_BENCH").is_some() { - io::file_writer(&Path::new("./shootout-fasta.data"), - [io::Truncate, io::Create]).unwrap() + let file = Path::new("./shootout-fasta.data").open_writer(io::CreateOrTruncate); + @mut file as @mut io::Writer } else { - io::stdout() + @mut io::stdout() as @mut io::Writer }; let n = from_str::(args[1]).unwrap(); diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 59dd0846b59aa..cfc78e1615ec0 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -18,10 +18,9 @@ use std::cmp::Ord; use std::comm::{stream, Port, Chan}; use std::comm; use std::hashmap::HashMap; -use std::io::ReaderUtil; -use std::io; use std::option; use std::os; +use std::rt::io; use std::str; use std::task; use std::util; @@ -195,48 +194,48 @@ fn main() { let mut proc_mode = false; loop { - let line = match rdr.read_line() { - Some(ln) => ln, None => break, - }; - let line = line.trim().to_owned(); - - if line.len() == 0u { continue; } - - match (line[0] as char, proc_mode) { - - // start processing if this is the one - ('>', false) => { - match line.slice_from(1).find_str("THREE") { - option::Some(_) => { proc_mode = true; } - option::None => { } - } - } - - // break our processing - ('>', true) => { break; } - - // process the sequence for k-mers - (_, true) => { - let line_bytes = line.as_bytes(); - - for (ii, _sz) in sizes.iter().enumerate() { - let lb = line_bytes.to_owned(); - to_child[ii].send(lb); - } - } - - // whatever - _ => { } - } + let line = match io::ignore_io_error(|| rdr.read_line()) { + Some(ln) => ln, None => break, + }; + let line = line.trim().to_owned(); + + if line.len() == 0u { continue; } + + match (line[0] as char, proc_mode) { + + // start processing if this is the one + ('>', false) => { + match line.slice_from(1).find_str("THREE") { + option::Some(_) => { proc_mode = true; } + option::None => { } + } + } + + // break our processing + ('>', true) => { break; } + + // process the sequence for k-mers + (_, true) => { + let line_bytes = line.as_bytes(); + + for (ii, _sz) in sizes.iter().enumerate() { + let lb = line_bytes.to_owned(); + to_child[ii].send(lb); + } + } + + // whatever + _ => { } + } } // finish... - for (ii, _sz) in sizes.iter().enumerate() { - to_child[ii].send(~[]); + for (ii, _sz) in sizes.iter().enumerate() { + to_child[ii].send(~[]); } // now fetch and print result messages - for (ii, _sz) in sizes.iter().enumerate() { - io::println(from_child[ii].recv()); + for (ii, _sz) in sizes.iter().enumerate() { + println(from_child[ii].recv()); } } diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 88b3cfdff4298..b3c3fa4db6fb6 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -23,8 +23,6 @@ extern mod extra; use extra::{time, getopts}; use std::comm::{stream, SharedChan}; -use std::io::WriterUtil; -use std::io; use std::os; use std::result::{Ok, Err}; use std::task; @@ -113,8 +111,6 @@ fn main() { let num_trials = 10; - let out = io::stdout(); - for n in range(1, max + 1) { for _ in range(0, num_trials) { let start = time::precise_time_ns(); @@ -123,8 +119,7 @@ fn main() { let elapsed = stop - start; - out.write_line(format!("{}\t{}\t{}", n, fibn, - elapsed.to_str())); + println!("{}\t{}\t{}", n, fibn, elapsed.to_str()); } } } diff --git a/src/test/bench/std-smallintmap.rs b/src/test/bench/std-smallintmap.rs index be2bd051cad86..e1b1f59298ed4 100644 --- a/src/test/bench/std-smallintmap.rs +++ b/src/test/bench/std-smallintmap.rs @@ -13,8 +13,6 @@ extern mod extra; use extra::smallintmap::SmallIntMap; -use std::io::WriterUtil; -use std::io; use std::os; use std::uint; @@ -59,8 +57,8 @@ fn main() { let maxf = max as f64; - io::stdout().write_str(format!("insert(): {:?} seconds\n", checkf)); - io::stdout().write_str(format!(" : {} op/sec\n", maxf/checkf)); - io::stdout().write_str(format!("get() : {:?} seconds\n", appendf)); - io::stdout().write_str(format!(" : {} op/sec\n", maxf/appendf)); + println!("insert(): {:?} seconds\n", checkf); + println!(" : {} op/sec\n", maxf/checkf); + println!("get() : {:?} seconds\n", appendf); + println!(" : {} op/sec\n", maxf/appendf); } diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index 189b3ef740e9c..d4f4a46af38b1 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -14,8 +14,9 @@ extern mod extra; -use std::io::{ReaderUtil, WriterUtil}; -use std::io; +use std::rt::io; +use std::rt::io::stdio::StdReader; +use std::rt::io::buffered::BufferedReader; use std::os; use std::uint; use std::unstable::intrinsics::cttz16; @@ -67,12 +68,14 @@ impl Sudoku { return true; } - pub fn read(reader: @io::Reader) -> Sudoku { - assert!(reader.read_line() == ~"9,9"); /* assert first line is exactly "9,9" */ + pub fn read(mut reader: BufferedReader) -> Sudoku { + assert!(reader.read_line().unwrap() == ~"9,9"); /* assert first line is exactly "9,9" */ let mut g = vec::from_fn(10u, { |_i| ~[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] }); - while !reader.eof() { - let line = reader.read_line(); + loop { + let line = match reader.read_line() { + Some(ln) => ln, None => break + }; let comps: ~[&str] = line.trim().split_iter(',').collect(); if comps.len() == 3u { @@ -87,13 +90,13 @@ impl Sudoku { return Sudoku::new(g) } - pub fn write(&self, writer: @io::Writer) { + pub fn write(&self, writer: @mut io::Writer) { for row in range(0u8, 9u8) { - writer.write_str(format!("{}", self.grid[row][0] as uint)); + write!(writer, "{}", self.grid[row][0]); for col in range(1u8, 9u8) { - writer.write_str(format!(" {}", self.grid[row][col] as uint)); + write!(writer, " {}", self.grid[row][col]); } - writer.write_char('\n'); + write!(writer, "\n"); } } @@ -278,8 +281,8 @@ fn main() { let mut sudoku = if use_default { Sudoku::from_vec(&DEFAULT_SUDOKU) } else { - Sudoku::read(io::stdin()) + Sudoku::read(BufferedReader::new(io::stdin())) }; sudoku.solve(); - sudoku.write(io::stdout()); + sudoku.write(@mut io::stdout() as @mut io::Writer); } diff --git a/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs b/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs index 76e700609291e..dcfef4e1d9c85 100644 --- a/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs +++ b/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs @@ -10,8 +10,6 @@ // Tests that auto-ref can't create mutable aliases to immutable memory. -use std::io; - struct Foo { x: int } diff --git a/src/test/compile-fail/issue-5060-fail.rs b/src/test/compile-fail/issue-5060-fail.rs index c50398544440a..ef5ad2766ca69 100644 --- a/src/test/compile-fail/issue-5060-fail.rs +++ b/src/test/compile-fail/issue-5060-fail.rs @@ -10,17 +10,15 @@ #[feature(macro_rules)]; -use std::io; - macro_rules! print_hd_tl ( ($field_hd:ident, $($field_tl:ident),+) => ({ - io::print(stringify!($field)); //~ ERROR unknown macro variable - io::print("::["); + print(stringify!($field)); //~ ERROR unknown macro variable + print("::["); $( - io::print(stringify!($field_tl)); - io::print(", "); + print(stringify!($field_tl)); + print(", "); )+ - io::print("]\n"); + print("]\n"); }) ) diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index a8b9000c6d9c9..621510cea99e4 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; +trait A {} struct Struct { - r: io::Reader //~ ERROR reference to trait `io::Reader` where a type is expected + r: A //~ ERROR reference to trait `A` where a type is expected } -fn new_struct(r: io::Reader) -> Struct { //~ ERROR reference to trait `io::Reader` where a type is expected +fn new_struct(r: A) -> Struct { //~ ERROR reference to trait `A` where a type is expected Struct { r: r } } diff --git a/src/test/compile-fail/issue-7573.rs b/src/test/compile-fail/issue-7573.rs index 2be763ee76850..9dc29e59f904a 100644 --- a/src/test/compile-fail/issue-7573.rs +++ b/src/test/compile-fail/issue-7573.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; - pub struct PkgId { local_path: ~str, junk: ~str @@ -32,7 +30,7 @@ pub fn remove_package_from_database() { list_database(push_id); for l in lines_to_use.iter() { - io::stdout().write_line(l.local_path); + println!("{}", l.local_path); } } diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index 22cf54428a73a..2818214c994b1 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -13,8 +13,6 @@ use cal = bar::c::cc; -use std::io; - use std::either::Right; //~ ERROR unused import use std::util::*; // shouldn't get errors for not using @@ -24,15 +22,23 @@ use std::util::*; // shouldn't get errors for not using use std::option::{Some, None}; //~ ERROR unused import //~^ ERROR unused import -use std::io::ReaderUtil; //~ ERROR unused import +use test::A; //~ ERROR unused import // Be sure that if we just bring some methods into scope that they're also // counted as being used. -use std::io::WriterUtil; +use test::B; // Make sure this import is warned about when at least one of its imported names // is unused use std::vec::{from_fn, from_elem}; //~ ERROR unused import +mod test { + pub trait A { fn a(&self) {} } + pub trait B { fn b(&self) {} } + pub struct C; + impl A for C {} + impl B for C {} +} + mod foo { pub struct Point{x: int, y: int} pub struct Square{p: Point, h: uint, w: uint} @@ -58,6 +64,6 @@ fn main() { cal(foo::Point{x:3, y:9}); let a = 3; ignore(a); - io::stdout().write_str("a"); + test::C.b(); let _a = from_elem(0, 0); } diff --git a/src/test/run-fail/issue-2156.rs b/src/test/run-fail/issue-2156.rs deleted file mode 100644 index 863663334f8ed..0000000000000 --- a/src/test/run-fail/issue-2156.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unnecessary_allocation)]; - -// error-pattern:explicit failure -// Don't double free the string -extern mod extra; - -use std::io::ReaderUtil; -use std::io; - -fn main() { - do io::with_str_reader(~"") |rdr| { - match rdr.read_char() { '=' => { } _ => { fail!() } } - } -} diff --git a/src/test/run-pass/auto-ref-bounded-ty-param.rs b/src/test/run-pass/auto-ref-bounded-ty-param.rs index bb01c27fa0d5c..5211e76d3d7d2 100644 --- a/src/test/run-pass/auto-ref-bounded-ty-param.rs +++ b/src/test/run-pass/auto-ref-bounded-ty-param.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; - trait Foo { fn f(&self); } @@ -30,7 +28,7 @@ impl Foo for T { impl Baz for Bar { fn g(&self) { - io::println(self.x.to_str()); + println(self.x.to_str()); } } diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 0e0e52c62737a..4ff184b44831e 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -18,6 +18,7 @@ use std::libc; use std::run; use std::str; +use std::rt::io; #[test] fn test_destroy_once() { @@ -29,7 +30,9 @@ fn test_destroy_once() { fn test_destroy_twice() { let mut p = run::Process::new("echo", [], run::ProcessOptions::new()); p.destroy(); // this shouldnt crash... - p.destroy(); // ...and nor should this (and nor should the destructor) + do io::io_error::cond.trap(|_| {}).inside { + p.destroy(); // ...and nor should this (and nor should the destructor) + } } fn test_destroy_actually_kills(force: bool) { diff --git a/src/test/run-pass/deriving-encodable-decodable.rs b/src/test/run-pass/deriving-encodable-decodable.rs index b1c5f2f0f2d72..8d3ad26764281 100644 --- a/src/test/run-pass/deriving-encodable-decodable.rs +++ b/src/test/run-pass/deriving-encodable-decodable.rs @@ -17,7 +17,8 @@ extern mod extra; -use std::io; +use std::rt::io::mem::MemWriter; +use std::rt::io::Decorator; use std::rand::{random, Rand}; use extra::serialize::{Encodable, Decodable}; use extra::ebml; @@ -55,11 +56,10 @@ struct G { fn roundtrip + Decodable>() { let obj: T = random(); - let bytes = do io::with_bytes_writer |w| { - let mut e = Encoder(w); - obj.encode(&mut e); - }; - let doc = ebml::reader::Doc(@bytes); + let w = @mut MemWriter::new(); + let mut e = Encoder(w); + obj.encode(&mut e); + let doc = ebml::reader::Doc(@w.inner_ref().to_owned()); let mut dec = Decoder(doc); let obj2 = Decodable::decode(&mut dec); assert!(obj == obj2); diff --git a/src/test/run-pass/expr-repeat-vstore.rs b/src/test/run-pass/expr-repeat-vstore.rs index 8a498563359fb..2831740deaf47 100644 --- a/src/test/run-pass/expr-repeat-vstore.rs +++ b/src/test/run-pass/expr-repeat-vstore.rs @@ -1,7 +1,5 @@ #[feature(managed_boxes)]; -use std::io::println; - pub fn main() { let v: ~[int] = ~[ 1, ..5 ]; println(v[0].to_str()); diff --git a/src/test/run-pass/glob-std.rs b/src/test/run-pass/glob-std.rs index acb2dde99adf6..8cd2d9edbd7c0 100644 --- a/src/test/run-pass/glob-std.rs +++ b/src/test/run-pass/glob-std.rs @@ -15,14 +15,16 @@ extern mod extra; use extra::glob::glob; use extra::tempfile::TempDir; use std::unstable::finally::Finally; -use std::{io, os, unstable}; +use std::{os, unstable}; +use std::rt::io; +use std::rt::io::file::FileInfo; pub fn main() { fn mk_file(path: &str, directory: bool) { if directory { os::make_dir(&Path::new(path), 0xFFFF); } else { - io::mk_file_writer(&Path::new(path), [io::Create]); + Path::new(path).open_writer(io::Create); } } diff --git a/src/test/run-pass/issue-2904.rs b/src/test/run-pass/issue-2904.rs index 0ef9e7108ae65..5a3b177aadcd2 100644 --- a/src/test/run-pass/issue-2904.rs +++ b/src/test/run-pass/issue-2904.rs @@ -16,8 +16,7 @@ extern mod extra; -use std::io::ReaderUtil; -use std::io; +use std::rt::io; use std::to_str; enum square { @@ -64,16 +63,15 @@ fn square_from_char(c: char) -> square { } fn read_board_grid(input: rdr) -> ~[~[square]] { - let input = @input as @io::Reader; + let input = @mut input as @mut io::Reader; let mut grid = ~[]; - do input.each_line |line| { - let mut row = ~[]; - for c in line.iter() { - row.push(square_from_char(c)) - } - grid.push(row); - true - }; + let mut line = [0, ..10]; + input.read(line); + let mut row = ~[]; + for c in line.iter() { + row.push(square_from_char(*c as char)) + } + grid.push(row); let width = grid[0].len(); for row in grid.iter() { assert!(row.len() == width) } grid diff --git a/src/test/run-pass/issue-3556.rs b/src/test/run-pass/issue-3556.rs index 2d4e128f62325..e092d45ce68c8 100644 --- a/src/test/run-pass/issue-3556.rs +++ b/src/test/run-pass/issue-3556.rs @@ -12,9 +12,6 @@ extern mod extra; -use std::io::WriterUtil; -use std::io; - enum Token { Text(@~str), ETag(@~[~str], @~str), @@ -28,8 +25,7 @@ fn check_strs(actual: &str, expected: &str) -> bool { if actual != expected { - io::stderr().write_line(format!("Found {}, but expected {}", actual, - expected)); + println!("Found {}, but expected {}", actual, expected); return false; } return true; diff --git a/src/test/run-pass/issue-3559.rs b/src/test/run-pass/issue-3559.rs index 9665da11b9334..ba92434ba69af 100644 --- a/src/test/run-pass/issue-3559.rs +++ b/src/test/run-pass/issue-3559.rs @@ -13,13 +13,11 @@ // rustc --test map_to_str.rs && ./map_to_str extern mod extra; -use std::io::{WriterUtil}; - fn check_strs(actual: &str, expected: &str) -> bool { if actual != expected { - io::stderr().write_line(fmt!("Found %s, but expected %s", actual, expected)); + println!("Found %s, but expected %s", actual, expected); return false; } return true; diff --git a/src/test/run-pass/issue-3563-3.rs b/src/test/run-pass/issue-3563-3.rs index 55273f7029b6f..50d6a3ae6b8db 100644 --- a/src/test/run-pass/issue-3563-3.rs +++ b/src/test/run-pass/issue-3563-3.rs @@ -20,8 +20,6 @@ extern mod extra; // Extern mod controls linkage. Use controls the visibility of names to modules that are // already linked in. Using WriterUtil allows us to use the write_line method. -use std::io::WriterUtil; -use std::io; use std::str; use std::vec; @@ -150,7 +148,7 @@ impl Canvas for AsciiArt { // this little helper. pub fn check_strs(actual: &str, expected: &str) -> bool { if actual != expected { - io::stderr().write_line(format!("Found:\n{}\nbut expected\n{}", actual, expected)); + println!("Found:\n{}\nbut expected\n{}", actual, expected); return false; } return true; diff --git a/src/test/run-pass/issue-4333.rs b/src/test/run-pass/issue-4333.rs index ebf29be6d5e45..86cef39abc81f 100644 --- a/src/test/run-pass/issue-4333.rs +++ b/src/test/run-pass/issue-4333.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; +use std::rt::io; pub fn main() { - let stdout = &io::stdout() as &io::WriterUtil; - stdout.write_line("Hello!"); + let stdout = &mut io::stdout() as &mut io::Writer; + stdout.write(bytes!("Hello!")); } diff --git a/src/test/run-pass/issue-4541.rs b/src/test/run-pass/issue-4541.rs index 7b80974313e37..32e13f5ac7f46 100644 --- a/src/test/run-pass/issue-4541.rs +++ b/src/test/run-pass/issue-4541.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; - fn parse_args() -> ~str { let args = ::std::os::args(); let mut n = 0; @@ -28,5 +26,5 @@ fn parse_args() -> ~str { } pub fn main() { - io::println(parse_args()); + println(parse_args()); } diff --git a/src/test/run-pass/issue-5060.rs b/src/test/run-pass/issue-5060.rs index e7d0cc012402a..7b96d5a48b9fd 100644 --- a/src/test/run-pass/issue-5060.rs +++ b/src/test/run-pass/issue-5060.rs @@ -10,17 +10,15 @@ #[feature(macro_rules)]; -use std::io; - macro_rules! print_hd_tl ( ($field_hd:ident, $($field_tl:ident),+) => ({ - io::print(stringify!($field_hd)); - io::print("::["); + print(stringify!($field_hd)); + print("::["); $( - io::print(stringify!($field_tl)); - io::print(", "); + print(stringify!($field_tl)); + print(", "); )+ - io::print("]\n"); + print("]\n"); }) ) diff --git a/src/test/run-pass/issue-5741.rs b/src/test/run-pass/issue-5741.rs index 46ec68675e7f3..4282e7acf19b1 100644 --- a/src/test/run-pass/issue-5741.rs +++ b/src/test/run-pass/issue-5741.rs @@ -10,9 +10,7 @@ #[allow(unreachable_code)]; -use std::io; - pub fn main() { return; - while io::stdin().read_line() != ~"quit" { }; + while true {}; } diff --git a/src/test/run-pass/issue-8498.rs b/src/test/run-pass/issue-8498.rs index 40f98355f34e1..247b74e464312 100644 --- a/src/test/run-pass/issue-8498.rs +++ b/src/test/run-pass/issue-8498.rs @@ -9,14 +9,13 @@ // except according to those terms. // xfail-test -use std::io; fn main() { // This is ok match &[(~5,~7)] { ps => { let (ref y, _) = ps[0]; - io::println(fmt!("1. y = %d", **y)); + println(fmt!("1. y = %d", **y)); assert!(**y == 5); } } @@ -25,8 +24,8 @@ fn main() { match Some(&[(~5,)]) { Some(ps) => { let (ref y,) = ps[0]; - io::println(fmt!("2. y = %d", **y)); - if **y != 5 { io::println("sadness"); } + println(fmt!("2. y = %d", **y)); + if **y != 5 { println("sadness"); } } None => () } @@ -35,7 +34,7 @@ fn main() { match Some(&[(~5,~7)]) { Some(ps) => { let (ref y, ref z) = ps[0]; - io::println(fmt!("3. y = %d z = %d", **y, **z)); + println(fmt!("3. y = %d z = %d", **y, **z)); assert!(**y == 5); } None => () diff --git a/src/test/run-pass/match-drop-strs-issue-4541.rs b/src/test/run-pass/match-drop-strs-issue-4541.rs index e90d6b2862671..0580bc938d7d4 100644 --- a/src/test/run-pass/match-drop-strs-issue-4541.rs +++ b/src/test/run-pass/match-drop-strs-issue-4541.rs @@ -2,7 +2,6 @@ // copying, and moving to ensure that we don't segfault // or double-free, as we were wont to do in the past. -use std::io; use std::os; fn parse_args() -> ~str { @@ -23,5 +22,5 @@ fn parse_args() -> ~str { } pub fn main() { - io::println(parse_args()); + println(parse_args()); } diff --git a/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs b/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs index 0259c3955d82c..5e03b47d1b1dc 100644 --- a/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs +++ b/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs @@ -12,8 +12,6 @@ extern mod extra; -use std::io; - trait Serializer { } @@ -33,15 +31,13 @@ impl Serializable for F { } } -impl Serializer for @io::Writer { +impl Serializer for int { } pub fn main() { - do io::with_str_writer |wr| { - let foo = F { a: 1 }; - foo.serialize(wr); + let foo = F { a: 1 }; + foo.serialize(1i); - let bar = F { a: F {a: 1 } }; - bar.serialize(wr); - }; + let bar = F { a: F {a: 1 } }; + bar.serialize(2i); } diff --git a/src/test/run-pass/new-import-syntax.rs b/src/test/run-pass/new-import-syntax.rs index c7497bf3de525..ef59606afe347 100644 --- a/src/test/run-pass/new-import-syntax.rs +++ b/src/test/run-pass/new-import-syntax.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io::println; - pub fn main() { println("Hello world!"); } diff --git a/src/test/run-pass/new-style-constants.rs b/src/test/run-pass/new-style-constants.rs index e2402080bc3c8..fa681c81398fe 100644 --- a/src/test/run-pass/new-style-constants.rs +++ b/src/test/run-pass/new-style-constants.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io::println; - static FOO: int = 3; pub fn main() { diff --git a/src/test/run-pass/rtio-processes.rs b/src/test/run-pass/rtio-processes.rs index 70d8b8fe5a4b8..14595f83ce506 100644 --- a/src/test/run-pass/rtio-processes.rs +++ b/src/test/run-pass/rtio-processes.rs @@ -25,7 +25,6 @@ use std::rt::io::process::{Process, ProcessConfig, CreatePipe, Ignored}; use std::rt::io::{Reader, Writer}; -use std::rt::io::pipe::PipeStream; use std::str; #[test] @@ -105,8 +104,7 @@ fn run_output(args: ProcessConfig) -> ~str { #[test] #[cfg(unix, not(target_os="android"))] fn stdout_works() { - let pipe = PipeStream::new().unwrap(); - let io = ~[Ignored, CreatePipe(pipe, false, true)]; + let io = ~[Ignored, CreatePipe(false, true)]; let args = ProcessConfig { program: "/bin/sh", args: [~"-c", ~"echo foobar"], @@ -120,8 +118,7 @@ fn stdout_works() { #[test] #[cfg(unix, not(target_os="android"))] fn set_cwd_works() { - let pipe = PipeStream::new().unwrap(); - let io = ~[Ignored, CreatePipe(pipe, false, true)]; + let io = ~[Ignored, CreatePipe(false, true)]; let cwd = Some("/"); let args = ProcessConfig { program: "/bin/sh", @@ -136,10 +133,8 @@ fn set_cwd_works() { #[test] #[cfg(unix, not(target_os="android"))] fn stdin_works() { - let input = PipeStream::new().unwrap(); - let output = PipeStream::new().unwrap(); - let io = ~[CreatePipe(input, true, false), - CreatePipe(output, false, true)]; + let io = ~[CreatePipe(true, false), + CreatePipe(false, true)]; let args = ProcessConfig { program: "/bin/sh", args: [~"-c", ~"read line; echo $line"], diff --git a/src/test/run-pass/stat.rs b/src/test/run-pass/stat.rs index 7501c46079d98..85cf265c2d0e8 100644 --- a/src/test/run-pass/stat.rs +++ b/src/test/run-pass/stat.rs @@ -13,8 +13,9 @@ extern mod extra; use extra::tempfile; -use std::io::WriterUtil; -use std::io; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::file::FileInfo; use std::os; pub fn main() { @@ -22,11 +23,12 @@ pub fn main() { let path = dir.path().join("file"); { - match io::file_writer(&path, [io::Create, io::Truncate]) { - Err(ref e) => fail!("{}", e.clone()), - Ok(f) => { + match path.open_writer(io::CreateOrTruncate) { + None => unreachable!(), + Some(f) => { + let mut f = f; for _ in range(0u, 1000) { - f.write_u8(0); + f.write([0]); } } } diff --git a/src/test/run-pass/trait-static-method-overwriting.rs b/src/test/run-pass/trait-static-method-overwriting.rs index 5ac26e65d8880..c8f2afe8c6171 100644 --- a/src/test/run-pass/trait-static-method-overwriting.rs +++ b/src/test/run-pass/trait-static-method-overwriting.rs @@ -11,8 +11,6 @@ // except according to those terms. mod base { - use std::io; - pub trait HasNew { fn new() -> Self; } @@ -34,7 +32,7 @@ mod base { impl ::base::HasNew for Bar { fn new() -> Bar { - io::println("Bar"); + println("Bar"); Bar { dummy: () } } }