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)
This commit is contained in:
bors 2013-10-24 14:26:15 -07:00
commit 3f5b2219cc
141 changed files with 3939 additions and 5453 deletions

View File

@ -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;

View File

@ -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

View File

@ -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.");
}
~~~

View File

@ -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()
}

View File

@ -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); }
}

View File

@ -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")

View File

@ -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);

View File

@ -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;

View File

@ -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
};
}
}

View File

@ -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() )
}
}

View File

@ -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);
};

View File

@ -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)
}
}
}

View File

@ -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);
}

View File

@ -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});
}

View File

@ -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);

View File

@ -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))
}
}

View File

@ -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 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,
};
st.write_failures();
let m = @mut MemWriter::new();
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 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

View File

@ -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 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 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
};
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;
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)]

View File

@ -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 = ~"";
let mut rdr = BufReader::new(s.as_bytes());
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:
':' | '/' | '?' | '#' | '[' | ']' | '@' |
loop {
let mut buf = [0];
let ch = match rdr.read(buf) {
None => break,
Some(*) => buf[0] as char,
};
// sub-delims:
'!' | '$' | '&' | '"' | '(' | ')' | '*' |
'+' | ',' | ';' | '=' => {
out.push_char(ch);
}
match ch {
// unreserved:
'A' .. 'Z' |
'a' .. 'z' |
'0' .. '9' |
'-' | '.' | '_' | '~' => {
out.push_char(ch);
}
_ => {
if full_url {
match ch {
// gen-delims:
':' | '/' | '?' | '#' | '[' | ']' | '@' |
_ => out.push_str(format!("%{:X}", ch as uint))
}
} else {
out.push_str(format!("%{:X}", ch as uint));
// 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 = ~"";
let mut rdr = BufReader::new(s.as_bytes());
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);
}
}
ch => out.push_char(ch)
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;
out
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);
}
}
ch => out.push_char(ch)
}
}
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 = ~"";
let mut rdr = BufReader::new(s.as_bytes());
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))
}
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
}
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;
let mut rdr = BufReader::new(s);
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);
}
parsing_key = true;
key = ~"";
value = ~"";
}
'=' => 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
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 => ~[],
};
if parsing_key {
key.push_char(ch)
} else {
value.push_char(ch)
values.push(value);
m.insert(key, values);
}
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);
}
m
}
if key != ~"" && value != ~"" {
let mut values = match m.pop(&key) {
Some(values) => values,
None => ~[],
};
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 {

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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())
}

View File

@ -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())
}
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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 : {}",

View File

@ -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);

View File

@ -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) {

View File

@ -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
}

View File

@ -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");

View File

@ -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,

View File

@ -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;
}

View File

@ -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]);
}

View File

@ -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()));
}

View File

@ -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());
}
}

View File

@ -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 {}",

View File

@ -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!");
}

View File

@ -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;
}

View File

@ -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, ~[]);

View File

@ -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!");
}

View File

@ -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.

View File

@ -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)));
~""
}
}
}

View File

@ -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() {

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
}

View File

@ -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

View File

@ -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};

View File

@ -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
}
}

View File

@ -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);
}
}
}

View File

@ -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 tell(&self) -> u64 { self.pos as u64 }
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
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; }
}
}
}
impl Decorator<~[u8]> for MemWriter {
fn inner(self) -> ~[u8] {
match self {
MemWriter { buf: buf } => buf
}
}
fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
match *self {
MemWriter { buf: ref buf } => buf
}
}
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
match *self {
MemWriter { buf: ref mut buf } => buf
}
}
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]

View File

@ -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).

View File

@ -17,13 +17,31 @@ use os;
use prelude::*;
use super::super::*;
fn raise_error() {
// XXX: this should probably be a bit more descriptive...
let (kind, desc) = match os::errno() as i32 {
#[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...
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,

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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
}

View File

@ -8,44 +8,289 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use prelude::*;
use super::super::*;
use super::super::support::PathLike;
/*!
pub struct UnixStream;
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 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));
}
}
}

View File

@ -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 {

View File

@ -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) {}
}

View File

@ -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
}
}
}
}

220
src/libstd/rt/io/signal.rs Normal file
View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}

View File

@ -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
}
}
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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(),

View File

@ -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 {}

View File

@ -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());

View File

@ -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");
}

View File

@ -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() }

View File

@ -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) -> ! {

View File

@ -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);
}

View File

@ -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 {

View File

@ -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();

View File

@ -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 {

View File

@ -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);

View File

@ -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 listen(&mut self, cb: ConnectionCallback) -> Result<(), UvError> {
{
let data = self.get_watcher_data();
assert!(data.connect_cb.is_none());
data.connect_cb = Some(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 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 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) {
{
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 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();
}
}
}
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");

View File

@ -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) {
{
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_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) }
#[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 data = self.get_watcher_data();
assert!(data.connect_cb.is_none());
data.connect_cb = Some(cb);
}
let connect = net::ConnectRequest::new();
let name = do name.with_ref |p| { p };
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 {

View File

@ -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))
}
}
}

View File

@ -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 }
}
}

View File

@ -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 {

84
src/libstd/rt/uv/tty.rs Normal file
View File

@ -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 }
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}
}
}
}
/*

View File

@ -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(),

View File

@ -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

View File

@ -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);

View File

@ -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 {

View File

@ -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);

View File

@ -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()));

View File

@ -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)))
}
}
}

View File

@ -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);

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More