diff options
| author | bors <bors@rust-lang.org> | 2013-10-24 14:26:15 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-10-24 14:26:15 -0700 |
| commit | 3f5b2219cc893b30863f9136703166f306fcc684 (patch) | |
| tree | d7267619b1909f2deaf319c560a64d667d141d35 | |
| parent | 61f8c059c4c6082683d78b2ee3d963f65fa1eb98 (diff) | |
| parent | 188e471339dfe652b8ff9f3bbe4cc262a040c584 (diff) | |
| download | rust-3f5b2219cc893b30863f9136703166f306fcc684.tar.gz rust-3f5b2219cc893b30863f9136703166f306fcc684.zip | |
auto merge of #9901 : alexcrichton/rust/unix-sockets, r=brson
Large topics: * Implemented `rt::io::net::unix`. We've got an implementation backed by "named pipes" for windows for free from libuv, so I'm not sure if these should be `cfg(unix)` or whether they'd be better placed in `rt::io::pipe` (which is currently kinda useless), or to leave in `unix`. Regardless, we probably shouldn't deny windows of functionality which it certainly has. * Fully implemented `net::addrinfo`, or at least fully implemented in the sense of making the best attempt to wrap libuv's `getaddrinfo` api * Moved standard I/O to a libuv TTY instead of just a plain old file descriptor. I found that this interacted better when closing stdin, and it has the added bonus of getting things like terminal dimentions (someone should make a progress bar now!) * Migrate to `~Trait` instead of a typedef'd object where possible. There are only two more types which are blocked on this, and those are traits which have a method which takes by-value self (there's an open issue on this) * Drop `rt::io::support::PathLike` in favor of just `ToCStr`. We recently had a lot of Path work done, but it still wasn't getting passed down to libuv (there was an intermediate string conversion), and this allows true paths to work all the way down to libuv (and anything else that can become a C string). * Removes `extra::fileinput` and `extra::io_util` Closes #9895 Closes #9975 Closes #8330 Closes #6850 (ported lots of libraries away from std::io) cc #4248 (implemented unix/dns) cc #9128 (made everything truly trait objects)
141 files changed, 3937 insertions, 5451 deletions
diff --git a/doc/tutorial-conditions.md b/doc/tutorial-conditions.md index 726b8bb2b80..056d967ae6c 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 <unnamed> 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 767f712a8d8..4983a5af3e5 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 7451919c5be..f9f110c122b 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 d02b88ae74e..4ae9ad81daf 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 04ef180299d..ae4a25b8008 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 25976410c7c..dc5e11dabdf 100755 --- a/src/etc/combine-tests.py +++ b/src/etc/combine-tests.py @@ -56,15 +56,15 @@ d.write("#[feature(globs, managed_boxes)];\n") 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 34515a2b955..f577ed55f97 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<int>) { 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 79a5b555c29..3ea164fb456 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 49072dab6d0..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -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<Path>, - 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<Path>], - /** - 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<Path>]) -> 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<Path>]) - -> 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<Path>] { - 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<Path>], 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<Path>], - 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::<uint>(nums[0]).unwrap(); - let line_num = from_str::<uint>(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 27a09be3a62..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[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<A>(&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 90260282e4b..0aab7b743ba 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<E: serialize::Encoder> serialize::Encodable<E> 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<T : Iterator<char>> Parser<T> { } } -/// Decodes a json value from an @io::Reader -pub fn from_reader(rdr: @io::Reader) -> Result<Json, Error> { - 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<Json, Error> { + let s = str::from_utf8(rdr.read_to_end()); let mut parser = Parser(~s.iter()); parser.parse() } @@ -1306,7 +1295,9 @@ impl<A:ToJson> ToJson for Option<A> { 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 02c35000ce3..0ab38cdb5df 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<T: Iterator<char>>(rdr: &mut T, + pred: &fn(char) -> bool) -> (~str, Option<char>) { 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<T: Iterator<char>>(rdr: &mut T) -> (uint, Option<char>) { + let (s, ch) = take_nonempty_prefix(rdr, char::is_digit); match from_str::<uint>(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<T: Iterator<char>>(rdr: &mut T) -> (Identifier, Option<char>) { + let (s,ch) = take_nonempty_prefix(rdr, char::is_alphanumeric); if s.iter().all(char::is_digit) { match from_str::<uint>(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<char>, 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<T: Iterator<char>>(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<Version> { 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 40f99716ca7..497145ca7c9 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 878224890e6..22ce833ea24 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<Terminal, ~str> { + pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> { 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<Terminal, ~str> { + pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> { 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 bc24c8a6e30..0020f432114 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 ea7d20e096d..8dff53f14a1 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 f95c7aa22b7..457f7868e23 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<term::Terminal>, 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 f675c6f2392..2950f02ad19 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<Tm, ~str> { } } - 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 e836d3b5270..d268b106e5c 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 345cf64f128..b94b74a696c 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 4d79b2059db..30efecde37f 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:Encodable<json::Encoder>>(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<T:Decodable<json::Decoder>>(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:Encodable<json::Encoder>>(t: &T) -> ~str { @@ -280,8 +284,8 @@ fn digest<T:Encodable<json::Encoder>>(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 2438d22881f..1b9cb10f1dc 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 67a59f24e29..d2b0dad80f6 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<session::Os> { @@ -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 10232730329..aca41f5f4cb 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<ebml::Doc> { 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 bae0dcc2a52..d64820332a5 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<T> { val: T, - pos: uint + pos: u64 } fn add_to_index(ebml_w: &mut writer::Encoder, @@ -1395,10 +1399,9 @@ fn create_index<T:Clone + Hash + IterBytes + 'static>( fn encode_index<T:'static>( ebml_w: &mut writer::Encoder, buckets: ~[@~[entry<T>]], - 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<T:'static>( 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<T:'static>( 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 e682ff299a9..34eb387a3f5 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 33be1be8955..7fb33c88115 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<ty::t, ty_abbrev>), } +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<T>(w: @io::Writer, t: Option<T>, enc_f: &fn(T)) { +fn enc_opt<T>(w: @mut MemWriter, t: Option<T>, 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 3d7f28b8b30..cb8c7b3262f 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 2722fff12a8..55daff90e62 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 22fd1d393e9..7ad55936b9e 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<O:DataFlowOperator+Clone+'static> DataFlowContext<O> { 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 71934c9f2a7..695f4a6fd13 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 df7b09f9db7..8b5167b7e8f 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 ecf45d5c424..ce50397d003 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 4c53fe48fe1..c0fab1ad98f 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<Output, ~str> { - 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 72197219fc5..bee21d70b2d 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 96c99a7a0f1..79c8ff794ab 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 2c1fdccd13c..bd3a1b2f672 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 9a571e07570..c3e4205dfc9 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 16e13f70092..ce5e81d4109 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 0fd68ca3a20..6c9a63fe7bd 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 b667dc0a576..016635339a9 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 0b838b3e0f9..f82c585b1d1 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 c8b2ce97c0c..d4c65954fe6 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 4b10451c813..ef6ac485b72 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] <cmd> [args..] + println("Usage: rustpkg [options] <cmd> [args..] Where <cmd> 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 <cmd> + println("rustpkg do <cmd> 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 <id|name>[@version] + println("rustpkg uninstall <id|name>[@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 <id|name>[@version] + println("rustpkg [options..] prefer <id|name>[@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 <id|name>[@version] + println("rustpkg [options..] unprefer <id|name>[@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 d49a581e070..b68e42d8ebe 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 acfa02a4def..b2e68c8d20f 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -348,12 +348,57 @@ impl<'self> Iterator<libc::c_char> 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<uint>, + 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 4e55c5fe60e..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -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 -`<T: Reader>`, 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<T:Reader> 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<T:Reader>(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::<T>(&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::<u64, f64>(self.read_be_u64()) - } - } - - fn read_be_f32(&self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(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::<u64, f64>(self.read_le_u64()) - } - } - - fn read_le_f32(&self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(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<T, C> { - 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<R:Reader,C> Reader for Wrapper<R, C> { - 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<T>(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<T>(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<W:Writer,C> Writer for Wrapper<W, C> { - 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<T>(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<T>(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<T:Writer> 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<t> { - priv arg: Arg<t>, - } - - impl <t> Res<t> { - pub fn new(arg: Arg<t>) -> Res<t> { - Res { arg: arg } - } - } - - #[unsafe_destructor] - impl<T> Drop for Res<T> { - 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<t> { - priv val: t, - priv opt_level: Option<Level>, - 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<Level>, - 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<Level>, - blk: &fn(v: Res<fd_t>)) { - 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<Level>, - 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 5e1ef3658b3..35a3ca3cff0 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 ba2b42c9b9c..1f32c6a0a35 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 886ad9995a1..bb8e6674b46 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 99634b532b0..4b16f0bc0e1 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<T: Reader> 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<T: Reader> 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<T>(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<T>(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 a43bcd8142e..d035e2f457c 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<P: PathLike>(path: &P, - mode: FileMode, - access: FileAccess - ) -> Option<FileStream> { - 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<P: ToCStr>(path: &P, + mode: FileMode, + access: FileAccess + ) -> Option<FileStream> { + 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<P: PathLike>(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<P: PathLike>(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<P: PathLike>(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<P: ToCStr>(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<P: PathLike>(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<P: PathLike>(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<P: PathLike>(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<P: ToCStr>(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<P: PathLike>(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<P: PathLike>(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<P: PathLike>(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<P: ToCStr>(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<P: PathLike>(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<P: PathLike>(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<P: PathLike>(path: &P) -> Option<FileStat> { - 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<P: ToCStr>(path: &P) -> Option<FileStat> { + 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<P: PathLike>(path: &P) -> Option<FileStat> { /// /// 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<P: PathLike>(path: &P) -> Option<FileStat> { /// 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<P: PathLike>(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<P: ToCStr>(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 5f6b4398c22..0ec37cd3c07 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 a80c1aab398..758c9779165 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<T>(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 d6820981181..ba819df071a 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 00000000000..27cf9781c9c --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +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<SocketType>, + protocol: Option<Protocol>, + flags: uint, +} + +pub struct Info { + address: SocketAddr, + family: uint, + socktype: Option<SocketType>, + protocol: Option<Protocol>, + 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<Hint>) -> 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 f44e879a63a..cf109167089 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 f29e17cfc2f..4e841b36a5d 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<TcpStream> { - 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<TcpListener> { - 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<TcpStream, TcpAcceptor> for TcpListener { } pub struct TcpAcceptor { - priv obj: ~RtioTcpAcceptorObject + priv obj: ~RtioTcpAcceptor } impl Acceptor<TcpStream> 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 27faae0838b..2e4ae95d98e 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<UdpSocket> { - 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 1771a963ba7..e424956e2ff 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<P: PathLike>(_path: &P) -> Option<UnixStream> { - 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<P: ToCStr>(path: &P) -> Option<UnixStream> { + 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<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } + fn read(&mut self, buf: &mut [u8]) -> Option<uint> { 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<P: PathLike>(_path: &P) -> Option<UnixListener> { - 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<P: ToCStr>(path: &P) -> Option<UnixListener> { + 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<UnixStream, UnixAcceptor> for UnixListener { - fn listen(self) -> Option<UnixAcceptor> { fail!() } + fn listen(self) -> Option<UnixAcceptor> { + 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<UnixStream> for UnixAcceptor { - fn accept(&mut self) -> Option<UnixStream> { fail!() } + fn accept(&mut self) -> Option<UnixStream> { + 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 2ea1b615483..52699964b62 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<FileStream>` 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<R: Reader> Reader for Option<R> { 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<R: Reader> Reader for Option<R> { } } +impl<S: Seek> Seek for Option<S> { + 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<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for Option<L> { fn listen(self) -> Option<A> { 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 d2cd531ed26..ec9a4a0101f 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<UnboundPipeStream> { - 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<PipeStream> { + 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 5f2453852ee..ae087099d1f 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<io::PipeStream>], } @@ -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<Process> { - 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 00000000000..a13fc19d000 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +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<Signum, ~RtioSignal>, + /// chan is where all the handles send signums, which are received by + /// the clients from port. + priv chan: SharedChan<Signum>, + + /// 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<Signum>, +} + +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 e6dd9a48099..b922e6400cc 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<T>(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<uint> { - 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 31040bc51a1..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::*; - -pub trait PathLike { - fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T; -} - -impl<'self> PathLike for &'self str { - fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T { - f(*self) - } -} - -impl PathLike for Path { - fn path_as_str<T>(&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 b41d7541a60..fab0062ee00 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<Timer> { - 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 d4f31879c00..1ddc2f86f4b 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<IoFactoryObject>) -> bool { rtabort!("unimpl") } - fn borrow<T>(_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 660d1cd4359..31650ede700 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<io::stdio::StdWriter>, +} + +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 9ea7b734d24..66d7a6bf488 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 501def8b060..66a0676a2f4 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<T>(f: &fn(&mut IoFactory) -> Option<T>) -> Option<T> { + 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<P: PathLike>(&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<ai::Hint>) -> 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<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>; - fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>; - fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError>; - fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>; - fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>; - fn fs_readdir<P: PathLike>(&mut self, path: &P, flags: c_int) -> + fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError>; + fn fs_stat(&mut self, path: &CString) -> Result<FileStat, IoError>; + 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<RtioPipeObject>]), 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<Signum>) + -> 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<uint, IoError>; 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<uint, IoError>; + 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 ee163bab3c0..6e661884616 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<SchedMessage>, 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 c4f352501a0..1ea68bb52d7 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("<unnamed>"); - 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("<unnamed>"); - - 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("<unnamed>"); + + // 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 4f7ebb4a721..c238b1dfba1 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 647d88c26f2..070985fb0a5 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::<Task>) { + 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 f2abcd3aca7..a1593d5c8db 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<UvError>); +type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &net::UvAddrInfo, Option<UvError>); 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<UvAddrInfo>, + service: Option<&str>, hints: Option<ai::Hint>, 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 ff7bb9dd03a..108aef43c3c 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 5d64ca4d755..d2ca15959b0 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<P: PathLike>(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<P: PathLike>(self, loop_: &Loop, path: &P, - flags: int, mode: int) -> Result<c_int, UvError> { + pub fn open_sync(self, loop_: &Loop, path: &CString, + flags: int, mode: int) -> Result<c_int, UvError> { 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<P: PathLike>(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<P: PathLike>(self, loop_: &Loop, path: &P) + pub fn unlink_sync(self, loop_: &Loop, path: &CString) -> Result<c_int, UvError> { 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<P: PathLike>(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<c_int, UvError> { @@ -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<c_int, UvError> { @@ -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<c_int, UvError> { let complete_cb_ptr = { @@ -186,44 +183,41 @@ impl FsRequest { self.sync_cleanup(result) } - pub fn mkdir<P: PathLike>(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<P: PathLike>(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<P: PathLike>(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 8cbcd7b77c0..40f0750b2d0 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 3a6a3acbc53..c92a54425bf 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<UvError>); pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>); pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>); pub type UdpSendCallback = ~fn(UdpWatcher, Option<UvError>); +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<UdpReceiveCallback>, udp_send_cb: Option<UdpSendCallback>, exit_cb: Option<ExitCallback>, + signal_cb: Option<SignalCallback>, } 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<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W { @@ -186,6 +202,7 @@ impl<H, W: Watcher + NativeHandle<*H>> 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<H, W: Watcher + NativeHandle<*H>> 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<UvError> /// 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 a2608bf6b24..77de8348c14 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 1147c731a60..74b9312954c 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 176754de8f7..f0d0afeb6aa 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<UvPipeStream>], 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::<uvll::uv_stdio_container_t>(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<UvPipeStream> { - 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 00000000000..3252c89673d --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use 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 7b09cf2eb0e..fb3c84df39f 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 00000000000..f44c5ae8eff --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use prelude::*; +use 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<TTY, uv::UvError> + { + 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 8dd0f8a6b10..29370c484eb 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<P: PathLike>(loop_: &mut Loop, path: &P, - cb: ~fn(&mut FsRequest, &mut Loop, &P, - ~fn(&FsRequest, Option<UvError>))) +fn uv_fs_helper(loop_: &mut Loop, path: &CString, + cb: ~fn(&mut FsRequest, &mut Loop, &CString, + ~fn(&FsRequest, Option<UvError>))) -> Result<(), IoError> { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell<Result<(), IoError>> = &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<~RtioTcpStreamObject, IoError>> = &result_cell; + let result_cell_ptr: *Cell<Result<~RtioTcpStream, IoError>> = &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<P: PathLike>(&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<P: PathLike>(&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<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError> { + fn fs_stat(&mut self, path: &CString) -> Result<FileStat, IoError> { use str::StrSlice; let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell<Result<FileStat, @@ -625,14 +627,15 @@ 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.stat(self.uv_loop(), path) - |req,err| { + // Don't pick up the null byte + let slice = path.as_bytes().slice(0, path.len()); + let path_instance = Cell::new(Path::new(slice)); + do stat_req.stat(self.uv_loop(), path) |req,err| { let res = match err { None => { 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<ai::Hint>) -> Result<~[ai::Info], IoError> { let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell<Result<~[IpAddr], IoError>> = &result_cell; - let host_ptr: *&str = &host; + let result_cell_ptr: *Cell<Result<~[ai::Info], IoError>> = &result_cell; + let host_ptr: *Option<&str> = &host; + let servname_ptr: *Option<&str> = &servname; + let hint_ptr: *Option<ai::Hint> = &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<P: PathLike>(&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<P: PathLike>(&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<P: PathLike>(&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<RtioPipeObject>]), 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<~RtioPipe, IoError>> = &result_cell; + let pipe_cell = Cell::new(pipe); + let pipe_cell_ptr: *Cell<UvUnboundPipe> = &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<Signum>) + -> 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<Result<~RtioTcpStreamObject, IoError>>, + priv incoming: Tube<Result<~RtioTcpStream, IoError>>, } 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<int, IoError> { @@ -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<uint, IoError> { + 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<Result<~RtioPipe, IoError>>, +} + +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 367585b0f0e..75e6a0c6ca5 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 c4cb8be2061..615ba60e066 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<c_int>, 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 8c72e083f88..12316cb5ead 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 f134788942c..053076c5d89 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<uint>) -> ~[~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 dec13eded39..fbe2988f77c 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 4d5da19dafd..8c78e34528b 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<A:IterBytes> 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 1d9d5512ff4..456d344b838 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 bbbaf2a2f60..736f92910af 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<term::Terminal>) - 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 1018e79aabc..99bcb36eedb 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 52807009073..3e07b16221e 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 dcfeb99365a..119a74cccd6 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 38921648a2b..e9e6eb872c8 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 c9405d72464..fad9eab7542 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<Span>) -> @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<E : Encodable<extra::json::Encoder>>(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 871584003b5..4801fa21fc4 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 0e330da31e6..400ff804485 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<ast::explicit_self_>, 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: &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<comments::cmnt> { diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 3e9b8ba136e..0cbbb58d02c 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 7323397508e..269da8e7882 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 2d209e40e42..f91327b6a65 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<M: MutableMap<uint, uint>>(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<M: MutableMap<uint, uint>>(map: &mut M, n_keys: uint) { } fn descending<M: MutableMap<uint, uint>>(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<uint,uint> = TreeMap::new(); @@ -131,12 +130,12 @@ fn main() { } { - io::println(" Random integers:"); + println(" Random integers:"); let mut map: TreeMap<uint,uint> = TreeMap::new(); vector(&mut map, n_keys, rand); } - io::println("\nHashMap:"); + println("\nHashMap:"); { let mut map: HashMap<uint,uint> = HashMap::new(); @@ -149,12 +148,12 @@ fn main() { } { - io::println(" Random integers:"); + println(" Random integers:"); let mut map: HashMap<uint,uint> = HashMap::new(); vector(&mut map, n_keys, rand); } - io::println("\nTrieMap:"); + println("\nTrieMap:"); { let mut map: TrieMap<uint> = TrieMap::new(); @@ -167,7 +166,7 @@ fn main() { } { - io::println(" Random integers:"); + println(" Random integers:"); let mut map: TrieMap<uint> = 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 b9a8e74668f..9f65dc1e555 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 97479fc133a..2a5971be216 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 584a8b8befc..1ff531324b3 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 96e87788b70..6bfb731badd 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::<uint>(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 ef1061c780e..52f068b8b1c 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::<int>(args[1]).unwrap(); diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 59dd0846b59..cfc78e1615e 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 88b3cfdff42..b3c3fa4db6f 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 be2bd051cad..e1b1f59298e 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 189b3ef740e..d4f4a46af38 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<StdReader>) -> 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 76e70060929..dcfef4e1d9c 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 c5039854444..ef5ad2766ca 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 a8b9000c6d9..621510cea99 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 2be763ee768..9dc29e59f90 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 22cf54428a7..2818214c994 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 863663334f8..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[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 bb01c27fa0d..5211e76d3d7 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<T:Baz> 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 0e0e52c6273..4ff184b4483 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 b1c5f2f0f2d..8d3ad267642 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<T> { fn roundtrip<T: Rand + Eq + Encodable<Encoder> + Decodable<Decoder>>() { 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 8a498563359..2831740deaf 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 acb2dde99ad..8cd2d9edbd7 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 0ef9e7108ae..5a3b177aadc 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<rdr:'static + io::Reader>(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 2d4e128f623..e092d45ce68 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 9665da11b93..ba92434ba69 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 55273f7029b..50d6a3ae6b8 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 ebf29be6d5e..86cef39abc8 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 7b80974313e..32e13f5ac7f 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 e7d0cc01240..7b96d5a48b9 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 46ec68675e7..4282e7acf19 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 40f98355f34..247b74e4643 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 e90d6b28626..0580bc938d7 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 0259c3955d8..5e03b47d1b1 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<A:Serializable> Serializable for F<A> { } } -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 c7497bf3de5..ef59606afe3 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 e2402080bc3..fa681c81398 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 70d8b8fe5a4..14595f83ce5 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 7501c46079d..85cf265c2d0 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 5ac26e65d88..c8f2afe8c61 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<T> { fn new() -> Self; } @@ -34,7 +32,7 @@ mod base { impl ::base::HasNew<Bar> for Bar { fn new() -> Bar { - io::println("Bar"); + println("Bar"); Bar { dummy: () } } } |
