auto merge of #11946 : alexcrichton/rust/no-io-error, r=brson

Turns out this was a little more far-reaching than I thought it was.

The first commit is the crux of this stack of commits. The `io::io_error` condition is completely removed and the `read` and `write` methods are altered to return `IoResult<T>`. This turned out to be an incredibly far-reaching change!

Overall, I'm very happy with how this turned out (in addition with the `unused_must_use` lint). I had to almost rewrite the pretty printer in `libsyntax` as well as the the formatting in `librustdoc` (as one would expect). These two modules do *tons* of I/O, and I believe that it's definitely improved.

This pull request also introduces the `if_ok!()` macro for returning-early from something that returns a result. I made quite liberal use of this in mostly the pretty printer and html renderer, and I found its usage generally quite pleasant and convenient to have. I didn't really feel like adding any other macro while I was using it, and I figured that pretty printing could be nicer, but it's nowhere near horrid today.

This may be a controversial issue closing, but I'm going to say it.

Closes #6163
This commit is contained in:
bors
2014-02-03 10:41:34 -08:00
122 changed files with 4346 additions and 4233 deletions
+8 -2
View File
@@ -234,7 +234,13 @@ pub fn run_tests(config: &config) {
// For context, see #8904
io::test::raise_fd_limit();
let res = test::run_tests_console(&opts, tests);
if !res { fail!("Some tests failed"); }
match res {
Ok(true) => {}
Ok(false) => fail!("Some tests failed"),
Err(e) => {
println!("I/O failure during tests: {}", e);
}
}
}
pub fn test_opts(config: &config) -> test::TestOpts {
@@ -255,7 +261,7 @@ pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] {
debug!("making tests from {}",
config.src_base.display());
let mut tests = ~[];
let dirs = fs::readdir(&config.src_base);
let dirs = fs::readdir(&config.src_base).unwrap();
for file in dirs.iter() {
let file = file.clone();
debug!("inspecting file {}", file.display());
+6 -6
View File
@@ -58,9 +58,9 @@ pub fn run(lib_path: &str,
});
match opt_process {
Some(ref mut process) => {
Ok(ref mut process) => {
for input in input.iter() {
process.input().write(input.as_bytes());
process.input().write(input.as_bytes()).unwrap();
}
let run::ProcessOutput { status, output, error } = process.finish_with_output();
@@ -70,7 +70,7 @@ pub fn run(lib_path: &str,
err: str::from_utf8_owned(error).unwrap()
})
},
None => None
Err(..) => None
}
}
@@ -90,13 +90,13 @@ pub fn run_background(lib_path: &str,
});
match opt_process {
Some(mut process) => {
Ok(mut process) => {
for input in input.iter() {
process.input().write(input.as_bytes());
process.input().write(input.as_bytes()).unwrap();
}
Some(process)
},
None => None
Err(..) => None
}
}
+11 -9
View File
@@ -153,7 +153,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
let rounds =
match props.pp_exact { Some(_) => 1, None => 2 };
let src = File::open(testfile).read_to_end();
let src = File::open(testfile).read_to_end().unwrap();
let src = str::from_utf8_owned(src).unwrap();
let mut srcs = ~[src];
@@ -175,7 +175,7 @@ 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);
let s = File::open(&filepath).read_to_end();
let s = File::open(&filepath).read_to_end().unwrap();
str::from_utf8_owned(s).unwrap()
}
None => { srcs[srcs.len() - 2u].clone() }
@@ -318,8 +318,10 @@ fn run_debuginfo_test(config: &config, props: &TestProps, testfile: &Path) {
//waiting 1 second for gdbserver start
timer::sleep(1000);
let result = task::try(proc() {
tcp::TcpStream::connect(
SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 5039 });
tcp::TcpStream::connect(SocketAddr {
ip: Ipv4Addr(127, 0, 0, 1),
port: 5039,
}).unwrap();
});
if result.is_err() {
continue;
@@ -361,7 +363,7 @@ fn run_debuginfo_test(config: &config, props: &TestProps, testfile: &Path) {
stdout: out,
stderr: err,
cmdline: cmdline};
process.force_destroy();
process.force_destroy().unwrap();
}
_=> {
@@ -727,7 +729,7 @@ fn compose_and_run_compiler(
fn ensure_dir(path: &Path) {
if path.is_dir() { return; }
fs::mkdir(path, io::UserRWX);
fs::mkdir(path, io::UserRWX).unwrap();
}
fn compose_and_run(config: &config, testfile: &Path,
@@ -852,7 +854,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);
File::create(&outfile).write(out.as_bytes());
File::create(&outfile).write(out.as_bytes()).unwrap();
}
fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path {
@@ -1003,7 +1005,7 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps,
fn _arm_push_aux_shared_library(config: &config, testfile: &Path) {
let tdir = aux_output_dir_name(config, testfile);
let dirs = fs::readdir(&tdir);
let dirs = fs::readdir(&tdir).unwrap();
for file in dirs.iter() {
if file.extension_str() == Some("so") {
// FIXME (#9639): This needs to handle non-utf8 paths
@@ -1099,7 +1101,7 @@ fn disassemble_extract(config: &config, _props: &TestProps,
fn count_extracted_lines(p: &Path) -> uint {
let x = File::open(&p.with_extension("ll")).read_to_end();
let x = File::open(&p.with_extension("ll")).read_to_end().unwrap();
let x = str::from_utf8_owned(x).unwrap();
x.lines().len()
}
+14 -21
View File
@@ -47,7 +47,7 @@ An example program that does this task reads like this:
# #[allow(unused_imports)];
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
# use std::io::{File, IoResult};
# use std::io::MemReader;
# use std::io::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\
@@ -55,7 +55,7 @@ use std::io::{BufferedReader, File};
# 789 123\n\
# 45 67\n\
# ");
# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
# pub fn new(_inner: IoResult<File>) -> BufferedReader<MemReader> {
# BufferedReader::new(MemReader::new(s.to_owned()))
# }
# }
@@ -71,7 +71,6 @@ fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[];
// Path takes a generic by-value, rather than by reference
# let _g = std::io::ignore_io_error();
let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path));
@@ -245,7 +244,7 @@ and trapping its exit status using `task::try`:
use std::io::{BufferedReader, File};
use std::task;
# mod BufferedReader {
# use std::io::File;
# use std::io::{File, IoResult};
# use std::io::MemReader;
# use std::io::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\
@@ -253,7 +252,7 @@ use std::task;
# 789 123\n\
# 45 67\n\
# ");
# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
# pub fn new(_inner: IoResult<File>) -> BufferedReader<MemReader> {
# BufferedReader::new(MemReader::new(s.to_owned()))
# }
# }
@@ -277,7 +276,6 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[];
# let _g = std::io::ignore_io_error();
let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path));
@@ -347,7 +345,7 @@ but similarly clear as the version that used `fail!` in the logic where the erro
# #[allow(unused_imports)];
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
# use std::io::{File, IoResult};
# use std::io::MemReader;
# use std::io::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\
@@ -355,7 +353,7 @@ use std::io::{BufferedReader, File};
# 789 123\n\
# 45 67\n\
# ");
# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
# pub fn new(_inner: IoResult<File>) -> BufferedReader<MemReader> {
# BufferedReader::new(MemReader::new(s.to_owned()))
# }
# }
@@ -374,7 +372,6 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[];
# let _g = std::io::ignore_io_error();
let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path));
@@ -415,7 +412,7 @@ and replaces bad input lines with the pair `(-1,-1)`:
# #[allow(unused_imports)];
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
# use std::io::{File, IoResult};
# use std::io::MemReader;
# use std::io::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\
@@ -423,7 +420,7 @@ use std::io::{BufferedReader, File};
# 789 123\n\
# 45 67\n\
# ");
# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
# pub fn new(_inner: IoResult<File>) -> BufferedReader<MemReader> {
# BufferedReader::new(MemReader::new(s.to_owned()))
# }
# }
@@ -447,7 +444,6 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[];
# let _g = std::io::ignore_io_error();
let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path));
@@ -489,7 +485,7 @@ Changing the condition's return type from `(int,int)` to `Option<(int,int)>` wil
# #[allow(unused_imports)];
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
# use std::io::{IoResult, File};
# use std::io::MemReader;
# use std::io::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\
@@ -497,7 +493,7 @@ use std::io::{BufferedReader, File};
# 789 123\n\
# 45 67\n\
# ");
# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
# pub fn new(_inner: IoResult<File>) -> BufferedReader<MemReader> {
# BufferedReader::new(MemReader::new(s.to_owned()))
# }
# }
@@ -522,7 +518,6 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[];
# let _g = std::io::ignore_io_error();
let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path));
@@ -573,7 +568,7 @@ This can be encoded in the handler API by introducing a helper type: `enum Malfo
# #[allow(unused_imports)];
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
# use std::io::{File, IoResult};
# use std::io::MemReader;
# use std::io::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\
@@ -581,7 +576,7 @@ use std::io::{BufferedReader, File};
# 789 123\n\
# 45 67\n\
# ");
# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
# pub fn new(_inner: IoResult<File>) -> BufferedReader<MemReader> {
# BufferedReader::new(MemReader::new(s.to_owned()))
# }
# }
@@ -615,7 +610,6 @@ fn main() {
fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[];
# let _g = std::io::ignore_io_error();
let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path));
@@ -696,7 +690,7 @@ a second condition and a helper function will suffice:
# #[allow(unused_imports)];
use std::io::{BufferedReader, File};
# mod BufferedReader {
# use std::io::File;
# use std::io::{File, IoResult};
# use std::io::MemReader;
# use std::io::BufferedReader;
# static s : &'static [u8] = bytes!("1 2\n\
@@ -704,7 +698,7 @@ use std::io::{BufferedReader, File};
# 789 123\n\
# 45 67\n\
# ");
# pub fn new(_inner: Option<File>) -> BufferedReader<MemReader> {
# pub fn new(_inner: IoResult<File>) -> BufferedReader<MemReader> {
# BufferedReader::new(MemReader::new(s.to_owned()))
# }
# }
@@ -752,7 +746,6 @@ fn parse_int(x: &str) -> int {
fn read_int_pairs() -> ~[(int,int)] {
let mut pairs = ~[];
# let _g = std::io::ignore_io_error();
let path = Path::new(&"foo.txt");
let mut reader = BufferedReader::new(File::open(&path));
+1
View File
@@ -69,6 +69,7 @@ extern mod run_pass_stage2;
use run_pass_stage2::*;
use std::io;
use std::io::Writer;
#[allow(warnings)]
fn main() {
let mut out = io::stdout();
"""
+10 -10
View File
@@ -637,7 +637,7 @@ fn test_arc_condvar_poison() {
fn test_mutex_arc_poison() {
let arc = ~MutexArc::new(1);
let arc2 = ~arc.clone();
task::try(proc() {
let _ = task::try(proc() {
arc2.access(|one| {
assert_eq!(*one, 2);
})
@@ -668,7 +668,7 @@ fn test_unsafe_mutex_arc_nested() {
fn test_mutex_arc_access_in_unwind() {
let arc = MutexArc::new(1i);
let arc2 = arc.clone();
task::try::<()>(proc() {
let _ = task::try::<()>(proc() {
struct Unwinder {
i: MutexArc<int>
}
@@ -687,7 +687,7 @@ fn drop(&mut self) {
fn test_rw_arc_poison_wr() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
task::try(proc() {
let _ = task::try(proc() {
arc2.write(|one| {
assert_eq!(*one, 2);
})
@@ -701,7 +701,7 @@ fn test_rw_arc_poison_wr() {
fn test_rw_arc_poison_ww() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
task::try(proc() {
let _ = task::try(proc() {
arc2.write(|one| {
assert_eq!(*one, 2);
})
@@ -714,7 +714,7 @@ fn test_rw_arc_poison_ww() {
fn test_rw_arc_poison_dw() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
task::try(proc() {
let _ = task::try(proc() {
arc2.write_downgrade(|mut write_mode| {
write_mode.write(|one| {
assert_eq!(*one, 2);
@@ -729,7 +729,7 @@ fn test_rw_arc_poison_dw() {
fn test_rw_arc_no_poison_rr() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
task::try(proc() {
let _ = task::try(proc() {
arc2.read(|one| {
assert_eq!(*one, 2);
})
@@ -742,7 +742,7 @@ fn test_rw_arc_no_poison_rr() {
fn test_rw_arc_no_poison_rw() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
task::try(proc() {
let _ = task::try(proc() {
arc2.read(|one| {
assert_eq!(*one, 2);
})
@@ -755,7 +755,7 @@ fn test_rw_arc_no_poison_rw() {
fn test_rw_arc_no_poison_dr() {
let arc = RWArc::new(1);
let arc2 = arc.clone();
task::try(proc() {
let _ = task::try(proc() {
arc2.write_downgrade(|write_mode| {
let read_mode = arc2.downgrade(write_mode);
read_mode.read(|one| {
@@ -800,7 +800,7 @@ fn test_rw_arc() {
// Wait for children to pass their asserts
for r in children.mut_iter() {
r.recv();
let _ = r.recv();
}
// Wait for writer to finish
@@ -814,7 +814,7 @@ fn test_rw_arc() {
fn test_rw_arc_access_in_unwind() {
let arc = RWArc::new(1i);
let arc2 = arc.clone();
task::try::<()>(proc() {
let _ = task::try::<()>(proc() {
struct Unwinder {
i: RWArc<int>
}
+1 -1
View File
@@ -359,7 +359,7 @@ pub fn bench_from_base64(bh: & mut BenchHarness) {
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
let b = s.as_bytes().to_base64(STANDARD);
bh.iter(|| {
b.from_base64();
b.from_base64().unwrap();
});
bh.bytes = b.len() as u64;
}
+23 -11
View File
@@ -12,6 +12,10 @@
use std::str;
macro_rules! if_ok( ($e:expr) => (
match $e { Ok(e) => e, Err(e) => { self.last_error = Err(e); return } }
) )
// Simple Extensible Binary Markup Language (ebml) reader and writer on a
// cursor model. See the specification here:
// http://www.matroska.org/technical/specs/rfc/index.html
@@ -595,9 +599,15 @@ pub mod writer {
// ebml writing
pub struct Encoder<'a> {
// FIXME(#5665): this should take a trait object
// FIXME(#5665): this should take a trait object. Note that if you
// delete this comment you should consider removing the
// unwrap()'s below of the results of the calls to
// write(). We're guaranteed that writing into a MemWriter
// won't fail, but this is not true for all I/O streams in
// general.
writer: &'a mut MemWriter,
priv size_positions: ~[uint],
last_error: io::IoResult<()>,
}
fn write_sized_vuint(w: &mut MemWriter, n: uint, size: uint) {
@@ -609,7 +619,7 @@ fn write_sized_vuint(w: &mut MemWriter, n: uint, size: uint) {
4u => w.write(&[0x10u8 | ((n >> 24_u) as u8), (n >> 16_u) as u8,
(n >> 8_u) as u8, n as u8]),
_ => fail!("vint to write too big: {}", n)
};
}.unwrap()
}
fn write_vuint(w: &mut MemWriter, n: uint) {
@@ -624,7 +634,8 @@ pub fn Encoder<'a>(w: &'a mut MemWriter) -> Encoder<'a> {
let size_positions: ~[uint] = ~[];
Encoder {
writer: w,
size_positions: size_positions
size_positions: size_positions,
last_error: Ok(()),
}
}
@@ -635,6 +646,7 @@ pub unsafe fn unsafe_clone(&self) -> Encoder<'a> {
Encoder {
writer: cast::transmute_copy(&self.writer),
size_positions: self.size_positions.clone(),
last_error: Ok(()),
}
}
@@ -645,18 +657,18 @@ pub fn start_tag(&mut self, tag_id: uint) {
write_vuint(self.writer, tag_id);
// Write a placeholder four-byte size.
self.size_positions.push(self.writer.tell() as uint);
self.size_positions.push(if_ok!(self.writer.tell()) as uint);
let zeroes: &[u8] = &[0u8, 0u8, 0u8, 0u8];
self.writer.write(zeroes);
if_ok!(self.writer.write(zeroes));
}
pub fn end_tag(&mut self) {
let last_size_pos = self.size_positions.pop().unwrap();
let cur_pos = self.writer.tell();
self.writer.seek(last_size_pos as i64, io::SeekSet);
let cur_pos = if_ok!(self.writer.tell());
if_ok!(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, 4u);
self.writer.seek(cur_pos as i64, io::SeekSet);
if_ok!(self.writer.seek(cur_pos as i64, io::SeekSet));
debug!("End tag (size = {})", size);
}
@@ -670,7 +682,7 @@ pub fn wr_tag(&mut self, tag_id: uint, blk: ||) {
pub fn wr_tagged_bytes(&mut self, tag_id: uint, b: &[u8]) {
write_vuint(self.writer, tag_id);
write_vuint(self.writer, b.len());
self.writer.write(b);
self.writer.write(b).unwrap();
}
pub fn wr_tagged_u64(&mut self, tag_id: uint, v: u64) {
@@ -723,12 +735,12 @@ pub fn wr_tagged_str(&mut self, tag_id: uint, v: &str) {
pub fn wr_bytes(&mut self, b: &[u8]) {
debug!("Write {} bytes", b.len());
self.writer.write(b);
self.writer.write(b).unwrap();
}
pub fn wr_str(&mut self, s: &str) {
debug!("Write str: {}", s);
self.writer.write(s.as_bytes());
self.writer.write(s.as_bytes()).unwrap();
}
}
+1 -1
View File
@@ -201,7 +201,7 @@ pub fn bench_from_hex(bh: & mut BenchHarness) {
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
let b = s.as_bytes().to_hex();
bh.iter(|| {
b.from_hex();
b.from_hex().unwrap();
});
bh.bytes = b.len() as u64;
}
+86 -59
View File
@@ -234,6 +234,10 @@ fn main() {
use serialize;
use treemap::TreeMap;
macro_rules! if_ok( ($e:expr) => (
match $e { Ok(e) => e, Err(e) => { self.error = Err(e); return } }
) )
/// Represents a json value
#[deriving(Clone, Eq)]
pub enum Json {
@@ -260,6 +264,14 @@ pub struct Error {
priv msg: ~str,
}
fn io_error_to_error(io: io::IoError) -> Error {
Error {
line: 0,
col: 0,
msg: format!("io error: {}", io)
}
}
fn escape_str(s: &str) -> ~str {
let mut escaped = ~"\"";
for c in s.chars() {
@@ -289,13 +301,14 @@ fn spaces(n: uint) -> ~str {
/// A structure for implementing serialization to JSON.
pub struct Encoder<'a> {
priv wr: &'a mut io::Writer,
priv error: io::IoResult<()>,
}
impl<'a> Encoder<'a> {
/// Creates a new JSON encoder whose output will be written to the writer
/// specified.
pub fn new<'a>(wr: &'a mut io::Writer) -> Encoder<'a> {
Encoder { wr: wr }
Encoder { wr: wr, error: Ok(()) }
}
/// Encode the specified struct into a json [u8]
@@ -317,7 +330,7 @@ pub fn str_encode<T:Encodable<Encoder<'a>>>(to_encode_object: &T) -> ~str {
}
impl<'a> serialize::Encoder for Encoder<'a> {
fn emit_nil(&mut self) { write!(self.wr, "null") }
fn emit_nil(&mut self) { if_ok!(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); }
@@ -333,20 +346,20 @@ fn emit_nil(&mut self) { write!(self.wr, "null") }
fn emit_bool(&mut self, v: bool) {
if v {
write!(self.wr, "true");
if_ok!(write!(self.wr, "true"));
} else {
write!(self.wr, "false");
if_ok!(write!(self.wr, "false"));
}
}
fn emit_f64(&mut self, v: f64) {
write!(self.wr, "{}", f64::to_str_digits(v, 6u))
if_ok!(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) {
write!(self.wr, "{}", escape_str(v))
if_ok!(write!(self.wr, "{}", escape_str(v)))
}
fn emit_enum(&mut self, _name: &str, f: |&mut Encoder<'a>|) { f(self) }
@@ -360,19 +373,19 @@ fn emit_enum_variant(&mut self,
// Bunny => "Bunny"
// Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]}
if cnt == 0 {
write!(self.wr, "{}", escape_str(name));
if_ok!(write!(self.wr, "{}", escape_str(name)));
} else {
write!(self.wr, "\\{\"variant\":");
write!(self.wr, "{}", escape_str(name));
write!(self.wr, ",\"fields\":[");
if_ok!(write!(self.wr, "\\{\"variant\":"));
if_ok!(write!(self.wr, "{}", escape_str(name)));
if_ok!(write!(self.wr, ",\"fields\":["));
f(self);
write!(self.wr, "]\\}");
if_ok!(write!(self.wr, "]\\}"));
}
}
fn emit_enum_variant_arg(&mut self, idx: uint, f: |&mut Encoder<'a>|) {
if idx != 0 {
write!(self.wr, ",");
if_ok!(write!(self.wr, ","));
}
f(self);
}
@@ -393,17 +406,17 @@ fn emit_enum_struct_variant_field(&mut self,
}
fn emit_struct(&mut self, _: &str, _: uint, f: |&mut Encoder<'a>|) {
write!(self.wr, r"\{");
if_ok!(write!(self.wr, r"\{"));
f(self);
write!(self.wr, r"\}");
if_ok!(write!(self.wr, r"\}"));
}
fn emit_struct_field(&mut self,
name: &str,
idx: uint,
f: |&mut Encoder<'a>|) {
if idx != 0 { write!(self.wr, ",") }
write!(self.wr, "{}:", escape_str(name));
if idx != 0 { if_ok!(write!(self.wr, ",")) }
if_ok!(write!(self.wr, "{}:", escape_str(name)));
f(self);
}
@@ -429,31 +442,31 @@ fn emit_tuple_struct_arg(&mut self, idx: uint, f: |&mut Encoder<'a>|) {
fn emit_option_some(&mut self, f: |&mut Encoder<'a>|) { f(self); }
fn emit_seq(&mut self, _len: uint, f: |&mut Encoder<'a>|) {
write!(self.wr, "[");
if_ok!(write!(self.wr, "["));
f(self);
write!(self.wr, "]");
if_ok!(write!(self.wr, "]"));
}
fn emit_seq_elt(&mut self, idx: uint, f: |&mut Encoder<'a>|) {
if idx != 0 {
write!(self.wr, ",");
if_ok!(write!(self.wr, ","));
}
f(self)
}
fn emit_map(&mut self, _len: uint, f: |&mut Encoder<'a>|) {
write!(self.wr, r"\{");
if_ok!(write!(self.wr, r"\{"));
f(self);
write!(self.wr, r"\}");
if_ok!(write!(self.wr, r"\}"));
}
fn emit_map_elt_key(&mut self, idx: uint, f: |&mut Encoder<'a>|) {
if idx != 0 { write!(self.wr, ",") }
if idx != 0 { if_ok!(write!(self.wr, ",")) }
f(self)
}
fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut Encoder<'a>|) {
write!(self.wr, ":");
if_ok!(write!(self.wr, ":"));
f(self)
}
}
@@ -463,6 +476,7 @@ fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut Encoder<'a>|) {
pub struct PrettyEncoder<'a> {
priv wr: &'a mut io::Writer,
priv indent: uint,
priv error: io::IoResult<()>,
}
impl<'a> PrettyEncoder<'a> {
@@ -471,12 +485,13 @@ pub fn new<'a>(wr: &'a mut io::Writer) -> PrettyEncoder<'a> {
PrettyEncoder {
wr: wr,
indent: 0,
error: Ok(())
}
}
}
impl<'a> serialize::Encoder for PrettyEncoder<'a> {
fn emit_nil(&mut self) { write!(self.wr, "null") }
fn emit_nil(&mut self) { if_ok!(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); }
@@ -492,19 +507,21 @@ fn emit_nil(&mut self) { write!(self.wr, "null") }
fn emit_bool(&mut self, v: bool) {
if v {
write!(self.wr, "true");
if_ok!(write!(self.wr, "true"));
} else {
write!(self.wr, "false");
if_ok!(write!(self.wr, "false"));
}
}
fn emit_f64(&mut self, v: f64) {
write!(self.wr, "{}", f64::to_str_digits(v, 6u))
if_ok!(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) { write!(self.wr, "{}", escape_str(v)); }
fn emit_str(&mut self, v: &str) {
if_ok!(write!(self.wr, "{}", escape_str(v)));
}
fn emit_enum(&mut self, _name: &str, f: |&mut PrettyEncoder<'a>|) {
f(self)
@@ -516,13 +533,14 @@ fn emit_enum_variant(&mut self,
cnt: uint,
f: |&mut PrettyEncoder<'a>|) {
if cnt == 0 {
write!(self.wr, "{}", escape_str(name));
if_ok!(write!(self.wr, "{}", escape_str(name)));
} else {
self.indent += 2;
write!(self.wr, "[\n{}{},\n", spaces(self.indent), escape_str(name));
if_ok!(write!(self.wr, "[\n{}{},\n", spaces(self.indent),
escape_str(name)));
f(self);
self.indent -= 2;
write!(self.wr, "\n{}]", spaces(self.indent));
if_ok!(write!(self.wr, "\n{}]", spaces(self.indent)));
}
}
@@ -530,9 +548,9 @@ fn emit_enum_variant_arg(&mut self,
idx: uint,
f: |&mut PrettyEncoder<'a>|) {
if idx != 0 {
write!(self.wr, ",\n");
if_ok!(write!(self.wr, ",\n"));
}
write!(self.wr, "{}", spaces(self.indent));
if_ok!(write!(self.wr, "{}", spaces(self.indent)));
f(self)
}
@@ -557,13 +575,13 @@ fn emit_struct(&mut self,
len: uint,
f: |&mut PrettyEncoder<'a>|) {
if len == 0 {
write!(self.wr, "\\{\\}");
if_ok!(write!(self.wr, "\\{\\}"));
} else {
write!(self.wr, "\\{");
if_ok!(write!(self.wr, "\\{"));
self.indent += 2;
f(self);
self.indent -= 2;
write!(self.wr, "\n{}\\}", spaces(self.indent));
if_ok!(write!(self.wr, "\n{}\\}", spaces(self.indent)));
}
}
@@ -572,11 +590,11 @@ fn emit_struct_field(&mut self,
idx: uint,
f: |&mut PrettyEncoder<'a>|) {
if idx == 0 {
write!(self.wr, "\n");
if_ok!(write!(self.wr, "\n"));
} else {
write!(self.wr, ",\n");
if_ok!(write!(self.wr, ",\n"));
}
write!(self.wr, "{}{}: ", spaces(self.indent), escape_str(name));
if_ok!(write!(self.wr, "{}{}: ", spaces(self.indent), escape_str(name)));
f(self);
}
@@ -605,50 +623,50 @@ fn emit_tuple_struct_arg(&mut self,
fn emit_seq(&mut self, len: uint, f: |&mut PrettyEncoder<'a>|) {
if len == 0 {
write!(self.wr, "[]");
if_ok!(write!(self.wr, "[]"));
} else {
write!(self.wr, "[");
if_ok!(write!(self.wr, "["));
self.indent += 2;
f(self);
self.indent -= 2;
write!(self.wr, "\n{}]", spaces(self.indent));
if_ok!(write!(self.wr, "\n{}]", spaces(self.indent)));
}
}
fn emit_seq_elt(&mut self, idx: uint, f: |&mut PrettyEncoder<'a>|) {
if idx == 0 {
write!(self.wr, "\n");
if_ok!(write!(self.wr, "\n"));
} else {
write!(self.wr, ",\n");
if_ok!(write!(self.wr, ",\n"));
}
write!(self.wr, "{}", spaces(self.indent));
if_ok!(write!(self.wr, "{}", spaces(self.indent)));
f(self)
}
fn emit_map(&mut self, len: uint, f: |&mut PrettyEncoder<'a>|) {
if len == 0 {
write!(self.wr, "\\{\\}");
if_ok!(write!(self.wr, "\\{\\}"));
} else {
write!(self.wr, "\\{");
if_ok!(write!(self.wr, "\\{"));
self.indent += 2;
f(self);
self.indent -= 2;
write!(self.wr, "\n{}\\}", spaces(self.indent));
if_ok!(write!(self.wr, "\n{}\\}", spaces(self.indent)));
}
}
fn emit_map_elt_key(&mut self, idx: uint, f: |&mut PrettyEncoder<'a>|) {
if idx == 0 {
write!(self.wr, "\n");
if_ok!(write!(self.wr, "\n"));
} else {
write!(self.wr, ",\n");
if_ok!(write!(self.wr, ",\n"));
}
write!(self.wr, "{}", spaces(self.indent));
if_ok!(write!(self.wr, "{}", spaces(self.indent)));
f(self);
}
fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut PrettyEncoder<'a>|) {
write!(self.wr, ": ");
if_ok!(write!(self.wr, ": "));
f(self);
}
}
@@ -668,22 +686,24 @@ fn encode(&self, e: &mut E) {
impl Json{
/// Encodes a json value into a io::writer. Uses a single line.
pub fn to_writer(&self, wr: &mut io::Writer) {
pub fn to_writer(&self, wr: &mut io::Writer) -> io::IoResult<()> {
let mut encoder = Encoder::new(wr);
self.encode(&mut encoder)
self.encode(&mut encoder);
encoder.error
}
/// Encodes a json value into a io::writer.
/// Pretty-prints in a more readable format.
pub fn to_pretty_writer(&self, wr: &mut io::Writer) {
pub fn to_pretty_writer(&self, wr: &mut io::Writer) -> io::IoResult<()> {
let mut encoder = PrettyEncoder::new(wr);
self.encode(&mut encoder)
self.encode(&mut encoder);
encoder.error
}
/// Encodes a json value into a string
pub fn to_pretty_str(&self) -> ~str {
let mut s = MemWriter::new();
self.to_pretty_writer(&mut s as &mut io::Writer);
self.to_pretty_writer(&mut s as &mut io::Writer).unwrap();
str::from_utf8_owned(s.unwrap()).unwrap()
}
}
@@ -1067,7 +1087,14 @@ fn parse_object(&mut self) -> Result<Json, Error> {
/// Decodes a json value from an `&mut io::Reader`
pub fn from_reader(rdr: &mut io::Reader) -> Result<Json, Error> {
let s = str::from_utf8_owned(rdr.read_to_end()).unwrap();
let contents = match rdr.read_to_end() {
Ok(c) => c,
Err(e) => return Err(io_error_to_error(e))
};
let s = match str::from_utf8_owned(contents) {
Some(s) => s,
None => return Err(Error { line: 0, col: 0, msg: ~"contents not utf-8" })
};
let mut parser = Parser::new(s.chars());
parser.parse()
}
@@ -1540,7 +1567,7 @@ impl to_str::ToStr for Json {
/// Encodes a json value into a string
fn to_str(&self) -> ~str {
let mut s = MemWriter::new();
self.to_writer(&mut s as &mut io::Writer);
self.to_writer(&mut s as &mut io::Writer).unwrap();
str::from_utf8_owned(s.unwrap()).unwrap()
}
}
+5
View File
@@ -34,6 +34,11 @@
#[deny(non_camel_case_types)];
#[deny(missing_doc)];
#[cfg(stage0)]
macro_rules! if_ok (
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
)
// Utility modules
pub mod c_vec;
+23 -20
View File
@@ -322,14 +322,15 @@ 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: &mut io::Writer, s: &Summary) {
pub fn write_5_number_summary(w: &mut io::Writer,
s: &Summary) -> io::IoResult<()> {
let (q1,q2,q3) = s.quartiles;
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
@@ -344,7 +345,8 @@ pub fn write_5_number_summary(w: &mut io::Writer, s: &Summary) {
/// 10 | [--****#******----------] | 40
/// ~~~~
pub fn write_boxplot(w: &mut io::Writer, s: &Summary, width_hint: uint) {
pub fn write_boxplot(w: &mut io::Writer, s: &Summary,
width_hint: uint) -> io::IoResult<()> {
let (q1,q2,q3) = s.quartiles;
@@ -374,48 +376,49 @@ pub fn write_boxplot(w: &mut io::Writer, s: &Summary, width_hint: uint) {
let range_width = width_hint - overhead_width;;
let char_step = range / (range_width as f64);
write!(w, "{} |", lostr);
if_ok!(write!(w, "{} |", lostr));
let mut c = 0;
let mut v = lo;
while c < range_width && v < s.min {
write!(w, " ");
if_ok!(write!(w, " "));
v += char_step;
c += 1;
}
write!(w, "[");
if_ok!(write!(w, "["));
c += 1;
while c < range_width && v < q1 {
write!(w, "-");
if_ok!(write!(w, "-"));
v += char_step;
c += 1;
}
while c < range_width && v < q2 {
write!(w, "*");
if_ok!(write!(w, "*"));
v += char_step;
c += 1;
}
write!(w, r"\#");
if_ok!(write!(w, r"\#"));
c += 1;
while c < range_width && v < q3 {
write!(w, "*");
if_ok!(write!(w, "*"));
v += char_step;
c += 1;
}
while c < range_width && v < s.max {
write!(w, "-");
if_ok!(write!(w, "-"));
v += char_step;
c += 1;
}
write!(w, "]");
if_ok!(write!(w, "]"));
while c < range_width {
write!(w, " ");
if_ok!(write!(w, " "));
v += char_step;
c += 1;
}
write!(w, "| {}", histr);
if_ok!(write!(w, "| {}", histr));
Ok(())
}
/// Returns a HashMap with the number of occurrences of every element in the
@@ -453,11 +456,11 @@ fn check(samples: &[f64], summ: &Summary) {
let mut w = io::stdout();
let w = &mut w as &mut io::Writer;
write!(w, "\n");
write_5_number_summary(w, &summ2);
write!(w, "\n");
write_boxplot(w, &summ2, 50);
write!(w, "\n");
(write!(w, "\n")).unwrap();
write_5_number_summary(w, &summ2).unwrap();
(write!(w, "\n")).unwrap();
write_boxplot(w, &summ2, 50).unwrap();
(write!(w, "\n")).unwrap();
assert_eq!(summ.sum, summ2.sum);
assert_eq!(summ.min, summ2.min);
@@ -1000,7 +1003,7 @@ fn test_boxplot_nonpositive() {
fn t(s: &Summary, expected: ~str) {
use std::io::MemWriter;
let mut m = MemWriter::new();
write_boxplot(&mut m as &mut io::Writer, s, 30);
write_boxplot(&mut m as &mut io::Writer, s, 30).unwrap();
let out = str::from_utf8_owned(m.unwrap()).unwrap();
assert_eq!(out, expected);
}
+1 -1
View File
@@ -959,7 +959,7 @@ fn test_mutex_cond_broadcast_none() {
fn test_mutex_cond_no_waiter() {
let m = Mutex::new();
let m2 = m.clone();
task::try(proc() {
let _ = task::try(proc() {
m.lock_cond(|_x| { })
});
m2.lock_cond(|cond| {
+3 -2
View File
@@ -38,7 +38,7 @@ pub fn new_in(tmpdir: &Path, suffix: &str) -> Option<TempDir> {
let mut r = rand::rng();
for _ in range(0u, 1000) {
let p = tmpdir.join(r.gen_ascii_str(16) + suffix);
match io::result(|| fs::mkdir(&p, io::UserRWX)) {
match fs::mkdir(&p, io::UserRWX) {
Err(..) => {}
Ok(()) => return Some(TempDir { path: Some(p) })
}
@@ -73,7 +73,8 @@ impl Drop for TempDir {
fn drop(&mut self) {
for path in self.path.iter() {
if path.exists() {
fs::rmdir_recursive(path);
// FIXME: is failing the right thing to do?
fs::rmdir_recursive(path).unwrap();
}
}
}
+117 -94
View File
@@ -163,7 +163,11 @@ pub fn test_main(args: &[~str], tests: ~[TestDescAndFn]) {
Some(Err(msg)) => fail!("{}", msg),
None => return
};
if !run_tests_console(&opts, tests) { fail!("Some tests failed"); }
match run_tests_console(&opts, tests) {
Ok(true) => {}
Ok(false) => fail!("Some tests failed"),
Err(e) => fail!("io error when running tests: {}", e),
}
}
// A variant optimized for invocation with a static test vector.
@@ -359,16 +363,17 @@ struct ConsoleTestState<T> {
}
impl<T: Writer> ConsoleTestState<T> {
pub fn new(opts: &TestOpts, _: Option<T>) -> ConsoleTestState<StdWriter> {
pub fn new(opts: &TestOpts,
_: Option<T>) -> io::IoResult<ConsoleTestState<StdWriter>> {
let log_out = match opts.logfile {
Some(ref path) => File::create(path),
Some(ref path) => Some(if_ok!(File::create(path))),
None => None
};
let out = match term::Terminal::new(io::stdout()) {
Err(_) => Raw(io::stdout()),
Ok(t) => Pretty(t)
};
ConsoleTestState {
Ok(ConsoleTestState {
out: out,
log_out: log_out,
use_color: use_color(),
@@ -380,100 +385,103 @@ pub fn new(opts: &TestOpts, _: Option<T>) -> ConsoleTestState<StdWriter> {
metrics: MetricMap::new(),
failures: ~[],
max_name_len: 0u,
}
})
}
pub fn write_ok(&mut self) {
self.write_pretty("ok", term::color::GREEN);
pub fn write_ok(&mut self) -> io::IoResult<()> {
self.write_pretty("ok", term::color::GREEN)
}
pub fn write_failed(&mut self) {
self.write_pretty("FAILED", term::color::RED);
pub fn write_failed(&mut self) -> io::IoResult<()> {
self.write_pretty("FAILED", term::color::RED)
}
pub fn write_ignored(&mut self) {
self.write_pretty("ignored", term::color::YELLOW);
pub fn write_ignored(&mut self) -> io::IoResult<()> {
self.write_pretty("ignored", term::color::YELLOW)
}
pub fn write_metric(&mut self) {
self.write_pretty("metric", term::color::CYAN);
pub fn write_metric(&mut self) -> io::IoResult<()> {
self.write_pretty("metric", term::color::CYAN)
}
pub fn write_bench(&mut self) {
self.write_pretty("bench", term::color::CYAN);
pub fn write_bench(&mut self) -> io::IoResult<()> {
self.write_pretty("bench", term::color::CYAN)
}
pub fn write_added(&mut self) {
self.write_pretty("added", term::color::GREEN);
pub fn write_added(&mut self) -> io::IoResult<()> {
self.write_pretty("added", term::color::GREEN)
}
pub fn write_improved(&mut self) {
self.write_pretty("improved", term::color::GREEN);
pub fn write_improved(&mut self) -> io::IoResult<()> {
self.write_pretty("improved", term::color::GREEN)
}
pub fn write_removed(&mut self) {
self.write_pretty("removed", term::color::YELLOW);
pub fn write_removed(&mut self) -> io::IoResult<()> {
self.write_pretty("removed", term::color::YELLOW)
}
pub fn write_regressed(&mut self) {
self.write_pretty("regressed", term::color::RED);
pub fn write_regressed(&mut self) -> io::IoResult<()> {
self.write_pretty("regressed", term::color::RED)
}
pub fn write_pretty(&mut self,
word: &str,
color: term::color::Color) {
color: term::color::Color) -> io::IoResult<()> {
match self.out {
Pretty(ref mut term) => {
if self.use_color {
term.fg(color);
if_ok!(term.fg(color));
}
term.write(word.as_bytes());
if_ok!(term.write(word.as_bytes()));
if self.use_color {
term.reset();
if_ok!(term.reset());
}
Ok(())
}
Raw(ref mut stdout) => stdout.write(word.as_bytes())
}
}
pub fn write_plain(&mut self, s: &str) {
pub fn write_plain(&mut self, s: &str) -> io::IoResult<()> {
match self.out {
Pretty(ref mut term) => term.write(s.as_bytes()),
Raw(ref mut stdout) => stdout.write(s.as_bytes())
}
}
pub fn write_run_start(&mut self, len: uint) {
pub fn write_run_start(&mut self, len: uint) -> io::IoResult<()> {
self.total = len;
let noun = if len != 1 { &"tests" } else { &"test" };
self.write_plain(format!("\nrunning {} {}\n", len, noun));
self.write_plain(format!("\nrunning {} {}\n", len, noun))
}
pub fn write_test_start(&mut self, test: &TestDesc, align: NamePadding) {
pub fn write_test_start(&mut self, test: &TestDesc,
align: NamePadding) -> io::IoResult<()> {
let name = test.padded_name(self.max_name_len, align);
self.write_plain(format!("test {} ... ", name));
self.write_plain(format!("test {} ... ", name))
}
pub fn write_result(&mut self, result: &TestResult) {
match *result {
pub fn write_result(&mut self, result: &TestResult) -> io::IoResult<()> {
if_ok!(match *result {
TrOk => self.write_ok(),
TrFailed => self.write_failed(),
TrIgnored => self.write_ignored(),
TrMetrics(ref mm) => {
self.write_metric();
self.write_plain(format!(": {}", fmt_metrics(mm)));
if_ok!(self.write_metric());
self.write_plain(format!(": {}", fmt_metrics(mm)))
}
TrBench(ref bs) => {
self.write_bench();
self.write_plain(format!(": {}", fmt_bench_samples(bs)));
if_ok!(self.write_bench());
self.write_plain(format!(": {}", fmt_bench_samples(bs)))
}
}
self.write_plain("\n");
});
self.write_plain("\n")
}
pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) {
pub fn write_log(&mut self, test: &TestDesc,
result: &TestResult) -> io::IoResult<()> {
match self.log_out {
None => (),
None => Ok(()),
Some(ref mut o) => {
let s = format!("{} {}\n", match *result {
TrOk => ~"ok",
@@ -482,24 +490,25 @@ pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) {
TrMetrics(ref mm) => fmt_metrics(mm),
TrBench(ref bs) => fmt_bench_samples(bs)
}, test.name.to_str());
o.write(s.as_bytes());
o.write(s.as_bytes())
}
}
}
pub fn write_failures(&mut self) {
self.write_plain("\nfailures:\n");
pub fn write_failures(&mut self) -> io::IoResult<()> {
if_ok!(self.write_plain("\nfailures:\n"));
let mut failures = ~[];
for f in self.failures.iter() {
failures.push(f.name.to_str());
}
failures.sort();
for name in failures.iter() {
self.write_plain(format!(" {}\n", name.to_str()));
if_ok!(self.write_plain(format!(" {}\n", name.to_str())));
}
Ok(())
}
pub fn write_metric_diff(&mut self, diff: &MetricDiff) {
pub fn write_metric_diff(&mut self, diff: &MetricDiff) -> io::IoResult<()> {
let mut noise = 0;
let mut improved = 0;
let mut regressed = 0;
@@ -511,77 +520,82 @@ pub fn write_metric_diff(&mut self, diff: &MetricDiff) {
LikelyNoise => noise += 1,
MetricAdded => {
added += 1;
self.write_added();
self.write_plain(format!(": {}\n", *k));
if_ok!(self.write_added());
if_ok!(self.write_plain(format!(": {}\n", *k)));
}
MetricRemoved => {
removed += 1;
self.write_removed();
self.write_plain(format!(": {}\n", *k));
if_ok!(self.write_removed());
if_ok!(self.write_plain(format!(": {}\n", *k)));
}
Improvement(pct) => {
improved += 1;
self.write_plain(format!(": {}", *k));
self.write_improved();
self.write_plain(format!(" by {:.2f}%\n", pct as f64));
if_ok!(self.write_plain(format!(": {}", *k)));
if_ok!(self.write_improved());
if_ok!(self.write_plain(format!(" by {:.2f}%\n", pct as f64)));
}
Regression(pct) => {
regressed += 1;
self.write_plain(format!(": {}", *k));
self.write_regressed();
self.write_plain(format!(" by {:.2f}%\n", pct as f64));
if_ok!(self.write_plain(format!(": {}", *k)));
if_ok!(self.write_regressed());
if_ok!(self.write_plain(format!(" by {:.2f}%\n", pct as f64)));
}
}
}
self.write_plain(format!("result of ratchet: {} matrics added, {} removed, \
{} improved, {} regressed, {} noise\n",
added, removed, improved, regressed, noise));
if_ok!(self.write_plain(format!("result of ratchet: {} matrics added, \
{} removed, {} improved, {} regressed, \
{} noise\n",
added, removed, improved, regressed,
noise)));
if regressed == 0 {
self.write_plain("updated ratchet file\n");
if_ok!(self.write_plain("updated ratchet file\n"));
} else {
self.write_plain("left ratchet file untouched\n");
if_ok!(self.write_plain("left ratchet file untouched\n"));
}
Ok(())
}
pub fn write_run_finish(&mut self,
ratchet_metrics: &Option<Path>,
ratchet_pct: Option<f64>) -> bool {
ratchet_pct: Option<f64>) -> io::IoResult<bool> {
assert!(self.passed + self.failed + self.ignored + self.measured == self.total);
let ratchet_success = match *ratchet_metrics {
None => true,
Some(ref pth) => {
self.write_plain(format!("\nusing metrics ratcher: {}\n", pth.display()));
if_ok!(self.write_plain(format!("\nusing metrics ratcher: {}\n",
pth.display())));
match ratchet_pct {
None => (),
Some(pct) =>
self.write_plain(format!("with noise-tolerance forced to: {}%\n",
pct))
if_ok!(self.write_plain(format!("with noise-tolerance \
forced to: {}%\n",
pct)))
}
let (diff, ok) = self.metrics.ratchet(pth, ratchet_pct);
self.write_metric_diff(&diff);
if_ok!(self.write_metric_diff(&diff));
ok
}
};
let test_success = self.failed == 0u;
if !test_success {
self.write_failures();
if_ok!(self.write_failures());
}
let success = ratchet_success && test_success;
self.write_plain("\ntest result: ");
if_ok!(self.write_plain("\ntest result: "));
if success {
// There's no parallelism at this point so it's safe to use color
self.write_ok();
if_ok!(self.write_ok());
} else {
self.write_failed();
if_ok!(self.write_failed());
}
let s = format!(". {} passed; {} failed; {} ignored; {} measured\n\n",
self.passed, self.failed, self.ignored, self.measured);
self.write_plain(s);
return success;
if_ok!(self.write_plain(s));
return Ok(success);
}
}
@@ -611,15 +625,16 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> ~str {
// A simple console test runner
pub fn run_tests_console(opts: &TestOpts,
tests: ~[TestDescAndFn]) -> bool {
fn callback<T: Writer>(event: &TestEvent, st: &mut ConsoleTestState<T>) {
tests: ~[TestDescAndFn]) -> io::IoResult<bool> {
fn callback<T: Writer>(event: &TestEvent,
st: &mut ConsoleTestState<T>) -> io::IoResult<()> {
debug!("callback(event={:?})", event);
match (*event).clone() {
TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()),
TeWait(ref test, padding) => st.write_test_start(test, padding),
TeResult(test, result) => {
st.write_log(&test, &result);
st.write_result(&result);
if_ok!(st.write_log(&test, &result));
if_ok!(st.write_result(&result));
match result {
TrOk => st.passed += 1,
TrIgnored => st.ignored += 1,
@@ -643,10 +658,11 @@ fn callback<T: Writer>(event: &TestEvent, st: &mut ConsoleTestState<T>) {
st.failures.push(test);
}
}
Ok(())
}
}
}
let mut st = ConsoleTestState::new(opts, None::<StdWriter>);
let mut st = if_ok!(ConsoleTestState::new(opts, None::<StdWriter>));
fn len_if_padded(t: &TestDescAndFn) -> uint {
match t.testfn.padding() {
PadNone => 0u,
@@ -661,12 +677,13 @@ fn len_if_padded(t: &TestDescAndFn) -> uint {
},
None => {}
}
run_tests(opts, tests, |x| callback(&x, &mut st));
if_ok!(run_tests(opts, tests, |x| callback(&x, &mut st)));
match opts.save_metrics {
None => (),
Some(ref pth) => {
st.metrics.save(pth);
st.write_plain(format!("\nmetrics saved to: {}", pth.display()));
if_ok!(st.metrics.save(pth));
if_ok!(st.write_plain(format!("\nmetrics saved to: {}",
pth.display())));
}
}
return st.write_run_finish(&opts.ratchet_metrics, opts.ratchet_noise_percent);
@@ -703,7 +720,7 @@ fn should_sort_failures_before_printing_them() {
failures: ~[test_b, test_a]
};
st.write_failures();
st.write_failures().unwrap();
let s = match st.out {
Raw(ref m) => str::from_utf8(m.get_ref()).unwrap(),
Pretty(_) => unreachable!()
@@ -728,11 +745,11 @@ enum TestEvent {
fn run_tests(opts: &TestOpts,
tests: ~[TestDescAndFn],
callback: |e: TestEvent|) {
callback: |e: TestEvent| -> io::IoResult<()>) -> io::IoResult<()> {
let filtered_tests = filter_tests(opts, tests);
let filtered_descs = filtered_tests.map(|t| t.desc.clone());
callback(TeFiltered(filtered_descs));
if_ok!(callback(TeFiltered(filtered_descs)));
let (filtered_tests, filtered_benchs_and_metrics) =
filtered_tests.partition(|e| {
@@ -760,7 +777,7 @@ fn run_tests(opts: &TestOpts,
// We are doing one test at a time so we can print the name
// of the test before we run it. Useful for debugging tests
// that hang forever.
callback(TeWait(test.desc.clone(), test.testfn.padding()));
if_ok!(callback(TeWait(test.desc.clone(), test.testfn.padding())));
}
run_test(!opts.run_tests, test, ch.clone());
pending += 1;
@@ -768,20 +785,21 @@ fn run_tests(opts: &TestOpts,
let (desc, result) = p.recv();
if concurrency != 1 {
callback(TeWait(desc.clone(), PadNone));
if_ok!(callback(TeWait(desc.clone(), PadNone)));
}
callback(TeResult(desc, result));
if_ok!(callback(TeResult(desc, result)));
pending -= 1;
}
// All benchmarks run at the end, in serial.
// (this includes metric fns)
for b in filtered_benchs_and_metrics.move_iter() {
callback(TeWait(b.desc.clone(), b.testfn.padding()));
if_ok!(callback(TeWait(b.desc.clone(), b.testfn.padding())));
run_test(!opts.run_benchmarks, b, ch.clone());
let (test, result) = p.recv();
callback(TeResult(test, result));
if_ok!(callback(TeResult(test, result)));
}
Ok(())
}
fn get_concurrency() -> uint {
@@ -943,17 +961,22 @@ pub fn new() -> MetricMap {
}
/// Load MetricDiff from a file.
///
/// # Failure
///
/// This function will fail if the path does not exist or the path does not
/// contain a valid metric map.
pub fn load(p: &Path) -> MetricMap {
assert!(p.exists());
let mut f = File::open(p);
let mut f = File::open(p).unwrap();
let value = json::from_reader(&mut f as &mut io::Reader).unwrap();
let mut decoder = json::Decoder::new(value);
MetricMap(Decodable::decode(&mut decoder))
}
/// Write MetricDiff to a file.
pub fn save(&self, p: &Path) {
let mut file = File::create(p);
pub fn save(&self, p: &Path) -> io::IoResult<()> {
let mut file = if_ok!(File::create(p));
let MetricMap(ref map) = *self;
map.to_json().to_pretty_writer(&mut file)
}
@@ -1060,7 +1083,7 @@ pub fn ratchet(&self, p: &Path, pct: Option<f64>) -> (MetricDiff, bool) {
if ok {
debug!("rewriting file '{:?}' with updated metrics", p);
self.save(p);
self.save(p).unwrap();
}
return (diff, ok)
}
@@ -1462,7 +1485,7 @@ pub fn ratchet_test() {
m2.insert_metric("runtime", 1100.0, 2.0);
m2.insert_metric("throughput", 50.0, 2.0);
m1.save(&pth);
m1.save(&pth).unwrap();
// Ask for a ratchet that should fail to advance.
let (diff1, ok1) = m2.ratchet(&pth, None);
+8 -8
View File
@@ -766,14 +766,14 @@ fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
let mut buf = [0];
let c = match rdr.read(buf) {
Some(..) => buf[0] as char,
None => break
Ok(..) => buf[0] as char,
Err(..) => break
};
match c {
'%' => {
let ch = match rdr.read(buf) {
Some(..) => buf[0] as char,
None => break
Ok(..) => buf[0] as char,
Err(..) => break
};
match parse_type(s, pos, ch, &mut tm) {
Ok(next) => pos = next,
@@ -787,7 +787,7 @@ fn parse_type(s: &str, pos: uint, ch: char, tm: &mut Tm)
}
}
if pos == len && rdr.tell() as uint == format.len() {
if pos == len && rdr.tell().unwrap() == format.len() as u64 {
Ok(Tm {
tm_sec: tm.tm_sec,
tm_min: tm.tm_min,
@@ -1017,12 +1017,12 @@ fn parse_type(ch: char, tm: &Tm) -> ~str {
loop {
let mut b = [0];
let ch = match rdr.read(b) {
Some(..) => b[0],
None => break,
Ok(..) => b[0],
Err(..) => break,
};
match ch as char {
'%' => {
rdr.read(b);
rdr.read(b).unwrap();
let s = parse_type(b[0] as char, tm);
buf.push_all(s.as_bytes());
}
+13 -13
View File
@@ -102,8 +102,8 @@ fn encode_inner(s: &str, full_url: bool) -> ~str {
loop {
let mut buf = [0];
let ch = match rdr.read(buf) {
None => break,
Some(..) => buf[0] as char,
Err(..) => break,
Ok(..) => buf[0] as char,
};
match ch {
@@ -166,14 +166,14 @@ fn decode_inner(s: &str, full_url: bool) -> ~str {
loop {
let mut buf = [0];
let ch = match rdr.read(buf) {
None => break,
Some(..) => buf[0] as char
Err(..) => break,
Ok(..) => buf[0] as char
};
match ch {
'%' => {
let mut bytes = [0, 0];
match rdr.read(bytes) {
Some(2) => {}
Ok(2) => {}
_ => fail!() // FIXME: malformed url?
}
let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8 as char;
@@ -228,8 +228,8 @@ fn encode_plus(s: &str) -> ~str {
loop {
let mut buf = [0];
let ch = match rdr.read(buf) {
Some(..) => buf[0] as char,
None => break,
Ok(..) => buf[0] as char,
Err(..) => break,
};
match ch {
'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '-' => {
@@ -282,8 +282,8 @@ pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> {
loop {
let mut buf = [0];
let ch = match rdr.read(buf) {
Some(..) => buf[0] as char,
None => break,
Ok(..) => buf[0] as char,
Err(..) => break,
};
match ch {
'&' | ';' => {
@@ -307,7 +307,7 @@ pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> {
'%' => {
let mut bytes = [0, 0];
match rdr.read(bytes) {
Some(2) => {}
Ok(2) => {}
_ => fail!() // FIXME: malformed?
}
uint::parse_bytes(bytes, 16u).unwrap() as u8 as char
@@ -347,12 +347,12 @@ fn split_char_first(s: &str, c: char) -> (~str, ~str) {
loop {
let mut buf = [0];
let ch = match rdr.read(buf) {
Some(..) => buf[0] as char,
None => break,
Ok(..) => buf[0] as char,
Err(..) => break,
};
if ch == c {
// found a match, adjust markers
index = (rdr.tell() as uint) - 1;
index = (rdr.tell().unwrap() as uint) - 1;
mat = 1;
break;
}
+1 -1
View File
@@ -821,7 +821,7 @@ pub fn uuid_to_str(bh: &mut BenchHarness) {
pub fn parse_str(bh: &mut BenchHarness) {
let s = "urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4";
bh.iter(|| {
Uuid::parse_string(s);
Uuid::parse_string(s).unwrap();
})
}
}
+12 -11
View File
@@ -172,20 +172,19 @@ pub fn cache(&mut self,
}
// FIXME #4330: This should have &mut self and should set self.db_dirty to false.
fn save(&self) {
fn save(&self) -> io::IoResult<()> {
let mut f = File::create(&self.db_filename);
self.db_cache.to_json().to_pretty_writer(&mut f);
self.db_cache.to_json().to_pretty_writer(&mut f)
}
fn load(&mut self) {
assert!(!self.db_dirty);
assert!(self.db_filename.exists());
match io::result(|| File::open(&self.db_filename)) {
match File::open(&self.db_filename) {
Err(e) => fail!("Couldn't load workcache database {}: {}",
self.db_filename.display(),
e.desc),
Ok(r) => {
let mut stream = r.unwrap();
e),
Ok(mut stream) => {
match json::from_reader(&mut stream) {
Err(e) => fail!("Couldn't parse workcache database (from file {}): {}",
self.db_filename.display(), e.to_str()),
@@ -203,7 +202,8 @@ fn load(&mut self) {
impl Drop for Database {
fn drop(&mut self) {
if self.db_dirty {
self.save();
// FIXME: is failing the right thing to do here
self.save().unwrap();
}
}
}
@@ -473,13 +473,13 @@ fn test() {
fn make_path(filename: ~str) -> Path {
let pth = os::self_exe_path().expect("workcache::test failed").with_filename(filename);
if pth.exists() {
fs::unlink(&pth);
fs::unlink(&pth).unwrap();
}
return pth;
}
let pth = make_path(~"foo.c");
File::create(&pth).write(bytes!("int main() { return 0; }"));
File::create(&pth).write(bytes!("int main() { return 0; }")).unwrap();
let db_path = make_path(~"db.json");
@@ -491,7 +491,8 @@ fn make_path(filename: ~str) -> Path {
let subcx = cx.clone();
let pth = pth.clone();
let file_content = from_utf8_owned(File::open(&pth).read_to_end()).unwrap();
let contents = File::open(&pth).read_to_end().unwrap();
let file_content = from_utf8_owned(contents).unwrap();
// FIXME (#9639): This needs to handle non-utf8 paths
prep.declare_input("file", pth.as_str().unwrap(), file_content);
@@ -500,7 +501,7 @@ fn make_path(filename: ~str) -> Path {
// FIXME (#9639): This needs to handle non-utf8 paths
run::process_status("gcc", [pth.as_str().unwrap().to_owned(),
~"-o",
out.as_str().unwrap().to_owned()]);
out.as_str().unwrap().to_owned()]).unwrap();
let _proof_of_concept = subcx.prep("subfn");
// Could run sub-rules inside here.
+1 -2
View File
@@ -29,7 +29,6 @@
#[license = "MIT/ASL2"];
use std::{os, path};
use std::io;
use std::io::fs;
use std::path::is_sep;
@@ -153,7 +152,7 @@ fn next(&mut self) -> Option<Path> {
}
fn list_dir_sorted(path: &Path) -> ~[Path] {
match io::result(|| fs::readdir(path)) {
match fs::readdir(path) {
Ok(mut children) => {
children.sort_by(|p1, p2| p2.filename().cmp(&p1.filename()));
children
+3 -2
View File
@@ -56,16 +56,17 @@ pub fn dumb_println(args: &fmt::Arguments) {
struct Stderr;
impl io::Writer for Stderr {
fn write(&mut self, data: &[u8]) {
fn write(&mut self, data: &[u8]) -> io::IoResult<()> {
unsafe {
libc::write(libc::STDERR_FILENO,
data.as_ptr() as *libc::c_void,
data.len() as libc::size_t);
}
Ok(()) // just ignore the result
}
}
let mut w = Stderr;
fmt::writeln(&mut w as &mut io::Writer, args);
let _ = fmt::writeln(&mut w as &mut io::Writer, args);
}
pub fn abort(msg: &str) -> ! {
+1 -1
View File
@@ -23,7 +23,7 @@
static mut TASK_LOCK: Mutex = MUTEX_INIT;
pub fn increment() {
unsafe { TASK_COUNT.fetch_add(1, atomics::SeqCst); }
let _ = unsafe { TASK_COUNT.fetch_add(1, atomics::SeqCst) };
}
pub fn decrement() {
+14 -15
View File
@@ -111,17 +111,14 @@ pub fn fd(&self) -> fd_t { self.fd }
}
impl io::Reader for FileDesc {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
match self.inner_read(buf) { Ok(n) => Some(n), Err(..) => None }
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
self.inner_read(buf)
}
}
impl io::Writer for FileDesc {
fn write(&mut self, buf: &[u8]) {
match self.inner_write(buf) {
Ok(()) => {}
Err(e) => { io::io_error::cond.raise(e); }
}
fn write(&mut self, buf: &[u8]) -> io::IoResult<()> {
self.inner_write(buf)
}
}
@@ -425,7 +422,7 @@ fn truncate(&mut self, offset: i64) -> Result<(), IoError> {
impl Drop for CFile {
fn drop(&mut self) {
unsafe { libc::fclose(self.file); }
unsafe { let _ = libc::fclose(self.file); }
}
}
@@ -515,7 +512,7 @@ unsafe fn get_list(p: &CString) -> IoResult<~[Path]> {
paths.push(Path::new(cstr));
entry_ptr = readdir(dir_ptr);
}
closedir(dir_ptr);
assert_eq!(closedir(dir_ptr), 0);
Ok(paths)
} else {
Err(super::last_error())
@@ -564,7 +561,7 @@ unsafe fn get_list(p: &CString) -> IoResult<~[Path]> {
}
more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE);
}
FindClose(find_handle);
assert!(FindClose(find_handle) != 0);
free(wfd_ptr as *mut c_void);
Ok(paths)
} else {
@@ -686,7 +683,9 @@ fn os_readlink(p: &CString) -> IoResult<Path> {
ptr::mut_null())
})
};
if handle == ptr::mut_null() { return Err(super::last_error()) }
if handle as int == libc::INVALID_HANDLE_VALUE as int {
return Err(super::last_error())
}
let ret = fill_utf16_buf_and_decode(|buf, sz| {
unsafe {
libc::GetFinalPathNameByHandleW(handle, buf as *u16, sz,
@@ -697,7 +696,7 @@ fn os_readlink(p: &CString) -> IoResult<Path> {
Some(s) => Ok(Path::new(s)),
None => Err(super::last_error()),
};
unsafe { libc::CloseHandle(handle) };
assert!(unsafe { libc::CloseHandle(handle) } != 0);
return ret;
}
@@ -935,7 +934,7 @@ fn test_file_desc() {
let mut reader = FileDesc::new(input, true);
let mut writer = FileDesc::new(out, true);
writer.inner_write(bytes!("test"));
writer.inner_write(bytes!("test")).unwrap();
let mut buf = [0u8, ..4];
match reader.inner_read(buf) {
Ok(4) => {
@@ -960,9 +959,9 @@ fn test_cfile() {
assert!(!f.is_null());
let mut file = CFile::new(f);
file.write(bytes!("test"));
file.write(bytes!("test")).unwrap();
let mut buf = [0u8, ..4];
file.seek(0, io::SeekSet);
let _ = file.seek(0, io::SeekSet).unwrap();
match file.read(buf) {
Ok(4) => {
assert_eq!(buf[0], 't' as u8);
+2 -2
View File
@@ -112,8 +112,8 @@ fn setsockopt<T>(fd: sock_t, opt: libc::c_int, val: libc::c_int,
}
}
#[cfg(windows)] unsafe fn close(sock: sock_t) { libc::closesocket(sock); }
#[cfg(unix)] unsafe fn close(sock: sock_t) { libc::close(sock); }
#[cfg(windows)] unsafe fn close(sock: sock_t) { let _ = libc::closesocket(sock); }
#[cfg(unix)] unsafe fn close(sock: sock_t) { let _ = libc::close(sock); }
fn sockname(fd: sock_t,
f: extern "system" unsafe fn(sock_t, *mut libc::sockaddr,
+22 -23
View File
@@ -102,9 +102,9 @@ fn get_io(io: &[p::StdioContainer],
cwd.as_ref(), in_fd, out_fd, err_fd);
unsafe {
for pipe in in_pipe.iter() { libc::close(pipe.input); }
for pipe in out_pipe.iter() { libc::close(pipe.out); }
for pipe in err_pipe.iter() { libc::close(pipe.out); }
for pipe in in_pipe.iter() { let _ = libc::close(pipe.input); }
for pipe in out_pipe.iter() { let _ = libc::close(pipe.out); }
for pipe in err_pipe.iter() { let _ = libc::close(pipe.out); }
}
match res {
@@ -149,9 +149,8 @@ fn kill(&mut self, signum: int) -> Result<(), io::IoError> {
unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> {
match signal {
io::process::PleaseExitSignal | io::process::MustDieSignal => {
libc::funcs::extra::kernel32::TerminateProcess(
cast::transmute(pid), 1);
Ok(())
let ret = libc::TerminateProcess(pid as libc::HANDLE, 1);
super::mkerr_winbool(ret)
}
_ => Err(io::IoError {
kind: io::OtherIoError,
@@ -163,8 +162,8 @@ unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> {
#[cfg(not(windows))]
unsafe fn killpid(pid: pid_t, signal: int) -> Result<(), io::IoError> {
libc::funcs::posix88::signal::kill(pid, signal as c_int);
Ok(())
let r = libc::funcs::posix88::signal::kill(pid, signal as c_int);
super::mkerr_libc(r)
}
}
}
@@ -255,9 +254,9 @@ fn spawn_process_os(prog: &str, args: &[~str],
})
});
CloseHandle(si.hStdInput);
CloseHandle(si.hStdOutput);
CloseHandle(si.hStdError);
assert!(CloseHandle(si.hStdInput) != 0);
assert!(CloseHandle(si.hStdOutput) != 0);
assert!(CloseHandle(si.hStdError) != 0);
match create_err {
Some(err) => return Err(err),
@@ -269,7 +268,7 @@ fn spawn_process_os(prog: &str, args: &[~str],
// able to close it later. We don't close the process handle however
// because std::we want the process id to stay valid at least until the
// calling code closes the process handle.
CloseHandle(pi.hThread);
assert!(CloseHandle(pi.hThread) != 0);
Ok(SpawnProcessResult {
pid: pi.dwProcessId as pid_t,
@@ -445,24 +444,24 @@ unsafe fn set_cloexec(fd: c_int) {
rustrt::rust_unset_sigprocmask();
if in_fd == -1 {
libc::close(libc::STDIN_FILENO);
let _ = libc::close(libc::STDIN_FILENO);
} else if retry(|| dup2(in_fd, 0)) == -1 {
fail!("failure in dup2(in_fd, 0): {}", os::last_os_error());
}
if out_fd == -1 {
libc::close(libc::STDOUT_FILENO);
let _ = libc::close(libc::STDOUT_FILENO);
} else if retry(|| dup2(out_fd, 1)) == -1 {
fail!("failure in dup2(out_fd, 1): {}", os::last_os_error());
}
if err_fd == -1 {
libc::close(libc::STDERR_FILENO);
let _ = libc::close(libc::STDERR_FILENO);
} else if retry(|| dup2(err_fd, 2)) == -1 {
fail!("failure in dup3(err_fd, 2): {}", os::last_os_error());
}
// close all other fds
for fd in range(3, getdtablesize()).rev() {
if fd != output.fd() {
close(fd as c_int);
let _ = close(fd as c_int);
}
}
@@ -478,7 +477,7 @@ unsafe fn set_cloexec(fd: c_int) {
}
});
with_argv(prog, args, |argv| {
execvp(*argv, argv);
let _ = execvp(*argv, argv);
let errno = os::errno();
let bytes = [
(errno << 24) as u8,
@@ -576,9 +575,9 @@ fn with_dirp<T>(d: Option<&Path>, cb: |*libc::c_char| -> T) -> T {
#[cfg(windows)]
fn free_handle(handle: *()) {
unsafe {
libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
}
assert!(unsafe {
libc::CloseHandle(cast::transmute(handle)) != 0
})
}
#[cfg(unix)]
@@ -629,15 +628,15 @@ fn waitpid_os(pid: pid_t) -> p::ProcessExit {
loop {
let mut status = 0;
if GetExitCodeProcess(process, &mut status) == FALSE {
CloseHandle(process);
assert!(CloseHandle(process) != 0);
fail!("failure in GetExitCodeProcess: {}", os::last_os_error());
}
if status != STILL_ACTIVE {
CloseHandle(process);
assert!(CloseHandle(process) != 0);
return p::ExitStatus(status as int);
}
if WaitForSingleObject(process, INFINITE) == WAIT_FAILED {
CloseHandle(process);
assert!(CloseHandle(process) != 0);
fail!("failure in WaitForSingleObject: {}", os::last_os_error());
}
}
+2 -2
View File
@@ -126,11 +126,11 @@ pub fn new() -> (HANDLE, HANDLE) {
}
pub fn signal(handle: HANDLE) {
unsafe { SetEvent(handle); }
assert!(unsafe { SetEvent(handle) != 0 });
}
pub fn close(handle: HANDLE) {
unsafe { CloseHandle(handle); }
assert!(unsafe { CloseHandle(handle) != 0 });
}
extern "system" {
+3 -2
View File
@@ -187,7 +187,7 @@ fn signal(active: &mut ~[~Inner], dead: &mut HashMap<uint, ~Inner>) {
// drain the file descriptor
let mut buf = [0];
fd.inner_read(buf).unwrap();
assert_eq!(fd.inner_read(buf).unwrap(), 1);
}
-1 if os::errno() == libc::EINTR as int => {}
@@ -216,7 +216,8 @@ pub fn new() -> IoResult<Timer> {
}
pub fn sleep(ms: u64) {
unsafe { libc::usleep((ms * 1000) as libc::c_uint); }
// FIXME: this can fail because of EINTR, what do do?
let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
}
fn inner(&mut self) -> ~Inner {
+4 -3
View File
@@ -96,7 +96,7 @@ fn del(efd: libc::c_int, fd: libc::c_int) {
if fd == input {
let mut buf = [0, ..1];
// drain the input file descriptor of its input
FileDesc::new(fd, false).inner_read(buf).unwrap();
let _ = FileDesc::new(fd, false).inner_read(buf).unwrap();
incoming = true;
} else {
let mut bits = [0, ..8];
@@ -104,7 +104,7 @@ fn del(efd: libc::c_int, fd: libc::c_int) {
//
// FIXME: should this perform a send() this number of
// times?
FileDesc::new(fd, false).inner_read(bits).unwrap();
let _ = FileDesc::new(fd, false).inner_read(bits).unwrap();
let remove = {
match map.find(&fd).expect("fd unregistered") {
&(ref c, oneshot) => !c.try_send(()) || oneshot
@@ -166,7 +166,8 @@ pub fn new() -> IoResult<Timer> {
}
pub fn sleep(ms: u64) {
unsafe { libc::usleep((ms * 1000) as libc::c_uint); }
// FIXME: this can fail because of EINTR, what do do?
let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) };
}
fn remove(&mut self) {
+6 -6
View File
@@ -62,8 +62,8 @@ fn helper(input: libc::HANDLE, messages: Port<Req>) {
c.send(());
match objs.iter().position(|&o| o == obj) {
Some(i) => {
objs.remove(i);
chans.remove(i - 1);
drop(objs.remove(i));
drop(chans.remove(i - 1));
}
None => {}
}
@@ -83,8 +83,8 @@ fn helper(input: libc::HANDLE, messages: Port<Req>) {
}
};
if remove {
objs.remove(idx as uint);
chans.remove(idx as uint - 1);
drop(objs.remove(idx as uint));
drop(chans.remove(idx as uint - 1));
}
}
}
@@ -133,7 +133,7 @@ fn sleep(&mut self, msecs: u64) {
ptr::mut_null(), 0)
}, 1);
unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE); }
let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) };
}
fn oneshot(&mut self, msecs: u64) -> Port<()> {
@@ -173,7 +173,7 @@ fn period(&mut self, msecs: u64) -> Port<()> {
impl Drop for Timer {
fn drop(&mut self) {
self.remove();
unsafe { libc::CloseHandle(self.obj); }
assert!(unsafe { libc::CloseHandle(self.obj) != 0 });
}
}
+3 -1
View File
@@ -21,6 +21,7 @@
#[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://static.rust-lang.org/doc/master")];
#[deny(unused_result, unused_must_use)];
// NB this crate explicitly does *not* allow glob imports, please seriously
// consider whether they're needed before adding that feature here (the
@@ -61,9 +62,10 @@ pub fn start(argc: int, argv: **u8, main: proc()) -> int {
rt::init(argc, argv);
let mut exit_code = None;
let mut main = Some(main);
task::new((my_stack_bottom, my_stack_top)).run(|| {
let t = task::new((my_stack_bottom, my_stack_top)).run(|| {
exit_code = Some(run(main.take_unwrap()));
});
drop(t);
unsafe { rt::cleanup(); }
// If the exit code wasn't set, then the task block must have failed.
return exit_code.unwrap_or(rt::DEFAULT_ERROR_CODE);
+2 -1
View File
@@ -103,7 +103,8 @@ pub fn spawn_opts(opts: TaskOpts, f: proc()) {
let mut f = Some(f);
let mut task = task;
task.put_runtime(ops as ~rt::Runtime);
task.run(|| { f.take_unwrap()() });
let t = task.run(|| { f.take_unwrap()() });
drop(t);
bookkeeping::decrement();
})
}
+16 -13
View File
@@ -17,6 +17,7 @@
use std::cast;
use std::io::fs;
use std::io;
use std::libc;
use std::os;
use std::run::{ProcessOptions, Process, ProcessOutput};
@@ -50,9 +51,8 @@ fn run_ar(sess: Session, args: &str, cwd: Option<&Path>,
Some(p) => { debug!("inside {}", p.display()); }
None => {}
}
let mut opt_prog = Process::new(ar, args.as_slice(), opts);
match opt_prog {
Some(ref mut prog) => {
match Process::new(ar, args.as_slice(), opts) {
Ok(mut prog) => {
let o = prog.finish_with_output();
if !o.status.success() {
sess.err(format!("{} {} failed with: {}", ar, args.connect(" "),
@@ -63,8 +63,8 @@ fn run_ar(sess: Session, args: &str, cwd: Option<&Path>,
}
o
},
None => {
sess.err(format!("could not exec `{}`", ar));
Err(e) => {
sess.err(format!("could not exec `{}`: {}", ar, e));
sess.abort_if_errors();
fail!("rustc::back::archive::run_ar() should not reach this point");
}
@@ -94,7 +94,7 @@ pub fn read(&self, file: &str) -> ~[u8] {
let archive = os::make_absolute(&self.dst);
run_ar(self.sess, "x", Some(loc.path()), [&archive,
&Path::new(file)]);
fs::File::open(&loc.path().join(file)).read_to_end()
fs::File::open(&loc.path().join(file)).read_to_end().unwrap()
} else {
run_ar(self.sess, "p", None, [&self.dst, &Path::new(file)]).output
}
@@ -102,9 +102,9 @@ pub fn read(&self, file: &str) -> ~[u8] {
/// Adds all of the contents of a native library to this archive. This will
/// search in the relevant locations for a library named `name`.
pub fn add_native_library(&mut self, name: &str) {
pub fn add_native_library(&mut self, name: &str) -> io::IoResult<()> {
let location = self.find_library(name);
self.add_archive(&location, name, []);
self.add_archive(&location, name, [])
}
/// Adds all of the contents of the rlib at the specified path to this
@@ -112,14 +112,15 @@ pub fn add_native_library(&mut self, name: &str) {
///
/// This ignores adding the bytecode from the rlib, and if LTO is enabled
/// then the object file also isn't added.
pub fn add_rlib(&mut self, rlib: &Path, name: &str, lto: bool) {
pub fn add_rlib(&mut self, rlib: &Path, name: &str,
lto: bool) -> io::IoResult<()> {
let object = format!("{}.o", name);
let bytecode = format!("{}.bc", name);
let mut ignore = ~[METADATA_FILENAME, bytecode.as_slice()];
if lto {
ignore.push(object.as_slice());
}
self.add_archive(rlib, name, ignore);
self.add_archive(rlib, name, ignore)
}
/// Adds an arbitrary file to this archive
@@ -144,7 +145,8 @@ pub fn files(&self) -> ~[~str] {
str::from_utf8(output.output).unwrap().lines().map(|s| s.to_owned()).collect()
}
fn add_archive(&mut self, archive: &Path, name: &str, skip: &[&str]) {
fn add_archive(&mut self, archive: &Path, name: &str,
skip: &[&str]) -> io::IoResult<()> {
let loc = TempDir::new("rsar").unwrap();
// First, extract the contents of the archive to a temporary directory
@@ -159,7 +161,7 @@ fn add_archive(&mut self, archive: &Path, name: &str, skip: &[&str]) {
// We skip any files explicitly desired for skipping, and we also skip
// all SYMDEF files as these are just magical placeholders which get
// re-created when we make a new archive anyway.
let files = fs::readdir(loc.path());
let files = if_ok!(fs::readdir(loc.path()));
let mut inputs = ~[];
for file in files.iter() {
let filename = file.filename_str().unwrap();
@@ -168,7 +170,7 @@ fn add_archive(&mut self, archive: &Path, name: &str, skip: &[&str]) {
let filename = format!("r-{}-{}", name, filename);
let new_filename = file.with_filename(filename);
fs::rename(file, &new_filename);
if_ok!(fs::rename(file, &new_filename));
inputs.push(new_filename);
}
@@ -176,6 +178,7 @@ fn add_archive(&mut self, archive: &Path, name: &str, skip: &[&str]) {
let mut args = ~[&self.dst];
args.extend(&mut inputs.iter());
run_ar(self.sess, "r", None, args.as_slice());
Ok(())
}
fn find_library(&self, name: &str) -> Path {
+53 -33
View File
@@ -100,7 +100,6 @@ pub mod write {
use util::common::time;
use std::c_str::ToCStr;
use std::io;
use std::libc::{c_uint, c_int};
use std::path::Path;
use std::run;
@@ -297,12 +296,8 @@ pub fn run_assembler(sess: Session, assembly: &Path, object: &Path) {
assembly.as_str().unwrap().to_owned()];
debug!("{} '{}'", cc, args.connect("' '"));
let opt_prog = {
let _guard = io::ignore_io_error();
run::process_output(cc, args)
};
match opt_prog {
Some(prog) => {
match run::process_output(cc, args) {
Ok(prog) => {
if !prog.status.success() {
sess.err(format!("linking with `{}` failed: {}", cc, prog.status));
sess.note(format!("{} arguments: '{}'", cc, args.connect("' '")));
@@ -310,8 +305,8 @@ pub fn run_assembler(sess: Session, assembly: &Path, object: &Path) {
sess.abort_if_errors();
}
},
None => {
sess.err(format!("could not exec the linker `{}`", cc));
Err(e) => {
sess.err(format!("could not exec the linker `{}`: {}", cc, e));
sess.abort_if_errors();
}
}
@@ -768,6 +763,15 @@ fn get_system_tool(sess: Session, tool: &str) -> ~str {
}
}
fn remove(sess: Session, path: &Path) {
match fs::unlink(path) {
Ok(..) => {}
Err(e) => {
sess.err(format!("failed to remove {}: {}", path.display(), e));
}
}
}
/// Perform the linkage portion of the compilation phase. This will generate all
/// of the requested outputs for this compilation session.
pub fn link_binary(sess: Session,
@@ -785,17 +789,15 @@ pub fn link_binary(sess: Session,
// Remove the temporary object file and metadata if we aren't saving temps
if !sess.opts.save_temps {
fs::unlink(obj_filename);
fs::unlink(&obj_filename.with_extension("metadata.o"));
remove(sess, obj_filename);
remove(sess, &obj_filename.with_extension("metadata.o"));
}
out_filenames
}
fn is_writeable(p: &Path) -> bool {
use std::io;
match io::result(|| p.stat()) {
match p.stat() {
Err(..) => true,
Ok(m) => m.perm & io::UserWrite == io::UserWrite
}
@@ -884,7 +886,7 @@ fn link_rlib(sess: Session,
for &(ref l, kind) in used_libraries.get().iter() {
match kind {
cstore::NativeStatic => {
a.add_native_library(l.as_slice());
a.add_native_library(l.as_slice()).unwrap();
}
cstore::NativeFramework | cstore::NativeUnknown => {}
}
@@ -919,16 +921,23 @@ fn link_rlib(sess: Session,
// the same filename for metadata (stomping over one another)
let tmpdir = TempDir::new("rustc").expect("needs a temp dir");
let metadata = tmpdir.path().join(METADATA_FILENAME);
fs::File::create(&metadata).write(trans.metadata);
match fs::File::create(&metadata).write(trans.metadata) {
Ok(..) => {}
Err(e) => {
sess.err(format!("failed to write {}: {}",
metadata.display(), e));
sess.abort_if_errors();
}
}
a.add_file(&metadata, false);
fs::unlink(&metadata);
remove(sess, &metadata);
// For LTO purposes, the bytecode of this library is also inserted
// into the archive.
let bc = obj_filename.with_extension("bc");
a.add_file(&bc, false);
if !sess.opts.save_temps {
fs::unlink(&bc);
remove(sess, &bc);
}
// After adding all files to the archive, we need to update the
@@ -959,7 +968,7 @@ fn link_rlib(sess: Session,
// metadata file).
fn link_staticlib(sess: Session, obj_filename: &Path, out_filename: &Path) {
let mut a = link_rlib(sess, None, obj_filename, out_filename);
a.add_native_library("morestack");
a.add_native_library("morestack").unwrap();
let crates = sess.cstore.get_used_crates(cstore::RequireStatic);
for &(cnum, ref path) in crates.iter() {
@@ -970,7 +979,7 @@ fn link_staticlib(sess: Session, obj_filename: &Path, out_filename: &Path) {
continue
}
};
a.add_rlib(&p, name, sess.lto());
a.add_rlib(&p, name, sess.lto()).unwrap();
let native_libs = csearch::get_native_libraries(sess.cstore, cnum);
for &(kind, ref lib) in native_libs.iter() {
let name = match kind {
@@ -1004,14 +1013,10 @@ fn link_natively(sess: Session, dylib: bool, obj_filename: &Path,
// Invoke the system linker
debug!("{} {}", cc_prog, cc_args.connect(" "));
let opt_prog = {
let _guard = io::ignore_io_error();
time(sess.time_passes(), "running linker", (), |()|
run::process_output(cc_prog, cc_args))
};
match opt_prog {
Some(prog) => {
let prog = time(sess.time_passes(), "running linker", (), |()|
run::process_output(cc_prog, cc_args));
match prog {
Ok(prog) => {
if !prog.status.success() {
sess.err(format!("linking with `{}` failed: {}", cc_prog, prog.status));
sess.note(format!("{} arguments: '{}'", cc_prog, cc_args.connect("' '")));
@@ -1019,8 +1024,8 @@ fn link_natively(sess: Session, dylib: bool, obj_filename: &Path,
sess.abort_if_errors();
}
},
None => {
sess.err(format!("could not exec the linker `{}`", cc_prog));
Err(e) => {
sess.err(format!("could not exec the linker `{}`: {}", cc_prog, e));
sess.abort_if_errors();
}
}
@@ -1030,8 +1035,14 @@ fn link_natively(sess: Session, dylib: bool, obj_filename: &Path,
// the symbols
if sess.targ_cfg.os == abi::OsMacos && sess.opts.debuginfo {
// FIXME (#9639): This needs to handle non-utf8 paths
run::process_status("dsymutil",
[out_filename.as_str().unwrap().to_owned()]);
match run::process_status("dsymutil",
[out_filename.as_str().unwrap().to_owned()]) {
Ok(..) => {}
Err(e) => {
sess.err(format!("failed to run dsymutil: {}", e));
sess.abort_if_errors();
}
}
}
}
@@ -1225,7 +1236,16 @@ fn unlib(config: @session::Config, stem: &str) -> ~str {
time(sess.time_passes(), format!("altering {}.rlib", name),
(), |()| {
let dst = tmpdir.join(cratepath.filename().unwrap());
fs::copy(&cratepath, &dst);
match fs::copy(&cratepath, &dst) {
Ok(..) => {}
Err(e) => {
sess.err(format!("failed to copy {} to {}: {}",
cratepath.display(),
dst.display(),
e));
sess.abort_if_errors();
}
}
let dst_str = dst.as_str().unwrap().to_owned();
let mut archive = Archive::open(sess, dst);
archive.remove_file(format!("{}.o", name));
+50 -39
View File
@@ -399,7 +399,7 @@ pub fn phase_5_run_llvm_passes(sess: Session,
// Remove assembly source, unless --save-temps was specified
if !sess.opts.save_temps {
fs::unlink(&asm_filename);
fs::unlink(&asm_filename).unwrap();
}
} else {
time(sess.time_passes(), "LLVM passes", (), |_|
@@ -455,33 +455,39 @@ pub fn stop_after_phase_5(sess: Session) -> bool {
return false;
}
fn write_out_deps(sess: Session, input: &Input, outputs: &OutputFilenames, crate: &ast::Crate)
fn write_out_deps(sess: Session, input: &Input, outputs: &OutputFilenames,
crate: &ast::Crate) -> io::IoResult<()>
{
let lm = link::build_link_meta(sess, crate.attrs, &outputs.obj_filename,
&mut ::util::sha2::Sha256::new());
&mut ::util::sha2::Sha256::new());
let sess_outputs = sess.outputs.borrow();
let out_filenames = sess_outputs.get().iter()
.map(|&output| link::filename_for_input(&sess, output, &lm, &outputs.out_filename))
.map(|&output| link::filename_for_input(&sess, output, &lm,
&outputs.out_filename))
.to_owned_vec();
// Write out dependency rules to the dep-info file if requested with --dep-info
// Write out dependency rules to the dep-info file if requested with
// --dep-info
let deps_filename = match sess.opts.write_dependency_info {
// Use filename from --dep-file argument if given
(true, Some(ref filename)) => filename.clone(),
// Use default filename: crate source filename with extension replaced by ".d"
// Use default filename: crate source filename with extension replaced
// by ".d"
(true, None) => match *input {
FileInput(ref input_path) => {
let filestem = input_path.filestem().expect("input file must have stem");
let filename = out_filenames[0].dir_path().join(filestem).with_extension("d");
filename
let filestem = input_path.filestem().expect("input file must \
have stem");
let filename = out_filenames[0].dir_path().join(filestem);
filename.with_extension("d")
},
StrInput(..) => {
sess.warn("can not write --dep-info without a filename when compiling stdin.");
return;
sess.warn("can not write --dep-info without a filename \
when compiling stdin.");
return Ok(());
},
},
_ => return,
_ => return Ok(()),
};
// Build a list of files used to compile the output and
@@ -499,11 +505,12 @@ fn write_out_deps(sess: Session, input: &Input, outputs: &OutputFilenames, crate
})
.collect()
};
let mut file = io::File::create(&deps_filename);
let mut file = if_ok!(io::File::create(&deps_filename));
for path in out_filenames.iter() {
write!(&mut file as &mut Writer,
"{}: {}\n\n", path.display(), files.connect(" "));
if_ok!(write!(&mut file as &mut Writer,
"{}: {}\n\n", path.display(), files.connect(" ")));
}
Ok(())
}
pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input,
@@ -521,7 +528,7 @@ pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input,
let outputs = build_output_filenames(input, outdir, output,
expanded_crate.attrs, sess);
write_out_deps(sess, input, outputs, &expanded_crate);
write_out_deps(sess, input, outputs, &expanded_crate).unwrap();
if stop_after_phase_2(sess) { return; }
@@ -541,32 +548,33 @@ struct IdentifiedAnnotation {
}
impl pprust::PpAnn for IdentifiedAnnotation {
fn pre(&self, node: pprust::AnnNode) {
fn pre(&self, node: pprust::AnnNode) -> io::IoResult<()> {
match node {
pprust::NodeExpr(s, _) => pprust::popen(s),
_ => ()
_ => Ok(())
}
}
fn post(&self, node: pprust::AnnNode) {
fn post(&self, node: pprust::AnnNode) -> io::IoResult<()> {
match node {
pprust::NodeItem(s, item) => {
pp::space(&mut s.s);
pprust::synth_comment(s, item.id.to_str());
if_ok!(pp::space(&mut s.s));
if_ok!(pprust::synth_comment(s, item.id.to_str()));
}
pprust::NodeBlock(s, blk) => {
pp::space(&mut s.s);
pprust::synth_comment(s, ~"block " + blk.id.to_str());
if_ok!(pp::space(&mut s.s));
if_ok!(pprust::synth_comment(s, ~"block " + blk.id.to_str()));
}
pprust::NodeExpr(s, expr) => {
pp::space(&mut s.s);
pprust::synth_comment(s, expr.id.to_str());
pprust::pclose(s);
if_ok!(pp::space(&mut s.s));
if_ok!(pprust::synth_comment(s, expr.id.to_str()));
if_ok!(pprust::pclose(s));
}
pprust::NodePat(s, pat) => {
pp::space(&mut s.s);
pprust::synth_comment(s, ~"pat " + pat.id.to_str());
if_ok!(pp::space(&mut s.s));
if_ok!(pprust::synth_comment(s, ~"pat " + pat.id.to_str()));
}
}
Ok(())
}
}
@@ -575,24 +583,26 @@ struct TypedAnnotation {
}
impl pprust::PpAnn for TypedAnnotation {
fn pre(&self, node: pprust::AnnNode) {
fn pre(&self, node: pprust::AnnNode) -> io::IoResult<()> {
match node {
pprust::NodeExpr(s, _) => pprust::popen(s),
_ => ()
_ => Ok(())
}
}
fn post(&self, node: pprust::AnnNode) {
fn post(&self, node: pprust::AnnNode) -> io::IoResult<()> {
let tcx = self.analysis.ty_cx;
match node {
pprust::NodeExpr(s, expr) => {
pp::space(&mut s.s);
pp::word(&mut s.s, "as");
pp::space(&mut s.s);
pp::word(&mut s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
pprust::pclose(s);
if_ok!(pp::space(&mut s.s));
if_ok!(pp::word(&mut s.s, "as"));
if_ok!(pp::space(&mut s.s));
if_ok!(pp::word(&mut s.s,
ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr))));
if_ok!(pprust::pclose(s));
}
_ => ()
}
Ok(())
}
}
@@ -638,7 +648,7 @@ pub fn pretty_print_input(sess: Session,
&mut rdr,
~stdout as ~io::Writer,
annotation,
is_expanded);
is_expanded).unwrap();
}
pub fn get_os(triple: &str) -> Option<abi::Os> {
@@ -1167,10 +1177,11 @@ pub fn early_error(emitter: &diagnostic::Emitter, msg: &str) -> ! {
fail!(diagnostic::FatalError);
}
pub fn list_metadata(sess: Session, path: &Path, out: &mut io::Writer) {
pub fn list_metadata(sess: Session, path: &Path,
out: &mut io::Writer) -> io::IoResult<()> {
metadata::loader::list_file_metadata(
token::get_ident_interner(),
session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
session::sess_os_to_meta_os(sess.targ_cfg.os), path, out)
}
#[cfg(test)]
+8 -3
View File
@@ -54,6 +54,11 @@
use syntax::diagnostic;
use syntax::parse;
#[cfg(stage0)]
macro_rules! if_ok (
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
)
pub mod middle {
pub mod trans;
pub mod ty;
@@ -236,8 +241,8 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) {
1u => {
let ifile = matches.free[0].as_slice();
if ifile == "-" {
let src =
str::from_utf8_owned(io::stdin().read_to_end()).unwrap();
let contents = io::stdin().read_to_end().unwrap();
let src = str::from_utf8_owned(contents).unwrap();
(d::StrInput(src), None)
} else {
(d::FileInput(Path::new(ifile)), Some(Path::new(ifile)))
@@ -267,7 +272,7 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) {
d::FileInput(ref ifile) => {
let mut stdout = io::stdout();
d::list_metadata(sess, &(*ifile),
&mut stdout as &mut io::Writer);
&mut stdout as &mut io::Writer).unwrap();
}
d::StrInput(_) => {
d::early_error(demitter, "can not list metadata for stdin");
+17 -16
View File
@@ -1111,15 +1111,15 @@ fn get_attributes(md: ebml::Doc) -> ~[ast::Attribute] {
}
fn list_crate_attributes(intr: @IdentInterner, md: ebml::Doc, hash: &str,
out: &mut io::Writer) {
write!(out, "=Crate Attributes ({})=\n", hash);
out: &mut io::Writer) -> io::IoResult<()> {
if_ok!(write!(out, "=Crate Attributes ({})=\n", hash));
let r = get_attributes(md);
for attr in r.iter() {
write!(out, "{}\n", pprust::attribute_to_str(attr, intr));
if_ok!(write!(out, "{}\n", pprust::attribute_to_str(attr, intr)));
}
write!(out, "\n\n");
write!(out, "\n\n")
}
pub fn get_crate_attributes(data: &[u8]) -> ~[ast::Attribute] {
@@ -1154,21 +1154,22 @@ fn docstr(doc: ebml::Doc, tag_: uint) -> ~str {
return deps;
}
fn list_crate_deps(data: &[u8], out: &mut io::Writer) {
write!(out, "=External Dependencies=\n");
fn list_crate_deps(data: &[u8], out: &mut io::Writer) -> io::IoResult<()> {
if_ok!(write!(out, "=External Dependencies=\n"));
let r = get_crate_deps(data);
for dep in r.iter() {
let string = token::get_ident(dep.name.name);
write!(out,
"{} {}-{}-{}\n",
dep.cnum,
string.get(),
dep.hash,
dep.vers);
if_ok!(write!(out,
"{} {}-{}-{}\n",
dep.cnum,
string.get(),
dep.hash,
dep.vers));
}
write!(out, "\n");
if_ok!(write!(out, "\n"));
Ok(())
}
pub fn get_crate_hash(data: &[u8]) -> ~str {
@@ -1186,11 +1187,11 @@ pub fn get_crate_vers(data: &[u8]) -> ~str {
}
pub fn list_crate_metadata(intr: @IdentInterner, bytes: &[u8],
out: &mut io::Writer) {
out: &mut io::Writer) -> io::IoResult<()> {
let hash = get_crate_hash(bytes);
let md = reader::Doc(bytes);
list_crate_attributes(intr, md, hash, out);
list_crate_deps(bytes, out);
if_ok!(list_crate_attributes(intr, md, hash, out));
list_crate_deps(bytes, out)
}
// Translates a def_id from an external crate to a def_id for the current
+38 -37
View File
@@ -10,6 +10,7 @@
// Metadata encoding
#[allow(unused_must_use)]; // everything is just a MemWriter, can't fail
use metadata::common::*;
use metadata::cstore;
@@ -350,7 +351,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
let mut index = index.borrow_mut();
index.get().push(entry {
val: variant.node.id as i64,
pos: ebml_w.writer.tell(),
pos: ebml_w.writer.tell().unwrap(),
});
}
ebml_w.start_tag(tag_items_data_item);
@@ -668,10 +669,10 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::Explic
// Encode the base self type.
match explicit_self {
SelfStatic => ebml_w.writer.write(&[ 's' as u8 ]),
SelfValue => ebml_w.writer.write(&[ 'v' as u8 ]),
SelfBox => ebml_w.writer.write(&[ '@' as u8 ]),
SelfUniq => ebml_w.writer.write(&[ '~' as u8 ]),
SelfStatic => { ebml_w.writer.write(&[ 's' as u8 ]); }
SelfValue => { ebml_w.writer.write(&[ 'v' as u8 ]); }
SelfBox => { ebml_w.writer.write(&[ '@' as u8 ]); }
SelfUniq => { ebml_w.writer.write(&[ '~' as u8 ]); }
SelfRegion(_, m) => {
// FIXME(#4846) encode custom lifetime
ebml_w.writer.write(&['&' as u8]);
@@ -684,8 +685,8 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::Explic
fn encode_mutability(ebml_w: &writer::Encoder,
m: ast::Mutability) {
match m {
MutImmutable => ebml_w.writer.write(&[ 'i' as u8 ]),
MutMutable => ebml_w.writer.write(&[ 'm' as u8 ]),
MutImmutable => { ebml_w.writer.write(&[ 'i' as u8 ]); }
MutMutable => { ebml_w.writer.write(&[ 'm' as u8 ]); }
}
}
}
@@ -726,12 +727,12 @@ fn encode_info_for_struct(ecx: &EncodeContext,
};
let id = field.node.id;
index.push(entry {val: id as i64, pos: ebml_w.writer.tell()});
index.push(entry {val: id as i64, pos: ebml_w.writer.tell().unwrap()});
{
let mut global_index = global_index.borrow_mut();
global_index.get().push(entry {
val: id as i64,
pos: ebml_w.writer.tell(),
pos: ebml_w.writer.tell().unwrap(),
});
}
ebml_w.start_tag(tag_items_data_item);
@@ -758,7 +759,7 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
let mut index = index.borrow_mut();
index.get().push(entry {
val: ctor_id as i64,
pos: ebml_w.writer.tell(),
pos: ebml_w.writer.tell().unwrap(),
});
}
@@ -921,7 +922,7 @@ fn add_to_index(item: &Item, ebml_w: &writer::Encoder,
let mut index = index.borrow_mut();
index.get().push(entry {
val: item.id as i64,
pos: ebml_w.writer.tell(),
pos: ebml_w.writer.tell().unwrap(),
});
}
let add_to_index: || = || add_to_index(item, ebml_w, index);
@@ -1157,7 +1158,7 @@ fn add_to_index(item: &Item, ebml_w: &writer::Encoder,
let mut index = index.borrow_mut();
index.get().push(entry {
val: m.def_id.node as i64,
pos: ebml_w.writer.tell(),
pos: ebml_w.writer.tell().unwrap(),
});
}
encode_info_for_method(ecx,
@@ -1219,7 +1220,7 @@ fn add_to_index(item: &Item, ebml_w: &writer::Encoder,
let mut index = index.borrow_mut();
index.get().push(entry {
val: method_def_id.node as i64,
pos: ebml_w.writer.tell(),
pos: ebml_w.writer.tell().unwrap(),
});
}
@@ -1294,7 +1295,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
let mut index = index.borrow_mut();
index.get().push(entry {
val: nitem.id as i64,
pos: ebml_w.writer.tell(),
pos: ebml_w.writer.tell().unwrap(),
});
}
@@ -1418,7 +1419,7 @@ fn encode_info_for_items(ecx: &EncodeContext,
let mut index = index.borrow_mut();
index.get().push(entry {
val: CRATE_NODE_ID as i64,
pos: ebml_w.writer.tell(),
pos: ebml_w.writer.tell().unwrap(),
});
}
encode_info_for_mod(ecx,
@@ -1478,7 +1479,7 @@ fn encode_index<T:'static>(
let mut bucket_locs = ~[];
ebml_w.start_tag(tag_index_buckets);
for bucket in buckets.iter() {
bucket_locs.push(ebml_w.writer.tell());
bucket_locs.push(ebml_w.writer.tell().unwrap());
ebml_w.start_tag(tag_index_buckets_bucket);
for elt in (**bucket).iter() {
ebml_w.start_tag(tag_index_buckets_bucket_elt);
@@ -1895,58 +1896,58 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, crate: &Crate)
encode_hash(&mut ebml_w, ecx.link_meta.crate_hash);
let mut i = ebml_w.writer.tell();
let mut i = ebml_w.writer.tell().unwrap();
let crate_attrs = synthesize_crate_attrs(&ecx, crate);
encode_attributes(&mut ebml_w, crate_attrs);
ecx.stats.attr_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.attr_bytes.set(ebml_w.writer.tell().unwrap() - i);
i = ebml_w.writer.tell();
i = ebml_w.writer.tell().unwrap();
encode_crate_deps(&ecx, &mut ebml_w, ecx.cstore);
ecx.stats.dep_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.dep_bytes.set(ebml_w.writer.tell().unwrap() - i);
// Encode the language items.
i = ebml_w.writer.tell();
i = ebml_w.writer.tell().unwrap();
encode_lang_items(&ecx, &mut ebml_w);
ecx.stats.lang_item_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.lang_item_bytes.set(ebml_w.writer.tell().unwrap() - i);
// Encode the native libraries used
i = ebml_w.writer.tell();
i = ebml_w.writer.tell().unwrap();
encode_native_libraries(&ecx, &mut ebml_w);
ecx.stats.native_lib_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.native_lib_bytes.set(ebml_w.writer.tell().unwrap() - i);
// Encode the macro registrar function
i = ebml_w.writer.tell();
i = ebml_w.writer.tell().unwrap();
encode_macro_registrar_fn(&ecx, &mut ebml_w);
ecx.stats.macro_registrar_fn_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.macro_registrar_fn_bytes.set(ebml_w.writer.tell().unwrap() - i);
// Encode macro definitions
i = ebml_w.writer.tell();
i = ebml_w.writer.tell().unwrap();
encode_macro_defs(&ecx, crate, &mut ebml_w);
ecx.stats.macro_defs_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.macro_defs_bytes.set(ebml_w.writer.tell().unwrap() - i);
// Encode the def IDs of impls, for coherence checking.
i = ebml_w.writer.tell();
i = ebml_w.writer.tell().unwrap();
encode_impls(&ecx, crate, &mut ebml_w);
ecx.stats.impl_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.impl_bytes.set(ebml_w.writer.tell().unwrap() - i);
// Encode miscellaneous info.
i = ebml_w.writer.tell();
i = ebml_w.writer.tell().unwrap();
encode_misc_info(&ecx, crate, &mut ebml_w);
ecx.stats.misc_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.misc_bytes.set(ebml_w.writer.tell().unwrap() - i);
// Encode and index the items.
ebml_w.start_tag(tag_items);
i = ebml_w.writer.tell();
i = ebml_w.writer.tell().unwrap();
let items_index = encode_info_for_items(&ecx, &mut ebml_w, crate);
ecx.stats.item_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.item_bytes.set(ebml_w.writer.tell().unwrap() - i);
i = ebml_w.writer.tell();
i = ebml_w.writer.tell().unwrap();
let items_buckets = create_index(items_index);
encode_index(&mut ebml_w, items_buckets, write_i64);
ecx.stats.index_bytes.set(ebml_w.writer.tell() - i);
ecx.stats.index_bytes.set(ebml_w.writer.tell().unwrap() - i);
ebml_w.end_tag();
ecx.stats.total_bytes.set(ebml_w.writer.tell());
ecx.stats.total_bytes.set(ebml_w.writer.tell().unwrap());
if tcx.sess.meta_stats() {
for e in ebml_w.writer.get_ref().iter() {
+4 -5
View File
@@ -11,7 +11,6 @@
use std::cell::RefCell;
use std::option;
use std::os;
use std::io;
use std::io::fs;
use std::hashmap::HashSet;
@@ -93,7 +92,7 @@ pub fn get_target_lib_file_path(&self, file: &Path) -> Path {
pub fn search(&self, pick: pick) {
self.for_each_lib_search_path(|lib_search_path| {
debug!("searching {}", lib_search_path.display());
match io::result(|| fs::readdir(lib_search_path)) {
match fs::readdir(lib_search_path) {
Ok(files) => {
let mut rslt = FileDoesntMatch;
let is_rlib = |p: & &Path| {
@@ -163,8 +162,8 @@ pub fn get_or_default_sysroot() -> Path {
// Follow symlinks. If the resolved path is relative, make it absolute.
fn canonicalize(path: Option<Path>) -> Option<Path> {
path.and_then(|mut path|
match io::io_error::cond.trap(|_| ()).inside(|| fs::readlink(&path)) {
Some(canon) => {
match fs::readlink(&path) {
Ok(canon) => {
if canon.is_absolute() {
Some(canon)
} else {
@@ -172,7 +171,7 @@ fn canonicalize(path: Option<Path>) -> Option<Path> {
Some(path.join(canon))
}
},
None => Some(path),
Err(..) => Some(path),
})
}
+2 -2
View File
@@ -381,13 +381,13 @@ pub fn read_meta_section_name(os: Os) -> &'static str {
pub fn list_file_metadata(intr: @IdentInterner,
os: Os,
path: &Path,
out: &mut io::Writer) {
out: &mut io::Writer) -> io::IoResult<()> {
match get_metadata_section(os, path) {
option::Some(bytes) => decoder::list_crate_metadata(intr,
bytes.as_slice(),
out),
option::None => {
write!(out, "could not find metadata in {}.\n", path.display())
write!(out, "could not find metadata in {}.\n", path.display())
}
}
}
+4 -2
View File
@@ -10,6 +10,8 @@
// Type encoding
#[allow(unused_must_use)]; // as with encoding, everything is a no-fail MemWriter
use std::cell::RefCell;
use std::hashmap::HashMap;
use std::io;
@@ -92,9 +94,9 @@ pub fn enc_ty(w: &mut MemWriter, cx: @ctxt, t: ty::t) {
None => {}
}
}
let pos = w.tell();
let pos = w.tell().unwrap();
enc_sty(w, cx, &ty::get(t).sty);
let end = w.tell();
let end = w.tell().unwrap();
let len = end - pos;
fn estimate_sz(u: u64) -> u64 {
let mut n = u;
+12 -9
View File
@@ -88,7 +88,7 @@ struct LoopScope<'a> {
}
impl<O:DataFlowOperator> pprust::PpAnn for DataFlowContext<O> {
fn pre(&self, node: pprust::AnnNode) {
fn pre(&self, node: pprust::AnnNode) -> io::IoResult<()> {
let (ps, id) = match node {
pprust::NodeExpr(ps, expr) => (ps, expr.id),
pprust::NodeBlock(ps, blk) => (ps, blk.id),
@@ -117,9 +117,10 @@ fn pre(&self, node: pprust::AnnNode) {
let comment_str = format!("id {}: {}{}{}",
id, entry_str, gens_str, kills_str);
pprust::synth_comment(ps, comment_str);
pp::space(&mut ps.s);
if_ok!(pprust::synth_comment(ps, comment_str));
if_ok!(pp::space(&mut ps.s));
}
Ok(())
}
}
@@ -347,18 +348,20 @@ pub fn propagate(&mut self, blk: &ast::Block) {
debug!("Dataflow result:");
debug!("{}", {
let this = @(*self).clone();
this.pretty_print_to(~io::stderr() as ~io::Writer, blk);
this.pretty_print_to(~io::stderr() as ~io::Writer, blk).unwrap();
""
});
}
fn pretty_print_to(@self, wr: ~io::Writer, blk: &ast::Block) {
fn pretty_print_to(@self, wr: ~io::Writer,
blk: &ast::Block) -> io::IoResult<()> {
let mut ps = pprust::rust_printer_annotated(wr, self.tcx.sess.intr(),
self as @pprust::PpAnn);
pprust::cbox(&mut ps, pprust::indent_unit);
pprust::ibox(&mut ps, 0u);
pprust::print_block(&mut ps, blk);
pp::eof(&mut ps.s);
if_ok!(pprust::cbox(&mut ps, pprust::indent_unit));
if_ok!(pprust::ibox(&mut ps, 0u));
if_ok!(pprust::print_block(&mut ps, blk));
if_ok!(pp::eof(&mut ps.s));
Ok(())
}
}
+4 -2
View File
@@ -736,14 +736,15 @@ pub fn indices2(&self,
pub fn write_vars(&self,
wr: &mut io::Writer,
ln: LiveNode,
test: |uint| -> LiveNode) {
test: |uint| -> LiveNode) -> io::IoResult<()> {
let node_base_idx = self.idx(ln, Variable(0));
for var_idx in range(0u, self.ir.num_vars.get()) {
let idx = node_base_idx + var_idx;
if test(idx).is_valid() {
write!(wr, " {}", Variable(var_idx).to_str());
if_ok!(write!(wr, " {}", Variable(var_idx).to_str()));
}
}
Ok(())
}
pub fn find_loop_scope(&self,
@@ -781,6 +782,7 @@ pub fn last_loop_scope(&self) -> NodeId {
*loop_scope.get().last().unwrap()
}
#[allow(unused_must_use)]
pub fn ln_str(&self, ln: LiveNode) -> ~str {
let mut wr = io::MemWriter::new();
{
+5 -4
View File
@@ -20,7 +20,7 @@
pub struct Escape<'a>(&'a str);
impl<'a> fmt::Show for Escape<'a> {
fn fmt(s: &Escape<'a>, fmt: &mut fmt::Formatter) {
fn fmt(s: &Escape<'a>, fmt: &mut fmt::Formatter) -> fmt::Result {
// Because the internet is always right, turns out there's not that many
// characters to escape: http://stackoverflow.com/questions/7381974
let Escape(s) = *s;
@@ -29,7 +29,7 @@ fn fmt(s: &Escape<'a>, fmt: &mut fmt::Formatter) {
for (i, ch) in s.bytes().enumerate() {
match ch as char {
'<' | '>' | '&' | '\'' | '"' => {
fmt.buf.write(pile_o_bits.slice(last, i).as_bytes());
if_ok!(fmt.buf.write(pile_o_bits.slice(last, i).as_bytes()));
let s = match ch as char {
'>' => "&gt;",
'<' => "&lt;",
@@ -38,7 +38,7 @@ fn fmt(s: &Escape<'a>, fmt: &mut fmt::Formatter) {
'"' => "&quot;",
_ => unreachable!()
};
fmt.buf.write(s.as_bytes());
if_ok!(fmt.buf.write(s.as_bytes()));
last = i + 1;
}
_ => {}
@@ -46,7 +46,8 @@ fn fmt(s: &Escape<'a>, fmt: &mut fmt::Formatter) {
}
if last < s.len() {
fmt.buf.write(pile_o_bits.slice_from(last).as_bytes());
if_ok!(fmt.buf.write(pile_o_bits.slice_from(last).as_bytes()));
}
Ok(())
}
}
+123 -88
View File
@@ -48,85 +48,104 @@ pub fn get(&self) -> ast::Purity {
}
impl fmt::Show for clean::Generics {
fn fmt(g: &clean::Generics, f: &mut fmt::Formatter) {
if g.lifetimes.len() == 0 && g.type_params.len() == 0 { return }
f.buf.write("&lt;".as_bytes());
fn fmt(g: &clean::Generics, f: &mut fmt::Formatter) -> fmt::Result {
if g.lifetimes.len() == 0 && g.type_params.len() == 0 { return Ok(()) }
if_ok!(f.buf.write("&lt;".as_bytes()));
for (i, life) in g.lifetimes.iter().enumerate() {
if i > 0 { f.buf.write(", ".as_bytes()); }
write!(f.buf, "{}", *life);
if i > 0 {
if_ok!(f.buf.write(", ".as_bytes()));
}
if_ok!(write!(f.buf, "{}", *life));
}
if g.type_params.len() > 0 {
if g.lifetimes.len() > 0 { f.buf.write(", ".as_bytes()); }
if g.lifetimes.len() > 0 {
if_ok!(f.buf.write(", ".as_bytes()));
}
for (i, tp) in g.type_params.iter().enumerate() {
if i > 0 { f.buf.write(", ".as_bytes()) }
f.buf.write(tp.name.as_bytes());
if i > 0 {
if_ok!(f.buf.write(", ".as_bytes()))
}
if_ok!(f.buf.write(tp.name.as_bytes()));
if tp.bounds.len() > 0 {
f.buf.write(": ".as_bytes());
if_ok!(f.buf.write(": ".as_bytes()));
for (i, bound) in tp.bounds.iter().enumerate() {
if i > 0 { f.buf.write(" + ".as_bytes()); }
write!(f.buf, "{}", *bound);
if i > 0 {
if_ok!(f.buf.write(" + ".as_bytes()));
}
if_ok!(write!(f.buf, "{}", *bound));
}
}
}
}
f.buf.write("&gt;".as_bytes());
if_ok!(f.buf.write("&gt;".as_bytes()));
Ok(())
}
}
impl fmt::Show for clean::Lifetime {
fn fmt(l: &clean::Lifetime, f: &mut fmt::Formatter) {
f.buf.write("'".as_bytes());
f.buf.write(l.get_ref().as_bytes());
fn fmt(l: &clean::Lifetime, f: &mut fmt::Formatter) -> fmt::Result {
if_ok!(f.buf.write("'".as_bytes()));
if_ok!(f.buf.write(l.get_ref().as_bytes()));
Ok(())
}
}
impl fmt::Show for clean::TyParamBound {
fn fmt(bound: &clean::TyParamBound, f: &mut fmt::Formatter) {
fn fmt(bound: &clean::TyParamBound, f: &mut fmt::Formatter) -> fmt::Result {
match *bound {
clean::RegionBound => {
f.buf.write("'static".as_bytes())
}
clean::TraitBound(ref ty) => {
write!(f.buf, "{}", *ty);
write!(f.buf, "{}", *ty)
}
}
}
}
impl fmt::Show for clean::Path {
fn fmt(path: &clean::Path, f: &mut fmt::Formatter) {
if path.global { f.buf.write("::".as_bytes()) }
fn fmt(path: &clean::Path, f: &mut fmt::Formatter) -> fmt::Result {
if path.global {
if_ok!(f.buf.write("::".as_bytes()))
}
for (i, seg) in path.segments.iter().enumerate() {
if i > 0 { f.buf.write("::".as_bytes()) }
f.buf.write(seg.name.as_bytes());
if i > 0 {
if_ok!(f.buf.write("::".as_bytes()))
}
if_ok!(f.buf.write(seg.name.as_bytes()));
if seg.lifetimes.len() > 0 || seg.types.len() > 0 {
f.buf.write("&lt;".as_bytes());
if_ok!(f.buf.write("&lt;".as_bytes()));
let mut comma = false;
for lifetime in seg.lifetimes.iter() {
if comma { f.buf.write(", ".as_bytes()); }
if comma {
if_ok!(f.buf.write(", ".as_bytes()));
}
comma = true;
write!(f.buf, "{}", *lifetime);
if_ok!(write!(f.buf, "{}", *lifetime));
}
for ty in seg.types.iter() {
if comma { f.buf.write(", ".as_bytes()); }
if comma {
if_ok!(f.buf.write(", ".as_bytes()));
}
comma = true;
write!(f.buf, "{}", *ty);
if_ok!(write!(f.buf, "{}", *ty));
}
f.buf.write("&gt;".as_bytes());
if_ok!(f.buf.write("&gt;".as_bytes()));
}
}
Ok(())
}
}
/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
/// rendering function with the necessary arguments for linking to a local path.
fn resolved_path(w: &mut io::Writer, id: ast::NodeId, p: &clean::Path,
print_all: bool) {
print_all: bool) -> fmt::Result {
path(w, p, print_all,
|_cache, loc| { Some("../".repeat(loc.len())) },
|cache| {
@@ -134,13 +153,14 @@ fn resolved_path(w: &mut io::Writer, id: ast::NodeId, p: &clean::Path,
None => None,
Some(&(ref fqp, shortty)) => Some((fqp.clone(), shortty))
}
});
})
}
/// Used when rendering an `ExternalPath` structure. Like `resolved_path` this
/// will invoke `path` with proper linking-style arguments.
fn external_path(w: &mut io::Writer, p: &clean::Path, print_all: bool,
fqn: &[~str], kind: clean::TypeKind, crate: ast::CrateNum) {
fqn: &[~str], kind: clean::TypeKind,
crate: ast::CrateNum) -> fmt::Result {
path(w, p, print_all,
|cache, loc| {
match *cache.extern_locations.get(&crate) {
@@ -161,7 +181,9 @@ fn external_path(w: &mut io::Writer, p: &clean::Path, print_all: bool,
fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
root: |&render::Cache, &[~str]| -> Option<~str>,
info: |&render::Cache| -> Option<(~[~str], &'static str)>) {
info: |&render::Cache| -> Option<(~[~str], &'static str)>)
-> fmt::Result
{
// The generics will get written to both the title and link
let mut generics = ~"";
let last = path.segments.last().unwrap();
@@ -200,20 +222,20 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
let mut root = root;
for seg in path.segments.slice_to(amt).iter() {
if "super" == seg.name || "self" == seg.name {
write!(w, "{}::", seg.name);
if_ok!(write!(w, "{}::", seg.name));
} else {
root.push_str(seg.name);
root.push_str("/");
write!(w, "<a class='mod'
href='{}index.html'>{}</a>::",
root,
seg.name);
if_ok!(write!(w, "<a class='mod'
href='{}index.html'>{}</a>::",
root,
seg.name));
}
}
}
None => {
for seg in path.segments.slice_to(amt).iter() {
write!(w, "{}::", seg.name);
if_ok!(write!(w, "{}::", seg.name));
}
}
}
@@ -241,51 +263,57 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
}
}
write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
shortty, url, fqp.connect("::"), last.name);
if_ok!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
shortty, url, fqp.connect("::"), last.name));
}
_ => {
write!(w, "{}", last.name);
if_ok!(write!(w, "{}", last.name));
}
}
write!(w, "{}", generics);
if_ok!(write!(w, "{}", generics));
Ok(())
})
})
}
/// Helper to render type parameters
fn typarams(w: &mut io::Writer, typarams: &Option<~[clean::TyParamBound]>) {
fn typarams(w: &mut io::Writer,
typarams: &Option<~[clean::TyParamBound]>) -> fmt::Result {
match *typarams {
Some(ref params) => {
write!(w, "&lt;");
if_ok!(write!(w, "&lt;"));
for (i, param) in params.iter().enumerate() {
if i > 0 { write!(w, ", "); }
write!(w, "{}", *param);
if i > 0 {
if_ok!(write!(w, ", "));
}
if_ok!(write!(w, "{}", *param));
}
write!(w, "&gt;");
if_ok!(write!(w, "&gt;"));
Ok(())
}
None => {}
None => Ok(())
}
}
impl fmt::Show for clean::Type {
fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
fn fmt(g: &clean::Type, f: &mut fmt::Formatter) -> fmt::Result {
match *g {
clean::TyParamBinder(id) | clean::Generic(id) => {
local_data::get(cache_key, |cache| {
let m = cache.unwrap().get();
f.buf.write(m.typarams.get(&id).as_bytes());
f.buf.write(m.typarams.get(&id).as_bytes())
})
}
clean::ResolvedPath{id, typarams: ref tp, path: ref path} => {
resolved_path(f.buf, id, path, false);
typarams(f.buf, tp);
if_ok!(resolved_path(f.buf, id, path, false));
typarams(f.buf, tp)
}
clean::ExternalPath{path: ref path, typarams: ref tp,
fqn: ref fqn, kind, crate} => {
external_path(f.buf, path, false, fqn.as_slice(), kind, crate);
typarams(f.buf, tp);
if_ok!(external_path(f.buf, path, false, fqn.as_slice(), kind,
crate))
typarams(f.buf, tp)
}
clean::Self(..) => f.buf.write("Self".as_bytes()),
clean::Primitive(prim) => {
@@ -306,7 +334,7 @@ fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
ast::TyBool => "bool",
ast::TyChar => "char",
};
f.buf.write(s.as_bytes());
f.buf.write(s.as_bytes())
}
clean::Closure(ref decl) => {
let region = match decl.region {
@@ -322,7 +350,7 @@ fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
ast::ManagedSigil => format!("@{}fn({})", region, decl.decl.inputs),
},
arrow = match decl.decl.output { clean::Unit => "no", _ => "yes" },
ret = decl.decl.output);
ret = decl.decl.output)
// FIXME: where are bounds and lifetimes printed?!
}
clean::BareFunction(ref decl) => {
@@ -333,19 +361,21 @@ fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
ref s => " " + *s + " ",
},
decl.generics,
decl.decl);
decl.decl)
}
clean::Tuple(ref typs) => {
f.buf.write("(".as_bytes());
if_ok!(f.buf.write("(".as_bytes()));
for (i, typ) in typs.iter().enumerate() {
if i > 0 { f.buf.write(", ".as_bytes()) }
write!(f.buf, "{}", *typ);
if i > 0 {
if_ok!(f.buf.write(", ".as_bytes()))
}
if_ok!(write!(f.buf, "{}", *typ));
}
f.buf.write(")".as_bytes());
f.buf.write(")".as_bytes())
}
clean::Vector(ref t) => write!(f.buf, "[{}]", **t),
clean::FixedVector(ref t, ref s) => {
write!(f.buf, "[{}, ..{}]", **t, *s);
write!(f.buf, "[{}, ..{}]", **t, *s)
}
clean::String => f.buf.write("str".as_bytes()),
clean::Bool => f.buf.write("bool".as_bytes()),
@@ -368,23 +398,23 @@ fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
clean::Mutable => "mut ",
clean::Immutable => "",
},
**ty);
**ty)
}
}
}
}
impl fmt::Show for clean::FnDecl {
fn fmt(d: &clean::FnDecl, f: &mut fmt::Formatter) {
fn fmt(d: &clean::FnDecl, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, "({args}){arrow, select, yes{ -&gt; {ret}} other{}}",
args = d.inputs,
arrow = match d.output { clean::Unit => "no", _ => "yes" },
ret = d.output);
ret = d.output)
}
}
impl fmt::Show for ~[clean::Argument] {
fn fmt(inputs: &~[clean::Argument], f: &mut fmt::Formatter) {
fn fmt(inputs: &~[clean::Argument], f: &mut fmt::Formatter) -> fmt::Result {
let mut args = ~"";
for (i, input) in inputs.iter().enumerate() {
if i > 0 { args.push_str(", "); }
@@ -393,12 +423,12 @@ fn fmt(inputs: &~[clean::Argument], f: &mut fmt::Formatter) {
}
args.push_str(format!("{}", input.type_));
}
f.buf.write(args.as_bytes());
f.buf.write(args.as_bytes())
}
}
impl<'a> fmt::Show for Method<'a> {
fn fmt(m: &Method<'a>, f: &mut fmt::Formatter) {
fn fmt(m: &Method<'a>, f: &mut fmt::Formatter) -> fmt::Result {
let Method(selfty, d) = *m;
let mut args = ~"";
match *selfty {
@@ -429,74 +459,79 @@ fn fmt(m: &Method<'a>, f: &mut fmt::Formatter) {
write!(f.buf, "({args}){arrow, select, yes{ -&gt; {ret}} other{}}",
args = args,
arrow = match d.output { clean::Unit => "no", _ => "yes" },
ret = d.output);
ret = d.output)
}
}
impl fmt::Show for VisSpace {
fn fmt(v: &VisSpace, f: &mut fmt::Formatter) {
fn fmt(v: &VisSpace, f: &mut fmt::Formatter) -> fmt::Result {
match v.get() {
Some(ast::Public) => { write!(f.buf, "pub "); }
Some(ast::Private) => { write!(f.buf, "priv "); }
Some(ast::Inherited) | None => {}
Some(ast::Public) => write!(f.buf, "pub "),
Some(ast::Private) => write!(f.buf, "priv "),
Some(ast::Inherited) | None => Ok(())
}
}
}
impl fmt::Show for PuritySpace {
fn fmt(p: &PuritySpace, f: &mut fmt::Formatter) {
fn fmt(p: &PuritySpace, f: &mut fmt::Formatter) -> fmt::Result {
match p.get() {
ast::UnsafeFn => write!(f.buf, "unsafe "),
ast::ExternFn => write!(f.buf, "extern "),
ast::ImpureFn => {}
ast::ImpureFn => Ok(())
}
}
}
impl fmt::Show for clean::ViewPath {
fn fmt(v: &clean::ViewPath, f: &mut fmt::Formatter) {
fn fmt(v: &clean::ViewPath, f: &mut fmt::Formatter) -> fmt::Result {
match *v {
clean::SimpleImport(ref name, ref src) => {
if *name == src.path.segments.last().unwrap().name {
write!(f.buf, "use {};", *src);
write!(f.buf, "use {};", *src)
} else {
write!(f.buf, "use {} = {};", *name, *src);
write!(f.buf, "use {} = {};", *name, *src)
}
}
clean::GlobImport(ref src) => {
write!(f.buf, "use {}::*;", *src);
write!(f.buf, "use {}::*;", *src)
}
clean::ImportList(ref src, ref names) => {
write!(f.buf, "use {}::\\{", *src);
if_ok!(write!(f.buf, "use {}::\\{", *src));
for (i, n) in names.iter().enumerate() {
if i > 0 { write!(f.buf, ", "); }
write!(f.buf, "{}", *n);
if i > 0 {
if_ok!(write!(f.buf, ", "));
}
if_ok!(write!(f.buf, "{}", *n));
}
write!(f.buf, "\\};");
write!(f.buf, "\\};")
}
}
}
}
impl fmt::Show for clean::ImportSource {
fn fmt(v: &clean::ImportSource, f: &mut fmt::Formatter) {
fn fmt(v: &clean::ImportSource, f: &mut fmt::Formatter) -> fmt::Result {
match v.did {
// FIXME: shouldn't be restricted to just local imports
Some(did) if ast_util::is_local(did) => {
resolved_path(f.buf, did.node, &v.path, true);
resolved_path(f.buf, did.node, &v.path, true)
}
_ => {
for (i, seg) in v.path.segments.iter().enumerate() {
if i > 0 { write!(f.buf, "::") }
write!(f.buf, "{}", seg.name);
if i > 0 {
if_ok!(write!(f.buf, "::"))
}
if_ok!(write!(f.buf, "{}", seg.name));
}
Ok(())
}
}
}
}
impl fmt::Show for clean::ViewListIdent {
fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) {
fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) -> fmt::Result {
match v.source {
// FIXME: shouldn't be limited to just local imports
Some(did) if ast_util::is_local(did) => {
@@ -508,7 +543,7 @@ fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) {
types: ~[],
}]
};
resolved_path(f.buf, did.node, &path, false);
resolved_path(f.buf, did.node, &path, false)
}
_ => write!(f.buf, "{}", v.name),
}
+2 -1
View File
@@ -26,6 +26,7 @@ pub struct Page<'a> {
pub fn render<T: fmt::Show, S: fmt::Show>(
dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T)
-> fmt::Result
{
write!(dst,
"<!DOCTYPE html>
@@ -121,7 +122,7 @@ pub fn render<T: fmt::Show, S: fmt::Show>(
favicon = nonestr(layout.favicon),
sidebar = *sidebar,
crate = layout.crate,
);
)
}
fn nonestr<'a>(s: &'a str) -> &'a str {
+7 -6
View File
@@ -109,7 +109,7 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
}
}
pub fn render(w: &mut io::Writer, s: &str) {
pub fn render(w: &mut io::Writer, s: &str) -> fmt::Result {
extern fn block(ob: *buf, text: *buf, lang: *buf, opaque: *libc::c_void) {
unsafe {
let my_opaque: &my_opaque = cast::transmute(opaque);
@@ -159,11 +159,12 @@ pub fn render(w: &mut io::Writer, s: &str) {
sd_markdown_render(ob, s.as_ptr(), s.len() as libc::size_t, markdown);
sd_markdown_free(markdown);
vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
w.write(buf);
let ret = vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
w.write(buf)
});
bufrelease(ob);
ret
}
}
@@ -210,10 +211,10 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
}
impl<'a> fmt::Show for Markdown<'a> {
fn fmt(md: &Markdown<'a>, fmt: &mut fmt::Formatter) {
fn fmt(md: &Markdown<'a>, fmt: &mut fmt::Formatter) -> fmt::Result {
let Markdown(md) = *md;
// This is actually common enough to special-case
if md.len() == 0 { return; }
render(fmt.buf, md.as_slice());
if md.len() == 0 { return Ok(()) }
render(fmt.buf, md.as_slice())
}
}
+341 -309
View File
@@ -195,7 +195,7 @@ struct IndexItem {
local_data_key!(pub current_location_key: ~[~str])
/// Generates the documentation for `crate` into the directory `dst`
pub fn run(mut crate: clean::Crate, dst: Path) {
pub fn run(mut crate: clean::Crate, dst: Path) -> io::IoResult<()> {
let mut cx = Context {
dst: dst,
current: ~[],
@@ -208,7 +208,7 @@ pub fn run(mut crate: clean::Crate, dst: Path) {
},
include_sources: true,
};
mkdir(&cx.dst);
if_ok!(mkdir(&cx.dst));
match crate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) {
Some(attrs) => {
@@ -248,47 +248,55 @@ pub fn run(mut crate: clean::Crate, dst: Path) {
// Add all the static files
let mut dst = cx.dst.join(crate.name.as_slice());
mkdir(&dst);
write(dst.join("jquery.js"), include_str!("static/jquery-2.0.3.min.js"));
write(dst.join("main.js"), include_str!("static/main.js"));
write(dst.join("main.css"), include_str!("static/main.css"));
write(dst.join("normalize.css"), include_str!("static/normalize.css"));
if_ok!(mkdir(&dst));
if_ok!(write(dst.join("jquery.js"),
include_str!("static/jquery-2.0.3.min.js")));
if_ok!(write(dst.join("main.js"), include_str!("static/main.js")));
if_ok!(write(dst.join("main.css"), include_str!("static/main.css")));
if_ok!(write(dst.join("normalize.css"),
include_str!("static/normalize.css")));
// Publish the search index
{
dst.push("search-index.js");
let mut w = BufferedWriter::new(File::create(&dst).unwrap());
let w = &mut w as &mut Writer;
write!(w, "var searchIndex = [");
if_ok!(write!(w, "var searchIndex = ["));
for (i, item) in cache.search_index.iter().enumerate() {
if i > 0 { write!(w, ","); }
write!(w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}",
item.ty, item.name, item.path,
item.desc.to_json().to_str())
if i > 0 {
if_ok!(write!(w, ","));
}
if_ok!(write!(w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}",
item.ty, item.name, item.path,
item.desc.to_json().to_str()));
match item.parent {
Some(id) => { write!(w, ",parent:'{}'", id); }
Some(id) => {
if_ok!(write!(w, ",parent:'{}'", id));
}
None => {}
}
write!(w, "\\}");
if_ok!(write!(w, "\\}"));
}
write!(w, "];");
write!(w, "var allPaths = \\{");
if_ok!(write!(w, "];"));
if_ok!(write!(w, "var allPaths = \\{"));
for (i, (&id, &(ref fqp, short))) in cache.paths.iter().enumerate() {
if i > 0 { write!(w, ","); }
write!(w, "'{}':\\{type:'{}',name:'{}'\\}",
id, short, *fqp.last().unwrap());
if i > 0 {
if_ok!(write!(w, ","));
}
if_ok!(write!(w, "'{}':\\{type:'{}',name:'{}'\\}",
id, short, *fqp.last().unwrap()));
}
write!(w, "\\};");
w.flush();
if_ok!(write!(w, "\\};"));
if_ok!(w.flush());
}
// Render all source files (this may turn into a giant no-op)
{
info!("emitting source files");
let dst = cx.dst.join("src");
mkdir(&dst);
if_ok!(mkdir(&dst));
let dst = dst.join(crate.name.as_slice());
mkdir(&dst);
if_ok!(mkdir(&dst));
let mut folder = SourceCollector {
dst: dst,
seen: HashSet::new(),
@@ -302,27 +310,23 @@ pub fn run(mut crate: clean::Crate, dst: Path) {
}
// And finally render the whole crate's documentation
cx.crate(crate, cache);
cx.crate(crate, cache)
}
/// Writes the entire contents of a string to a destination, not attempting to
/// catch any errors.
fn write(dst: Path, contents: &str) {
File::create(&dst).write(contents.as_bytes());
fn write(dst: Path, contents: &str) -> io::IoResult<()> {
File::create(&dst).write(contents.as_bytes())
}
/// Makes a directory on the filesystem, failing the task if an error occurs and
/// skipping if the directory already exists.
fn mkdir(path: &Path) {
io::io_error::cond.trap(|err| {
error!("Couldn't create directory `{}`: {}",
path.display(), err.desc);
fail!()
}).inside(|| {
if !path.is_dir() {
fs::mkdir(path, io::UserRWX);
}
})
fn mkdir(path: &Path) -> io::IoResult<()> {
if !path.exists() {
fs::mkdir(path, io::UserRWX)
} else {
Ok(())
}
}
/// Takes a path to a source file and cleans the path to it. This canonicalizes
@@ -387,15 +391,17 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
// something like that), so just don't include sources for the
// entire crate. The other option is maintaining this mapping on a
// per-file basis, but that's probably not worth it...
self.cx.include_sources = self.emit_source(item.source.filename);
self.cx.include_sources = match self.emit_source(item.source.filename) {
Ok(()) => true,
Err(e) => {
println!("warning: source code was requested to be rendered, \
but processing `{}` had an error: {}",
item.source.filename, e);
println!(" skipping rendering of source code");
false
}
};
self.seen.insert(item.source.filename.clone());
if !self.cx.include_sources {
println!("warning: source code was requested to be rendered, \
but `{}` is a missing source file.",
item.source.filename);
println!(" skipping rendering of source code");
}
}
self.fold_item_recur(item)
@@ -404,30 +410,18 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
impl<'a> SourceCollector<'a> {
/// Renders the given filename into its corresponding HTML source file.
fn emit_source(&mut self, filename: &str) -> bool {
fn emit_source(&mut self, filename: &str) -> io::IoResult<()> {
let p = Path::new(filename);
// Read the contents of the file
let mut contents = ~[];
{
let mut buf = [0, ..1024];
// If we couldn't open this file, then just returns because it
// probably means that it's some standard library macro thing and we
// can't have the source to it anyway.
let mut r = match io::result(|| File::open(&p)) {
Ok(r) => r,
// eew macro hacks
Err(..) => return filename == "<std-macros>"
};
// read everything
loop {
match r.read(buf) {
Some(n) => contents.push_all(buf.slice_to(n)),
None => break
}
}
}
// If we couldn't open this file, then just returns because it
// probably means that it's some standard library macro thing and we
// can't have the source to it anyway.
let contents = match File::open(&p).read_to_end() {
Ok(r) => r,
// eew macro hacks
Err(..) if filename == "<std-macros>" => return Ok(()),
Err(e) => return Err(e)
};
let contents = str::from_utf8_owned(contents).unwrap();
// Create the intermediate directories
@@ -435,12 +429,12 @@ fn emit_source(&mut self, filename: &str) -> bool {
let mut root_path = ~"../../";
clean_srcpath(p.dirname(), |component| {
cur.push(component);
mkdir(&cur);
mkdir(&cur).unwrap();
root_path.push_str("../");
});
cur.push(p.filename().expect("source has no filename") + bytes!(".html"));
let mut w = BufferedWriter::new(File::create(&cur).unwrap());
let mut w = BufferedWriter::new(if_ok!(File::create(&cur)));
let title = cur.filename_display().with_str(|s| format!("{} -- source", s));
let page = layout::Page {
@@ -448,10 +442,10 @@ fn emit_source(&mut self, filename: &str) -> bool {
ty: "source",
root_path: root_path,
};
layout::render(&mut w as &mut Writer, &self.cx.layout,
&page, &(""), &Source(contents.as_slice()));
w.flush();
return true;
if_ok!(layout::render(&mut w as &mut Writer, &self.cx.layout,
&page, &(""), &Source(contents.as_slice())));
if_ok!(w.flush());
return Ok(());
}
}
@@ -665,7 +659,7 @@ fn recurse<T>(&mut self, s: ~str, f: |&mut Context| -> T) -> T {
info!("Recursing into {}", self.dst.display());
mkdir(&self.dst);
mkdir(&self.dst).unwrap();
let ret = f(self);
info!("Recursed; leaving {}", self.dst.display());
@@ -683,10 +677,10 @@ fn recurse<T>(&mut self, s: ~str, f: |&mut Context| -> T) -> T {
///
/// This currently isn't parallelized, but it'd be pretty easy to add
/// parallelization to this function.
fn crate(self, mut crate: clean::Crate, cache: Cache) {
fn crate(self, mut crate: clean::Crate, cache: Cache) -> io::IoResult<()> {
let mut item = match crate.module.take() {
Some(i) => i,
None => return
None => return Ok(())
};
item.name = Some(crate.name);
@@ -696,12 +690,13 @@ fn crate(self, mut crate: clean::Crate, cache: Cache) {
let mut work = ~[(self, item)];
loop {
match work.pop() {
Some((mut cx, item)) => cx.item(item, |cx, item| {
Some((mut cx, item)) => if_ok!(cx.item(item, |cx, item| {
work.push((cx.clone(), item));
}),
})),
None => break,
}
}
Ok(())
}
/// Non-parellelized version of rendering an item. This will take the input
@@ -709,9 +704,10 @@ fn crate(self, mut crate: clean::Crate, cache: Cache) {
/// all sub-items which need to be rendered.
///
/// The rendering driver uses this closure to queue up more work.
fn item(&mut self, item: clean::Item, f: |&mut Context, clean::Item|) {
fn item(&mut self, item: clean::Item,
f: |&mut Context, clean::Item|) -> io::IoResult<()> {
fn render(w: io::File, cx: &mut Context, it: &clean::Item,
pushname: bool) {
pushname: bool) -> io::IoResult<()> {
info!("Rendering an item to {}", w.path().display());
// A little unfortunate that this is done like this, but it sure
// does make formatting *a lot* nicer.
@@ -733,10 +729,10 @@ fn render(w: io::File, cx: &mut Context, it: &clean::Item,
// of the pain by using a buffered writer instead of invoking the
// write sycall all the time.
let mut writer = BufferedWriter::new(w);
layout::render(&mut writer as &mut Writer, &cx.layout, &page,
&Sidebar{ cx: cx, item: it },
&Item{ cx: cx, item: it });
writer.flush();
if_ok!(layout::render(&mut writer as &mut Writer, &cx.layout, &page,
&Sidebar{ cx: cx, item: it },
&Item{ cx: cx, item: it }));
writer.flush()
}
match item.inner {
@@ -748,7 +744,8 @@ fn render(w: io::File, cx: &mut Context, it: &clean::Item,
self.recurse(name, |this| {
let item = item.take_unwrap();
let dst = this.dst.join("index.html");
render(File::create(&dst).unwrap(), this, &item, false);
let dst = if_ok!(File::create(&dst));
if_ok!(render(dst, this, &item, false));
let m = match item.inner {
clean::ModuleItem(m) => m,
@@ -758,6 +755,7 @@ fn render(w: io::File, cx: &mut Context, it: &clean::Item,
for item in m.items.move_iter() {
f(this,item);
}
Ok(())
})
}
@@ -765,10 +763,11 @@ fn render(w: io::File, cx: &mut Context, it: &clean::Item,
// pages dedicated to them.
_ if item.name.is_some() => {
let dst = self.dst.join(item_path(&item));
render(File::create(&dst).unwrap(), self, &item, true);
let dst = if_ok!(File::create(&dst));
render(dst, self, &item, true)
}
_ => {}
_ => Ok(())
}
}
}
@@ -802,16 +801,16 @@ fn ismodule(&self) -> bool {
}
impl<'a> fmt::Show for Item<'a> {
fn fmt(it: &Item<'a>, fmt: &mut fmt::Formatter) {
fn fmt(it: &Item<'a>, fmt: &mut fmt::Formatter) -> fmt::Result {
match attr::find_stability(it.item.attrs.iter()) {
Some(ref stability) => {
write!(fmt.buf,
if_ok!(write!(fmt.buf,
"<a class='stability {lvl}' title='{reason}'>{lvl}</a>",
lvl = stability.level.to_str(),
reason = match stability.text {
Some(ref s) => (*s).clone(),
None => InternedString::new(""),
});
}));
}
None => {}
}
@@ -826,23 +825,24 @@ fn fmt(it: &Item<'a>, fmt: &mut fmt::Formatter) {
} else {
format!("{}-{}", it.item.source.loline, it.item.source.hiline)
};
write!(fmt.buf,
"<a class='source'
href='{root}src/{crate}/{path}.html\\#{href}'>[src]</a>",
root = it.cx.root_path,
crate = it.cx.layout.crate,
path = path.connect("/"),
href = href);
if_ok!(write!(fmt.buf,
"<a class='source'
href='{root}src/{crate}/{path}.html\\#{href}'>\
[src]</a>",
root = it.cx.root_path,
crate = it.cx.layout.crate,
path = path.connect("/"),
href = href));
}
// Write the breadcrumb trail header for the top
write!(fmt.buf, "<h1 class='fqn'>");
if_ok!(write!(fmt.buf, "<h1 class='fqn'>"));
match it.item.inner {
clean::ModuleItem(..) => write!(fmt.buf, "Module "),
clean::FunctionItem(..) => write!(fmt.buf, "Function "),
clean::TraitItem(..) => write!(fmt.buf, "Trait "),
clean::StructItem(..) => write!(fmt.buf, "Struct "),
clean::EnumItem(..) => write!(fmt.buf, "Enum "),
clean::ModuleItem(..) => if_ok!(write!(fmt.buf, "Module ")),
clean::FunctionItem(..) => if_ok!(write!(fmt.buf, "Function ")),
clean::TraitItem(..) => if_ok!(write!(fmt.buf, "Trait ")),
clean::StructItem(..) => if_ok!(write!(fmt.buf, "Struct ")),
clean::EnumItem(..) => if_ok!(write!(fmt.buf, "Enum ")),
_ => {}
}
let cur = it.cx.current.as_slice();
@@ -852,11 +852,11 @@ fn fmt(it: &Item<'a>, fmt: &mut fmt::Formatter) {
for _ in range(0, cur.len() - i - 1) {
trail.push_str("../");
}
write!(fmt.buf, "<a href='{}index.html'>{}</a>::",
trail, component.as_slice());
if_ok!(write!(fmt.buf, "<a href='{}index.html'>{}</a>::",
trail, component.as_slice()));
}
write!(fmt.buf, "<a class='{}' href=''>{}</a></h1>",
shortty(it.item), it.item.name.get_ref().as_slice());
if_ok!(write!(fmt.buf, "<a class='{}' href=''>{}</a></h1>",
shortty(it.item), it.item.name.get_ref().as_slice()));
match it.item.inner {
clean::ModuleItem(ref m) => item_module(fmt.buf, it.cx,
@@ -867,7 +867,7 @@ fn fmt(it: &Item<'a>, fmt: &mut fmt::Formatter) {
clean::StructItem(ref s) => item_struct(fmt.buf, it.item, s),
clean::EnumItem(ref e) => item_enum(fmt.buf, it.item, e),
clean::TypedefItem(ref t) => item_typedef(fmt.buf, it.item, t),
_ => {}
_ => Ok(())
}
}
}
@@ -903,18 +903,19 @@ fn shorter<'a>(s: Option<&'a str>) -> &'a str {
}
}
fn document(w: &mut Writer, item: &clean::Item) {
fn document(w: &mut Writer, item: &clean::Item) -> fmt::Result {
match item.doc_value() {
Some(s) => {
write!(w, "<div class='docblock'>{}</div>", Markdown(s));
if_ok!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
}
None => {}
}
Ok(())
}
fn item_module(w: &mut Writer, cx: &Context,
item: &clean::Item, items: &[clean::Item]) {
document(w, item);
item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
if_ok!(document(w, item));
debug!("{:?}", items);
let mut indices = vec::from_fn(items.len(), |i| i);
@@ -965,10 +966,10 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
let myty = shortty(myitem);
if myty != curty {
if curty != "" {
write!(w, "</table>");
if_ok!(write!(w, "</table>"));
}
curty = myty;
write!(w, "<h2>{}</h2>\n<table>", match myitem.inner {
if_ok!(write!(w, "<h2>{}</h2>\n<table>", match myitem.inner {
clean::ModuleItem(..) => "Modules",
clean::StructItem(..) => "Structs",
clean::EnumItem(..) => "Enums",
@@ -984,24 +985,26 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
clean::VariantItem(..) => "Variants",
clean::ForeignFunctionItem(..) => "Foreign Functions",
clean::ForeignStaticItem(..) => "Foreign Statics",
});
}));
}
match myitem.inner {
clean::StaticItem(ref s) | clean::ForeignStaticItem(ref s) => {
struct Initializer<'a>(&'a str);
impl<'a> fmt::Show for Initializer<'a> {
fn fmt(s: &Initializer<'a>, f: &mut fmt::Formatter) {
fn fmt(s: &Initializer<'a>,
f: &mut fmt::Formatter) -> fmt::Result {
let Initializer(s) = *s;
if s.len() == 0 { return; }
write!(f.buf, "<code> = </code>");
if s.len() == 0 { return Ok(()); }
if_ok!(write!(f.buf, "<code> = </code>"));
let tag = if s.contains("\n") { "pre" } else { "code" };
write!(f.buf, "<{tag}>{}</{tag}>",
s.as_slice(), tag=tag);
if_ok!(write!(f.buf, "<{tag}>{}</{tag}>",
s.as_slice(), tag=tag));
Ok(())
}
}
write!(w, "
if_ok!(write!(w, "
<tr>
<td><code>{}static {}: {}</code>{}</td>
<td class='docblock'>{}&nbsp;</td>
@@ -1011,27 +1014,27 @@ fn fmt(s: &Initializer<'a>, f: &mut fmt::Formatter) {
*myitem.name.get_ref(),
s.type_,
Initializer(s.expr),
Markdown(blank(myitem.doc_value())));
Markdown(blank(myitem.doc_value()))));
}
clean::ViewItemItem(ref item) => {
match item.inner {
clean::ExternMod(ref name, ref src, _) => {
write!(w, "<tr><td><code>extern mod {}",
name.as_slice());
if_ok!(write!(w, "<tr><td><code>extern mod {}",
name.as_slice()));
match *src {
Some(ref src) => write!(w, " = \"{}\"",
src.as_slice()),
Some(ref src) => if_ok!(write!(w, " = \"{}\"",
src.as_slice())),
None => {}
}
write!(w, ";</code></td></tr>");
if_ok!(write!(w, ";</code></td></tr>"));
}
clean::Import(ref imports) => {
for import in imports.iter() {
write!(w, "<tr><td><code>{}{}</code></td></tr>",
VisSpace(myitem.visibility),
*import);
if_ok!(write!(w, "<tr><td><code>{}{}</code></td></tr>",
VisSpace(myitem.visibility),
*import));
}
}
}
@@ -1040,7 +1043,7 @@ fn fmt(s: &Initializer<'a>, f: &mut fmt::Formatter) {
_ => {
if myitem.name.is_none() { continue }
write!(w, "
if_ok!(write!(w, "
<tr>
<td><a class='{class}' href='{href}'
title='{title}'>{}</a></td>
@@ -1051,24 +1054,26 @@ fn fmt(s: &Initializer<'a>, f: &mut fmt::Formatter) {
Markdown(shorter(myitem.doc_value())),
class = shortty(myitem),
href = item_path(myitem),
title = full_path(cx, myitem));
title = full_path(cx, myitem)));
}
}
}
write!(w, "</table>");
write!(w, "</table>")
}
fn item_function(w: &mut Writer, it: &clean::Item, f: &clean::Function) {
write!(w, "<pre class='fn'>{vis}{purity}fn {name}{generics}{decl}</pre>",
fn item_function(w: &mut Writer, it: &clean::Item,
f: &clean::Function) -> fmt::Result {
if_ok!(write!(w, "<pre class='fn'>{vis}{purity}fn {name}{generics}{decl}</pre>",
vis = VisSpace(it.visibility),
purity = PuritySpace(f.purity),
name = it.name.get_ref().as_slice(),
generics = f.generics,
decl = f.decl);
document(w, it);
decl = f.decl));
document(w, it)
}
fn item_trait(w: &mut Writer, it: &clean::Item, t: &clean::Trait) {
fn item_trait(w: &mut Writer, it: &clean::Item,
t: &clean::Trait) -> fmt::Result {
let mut parents = ~"";
if t.parents.len() > 0 {
parents.push_str(": ");
@@ -1079,99 +1084,102 @@ fn item_trait(w: &mut Writer, it: &clean::Item, t: &clean::Trait) {
}
// Output the trait definition
write!(w, "<pre class='trait'>{}trait {}{}{} ",
VisSpace(it.visibility),
it.name.get_ref().as_slice(),
t.generics,
parents);
if_ok!(write!(w, "<pre class='trait'>{}trait {}{}{} ",
VisSpace(it.visibility),
it.name.get_ref().as_slice(),
t.generics,
parents));
let required = t.methods.iter().filter(|m| m.is_req()).to_owned_vec();
let provided = t.methods.iter().filter(|m| !m.is_req()).to_owned_vec();
if t.methods.len() == 0 {
write!(w, "\\{ \\}");
if_ok!(write!(w, "\\{ \\}"));
} else {
write!(w, "\\{\n");
if_ok!(write!(w, "\\{\n"));
for m in required.iter() {
write!(w, " ");
render_method(w, m.item(), true);
write!(w, ";\n");
if_ok!(write!(w, " "));
if_ok!(render_method(w, m.item(), true));
if_ok!(write!(w, ";\n"));
}
if required.len() > 0 && provided.len() > 0 {
w.write("\n".as_bytes());
if_ok!(w.write("\n".as_bytes()));
}
for m in provided.iter() {
write!(w, " ");
render_method(w, m.item(), true);
write!(w, " \\{ ... \\}\n");
if_ok!(write!(w, " "));
if_ok!(render_method(w, m.item(), true));
if_ok!(write!(w, " \\{ ... \\}\n"));
}
write!(w, "\\}");
if_ok!(write!(w, "\\}"));
}
write!(w, "</pre>");
if_ok!(write!(w, "</pre>"));
// Trait documentation
document(w, it);
if_ok!(document(w, it));
fn meth(w: &mut Writer, m: &clean::TraitMethod) {
write!(w, "<h3 id='{}.{}' class='method'><code>",
shortty(m.item()),
*m.item().name.get_ref());
render_method(w, m.item(), false);
write!(w, "</code></h3>");
document(w, m.item());
fn meth(w: &mut Writer, m: &clean::TraitMethod) -> fmt::Result {
if_ok!(write!(w, "<h3 id='{}.{}' class='method'><code>",
shortty(m.item()),
*m.item().name.get_ref()));
if_ok!(render_method(w, m.item(), false));
if_ok!(write!(w, "</code></h3>"));
if_ok!(document(w, m.item()));
Ok(())
}
// Output the documentation for each function individually
if required.len() > 0 {
write!(w, "
if_ok!(write!(w, "
<h2 id='required-methods'>Required Methods</h2>
<div class='methods'>
");
"));
for m in required.iter() {
meth(w, *m);
if_ok!(meth(w, *m));
}
write!(w, "</div>");
if_ok!(write!(w, "</div>"));
}
if provided.len() > 0 {
write!(w, "
if_ok!(write!(w, "
<h2 id='provided-methods'>Provided Methods</h2>
<div class='methods'>
");
"));
for m in provided.iter() {
meth(w, *m);
if_ok!(meth(w, *m));
}
write!(w, "</div>");
if_ok!(write!(w, "</div>"));
}
local_data::get(cache_key, |cache| {
let cache = cache.unwrap().get();
match cache.implementors.find(&it.id) {
Some(implementors) => {
write!(w, "
if_ok!(write!(w, "
<h2 id='implementors'>Implementors</h2>
<ul class='item-list'>
");
"));
for i in implementors.iter() {
match *i {
PathType(ref ty) => {
write!(w, "<li><code>{}</code></li>", *ty);
if_ok!(write!(w, "<li><code>{}</code></li>", *ty));
}
OtherType(ref generics, ref trait_, ref for_) => {
write!(w, "<li><code>impl{} {} for {}</code></li>",
*generics, *trait_, *for_);
if_ok!(write!(w, "<li><code>impl{} {} for {}</code></li>",
*generics, *trait_, *for_));
}
}
}
write!(w, "</ul>");
if_ok!(write!(w, "</ul>"));
}
None => {}
}
Ok(())
})
}
fn render_method(w: &mut Writer, meth: &clean::Item, withlink: bool) {
fn render_method(w: &mut Writer, meth: &clean::Item,
withlink: bool) -> fmt::Result {
fn fun(w: &mut Writer, it: &clean::Item, purity: ast::Purity,
g: &clean::Generics, selfty: &clean::SelfTy, d: &clean::FnDecl,
withlink: bool) {
withlink: bool) -> fmt::Result {
write!(w, "{}fn {withlink, select,
true{<a href='\\#{ty}.{name}'
class='fnname'>{name}</a>}
@@ -1185,118 +1193,125 @@ fn fun(w: &mut Writer, it: &clean::Item, purity: ast::Purity,
name = it.name.get_ref().as_slice(),
generics = *g,
decl = Method(selfty, d),
withlink = if withlink {"true"} else {"false"});
withlink = if withlink {"true"} else {"false"})
}
match meth.inner {
clean::TyMethodItem(ref m) => {
fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink);
fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
}
clean::MethodItem(ref m) => {
fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink);
fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
}
_ => unreachable!()
}
}
fn item_struct(w: &mut Writer, it: &clean::Item, s: &clean::Struct) {
write!(w, "<pre class='struct'>");
render_struct(w, it, Some(&s.generics), s.struct_type, s.fields,
s.fields_stripped, "", true);
write!(w, "</pre>");
fn item_struct(w: &mut Writer, it: &clean::Item,
s: &clean::Struct) -> fmt::Result {
if_ok!(write!(w, "<pre class='struct'>"));
if_ok!(render_struct(w, it, Some(&s.generics), s.struct_type, s.fields,
s.fields_stripped, "", true));
if_ok!(write!(w, "</pre>"));
document(w, it);
if_ok!(document(w, it));
match s.struct_type {
doctree::Plain if s.fields.len() > 0 => {
write!(w, "<h2 class='fields'>Fields</h2>\n<table>");
if_ok!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
for field in s.fields.iter() {
write!(w, "<tr><td id='structfield.{name}'>\
<code>{name}</code></td><td>",
name = field.name.get_ref().as_slice());
document(w, field);
write!(w, "</td></tr>");
if_ok!(write!(w, "<tr><td id='structfield.{name}'>\
<code>{name}</code></td><td>",
name = field.name.get_ref().as_slice()));
if_ok!(document(w, field));
if_ok!(write!(w, "</td></tr>"));
}
write!(w, "</table>");
if_ok!(write!(w, "</table>"));
}
_ => {}
}
render_methods(w, it);
render_methods(w, it)
}
fn item_enum(w: &mut Writer, it: &clean::Item, e: &clean::Enum) {
write!(w, "<pre class='enum'>{}enum {}{}",
VisSpace(it.visibility),
it.name.get_ref().as_slice(),
e.generics);
fn item_enum(w: &mut Writer, it: &clean::Item, e: &clean::Enum) -> fmt::Result {
if_ok!(write!(w, "<pre class='enum'>{}enum {}{}",
VisSpace(it.visibility),
it.name.get_ref().as_slice(),
e.generics));
if e.variants.len() == 0 && !e.variants_stripped {
write!(w, " \\{\\}");
if_ok!(write!(w, " \\{\\}"));
} else {
write!(w, " \\{\n");
if_ok!(write!(w, " \\{\n"));
for v in e.variants.iter() {
write!(w, " ");
if_ok!(write!(w, " "));
let name = v.name.get_ref().as_slice();
match v.inner {
clean::VariantItem(ref var) => {
match var.kind {
clean::CLikeVariant => write!(w, "{}", name),
clean::CLikeVariant => if_ok!(write!(w, "{}", name)),
clean::TupleVariant(ref tys) => {
write!(w, "{}(", name);
if_ok!(write!(w, "{}(", name));
for (i, ty) in tys.iter().enumerate() {
if i > 0 { write!(w, ", ") }
write!(w, "{}", *ty);
if i > 0 {
if_ok!(write!(w, ", "))
}
if_ok!(write!(w, "{}", *ty));
}
write!(w, ")");
if_ok!(write!(w, ")"));
}
clean::StructVariant(ref s) => {
render_struct(w, v, None, s.struct_type, s.fields,
s.fields_stripped, " ", false);
if_ok!(render_struct(w, v, None, s.struct_type,
s.fields, s.fields_stripped,
" ", false));
}
}
}
_ => unreachable!()
}
write!(w, ",\n");
if_ok!(write!(w, ",\n"));
}
if e.variants_stripped {
write!(w, " // some variants omitted\n");
if_ok!(write!(w, " // some variants omitted\n"));
}
write!(w, "\\}");
if_ok!(write!(w, "\\}"));
}
write!(w, "</pre>");
if_ok!(write!(w, "</pre>"));
document(w, it);
if_ok!(document(w, it));
if e.variants.len() > 0 {
write!(w, "<h2 class='variants'>Variants</h2>\n<table>");
if_ok!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>"));
for variant in e.variants.iter() {
write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>",
name = variant.name.get_ref().as_slice());
document(w, variant);
if_ok!(write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>",
name = variant.name.get_ref().as_slice()));
if_ok!(document(w, variant));
match variant.inner {
clean::VariantItem(ref var) => {
match var.kind {
clean::StructVariant(ref s) => {
write!(w, "<h3 class='fields'>Fields</h3>\n<table>");
if_ok!(write!(w, "<h3 class='fields'>Fields</h3>\n
<table>"));
for field in s.fields.iter() {
write!(w, "<tr><td id='variant.{v}.field.{f}'>\
<code>{f}</code></td><td>",
v = variant.name.get_ref().as_slice(),
f = field.name.get_ref().as_slice());
document(w, field);
write!(w, "</td></tr>");
if_ok!(write!(w, "<tr><td \
id='variant.{v}.field.{f}'>\
<code>{f}</code></td><td>",
v = variant.name.get_ref().as_slice(),
f = field.name.get_ref().as_slice()));
if_ok!(document(w, field));
if_ok!(write!(w, "</td></tr>"));
}
write!(w, "</table>");
if_ok!(write!(w, "</table>"));
}
_ => ()
}
}
_ => ()
}
write!(w, "</td></tr>");
if_ok!(write!(w, "</td></tr>"));
}
write!(w, "</table>");
if_ok!(write!(w, "</table>"));
}
render_methods(w, it);
if_ok!(render_methods(w, it));
Ok(())
}
fn render_struct(w: &mut Writer, it: &clean::Item,
@@ -1305,54 +1320,59 @@ fn render_struct(w: &mut Writer, it: &clean::Item,
fields: &[clean::Item],
fields_stripped: bool,
tab: &str,
structhead: bool) {
write!(w, "{}{}{}",
VisSpace(it.visibility),
if structhead {"struct "} else {""},
it.name.get_ref().as_slice());
structhead: bool) -> fmt::Result {
if_ok!(write!(w, "{}{}{}",
VisSpace(it.visibility),
if structhead {"struct "} else {""},
it.name.get_ref().as_slice()));
match g {
Some(g) => write!(w, "{}", *g),
Some(g) => if_ok!(write!(w, "{}", *g)),
None => {}
}
match ty {
doctree::Plain => {
write!(w, " \\{\n{}", tab);
if_ok!(write!(w, " \\{\n{}", tab));
for field in fields.iter() {
match field.inner {
clean::StructFieldItem(ref ty) => {
write!(w, " {}{}: {},\n{}",
VisSpace(field.visibility),
field.name.get_ref().as_slice(),
ty.type_,
tab);
if_ok!(write!(w, " {}{}: {},\n{}",
VisSpace(field.visibility),
field.name.get_ref().as_slice(),
ty.type_,
tab));
}
_ => unreachable!()
}
}
if fields_stripped {
write!(w, " // some fields omitted\n{}", tab);
if_ok!(write!(w, " // some fields omitted\n{}", tab));
}
write!(w, "\\}");
if_ok!(write!(w, "\\}"));
}
doctree::Tuple | doctree::Newtype => {
write!(w, "(");
if_ok!(write!(w, "("));
for (i, field) in fields.iter().enumerate() {
if i > 0 { write!(w, ", ") }
if i > 0 {
if_ok!(write!(w, ", "));
}
match field.inner {
clean::StructFieldItem(ref field) => {
write!(w, "{}", field.type_);
if_ok!(write!(w, "{}", field.type_));
}
_ => unreachable!()
}
}
write!(w, ");");
if_ok!(write!(w, ");"));
}
doctree::Unit => {
if_ok!(write!(w, ";"));
}
doctree::Unit => { write!(w, ";"); }
}
Ok(())
}
fn render_methods(w: &mut Writer, it: &clean::Item) {
fn render_methods(w: &mut Writer, it: &clean::Item) -> fmt::Result {
local_data::get(cache_key, |cache| {
let c = cache.unwrap().get();
match c.impls.find(&it.id) {
@@ -1367,29 +1387,31 @@ fn render_methods(w: &mut Writer, it: &clean::Item) {
let traits = traits.to_owned_vec();
if non_trait.len() > 0 {
write!(w, "<h2 id='methods'>Methods</h2>");
if_ok!(write!(w, "<h2 id='methods'>Methods</h2>"));
for &(ref i, ref dox) in non_trait.move_iter() {
render_impl(w, i, dox);
if_ok!(render_impl(w, i, dox));
}
}
if traits.len() > 0 {
write!(w, "<h2 id='implementations'>Trait \
Implementations</h2>");
if_ok!(write!(w, "<h2 id='implementations'>Trait \
Implementations</h2>"));
for &(ref i, ref dox) in traits.move_iter() {
render_impl(w, i, dox);
if_ok!(render_impl(w, i, dox));
}
}
}
None => {}
}
Ok(())
})
}
fn render_impl(w: &mut Writer, i: &clean::Impl, dox: &Option<~str>) {
write!(w, "<h3 class='impl'><code>impl{} ", i.generics);
fn render_impl(w: &mut Writer, i: &clean::Impl,
dox: &Option<~str>) -> fmt::Result {
if_ok!(write!(w, "<h3 class='impl'><code>impl{} ", i.generics));
let trait_id = match i.trait_ {
Some(ref ty) => {
write!(w, "{} for ", *ty);
if_ok!(write!(w, "{} for ", *ty));
match *ty {
clean::ResolvedPath { id, .. } => Some(id),
_ => None,
@@ -1397,32 +1419,32 @@ fn render_impl(w: &mut Writer, i: &clean::Impl, dox: &Option<~str>) {
}
None => None
};
write!(w, "{}</code></h3>", i.for_);
if_ok!(write!(w, "{}</code></h3>", i.for_));
match *dox {
Some(ref dox) => {
write!(w, "<div class='docblock'>{}</div>",
Markdown(dox.as_slice()));
if_ok!(write!(w, "<div class='docblock'>{}</div>",
Markdown(dox.as_slice())));
}
None => {}
}
fn docmeth(w: &mut Writer, item: &clean::Item) -> bool {
write!(w, "<h4 id='method.{}' class='method'><code>",
*item.name.get_ref());
render_method(w, item, false);
write!(w, "</code></h4>\n");
fn docmeth(w: &mut Writer, item: &clean::Item) -> io::IoResult<bool> {
if_ok!(write!(w, "<h4 id='method.{}' class='method'><code>",
*item.name.get_ref()));
if_ok!(render_method(w, item, false));
if_ok!(write!(w, "</code></h4>\n"));
match item.doc_value() {
Some(s) => {
write!(w, "<div class='docblock'>{}</div>", Markdown(s));
true
if_ok!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
Ok(true)
}
None => false
None => Ok(false)
}
}
write!(w, "<div class='methods'>");
if_ok!(write!(w, "<div class='methods'>"));
for meth in i.methods.iter() {
if docmeth(w, meth) {
if if_ok!(docmeth(w, meth)) {
continue
}
@@ -1431,7 +1453,7 @@ fn docmeth(w: &mut Writer, item: &clean::Item) -> bool {
None => continue,
Some(id) => id,
};
local_data::get(cache_key, |cache| {
if_ok!(local_data::get(cache_key, |cache| {
let cache = cache.unwrap().get();
match cache.traits.find(&trait_id) {
Some(t) => {
@@ -1440,9 +1462,9 @@ fn docmeth(w: &mut Writer, item: &clean::Item) -> bool {
Some(method) => {
match method.item().doc_value() {
Some(s) => {
write!(w,
"<div class='docblock'>{}</div>",
Markdown(s));
if_ok!(write!(w,
"<div class='docblock'>{}</div>",
Markdown(s)));
}
None => {}
}
@@ -1452,7 +1474,8 @@ fn docmeth(w: &mut Writer, item: &clean::Item) -> bool {
}
None => {}
}
})
Ok(())
}))
}
// If we've implemented a trait, then also emit documentation for all
@@ -1460,7 +1483,7 @@ fn docmeth(w: &mut Writer, item: &clean::Item) -> bool {
match trait_id {
None => {}
Some(id) => {
local_data::get(cache_key, |cache| {
if_ok!(local_data::get(cache_key, |cache| {
let cache = cache.unwrap().get();
match cache.traits.find(&id) {
Some(t) => {
@@ -1471,50 +1494,56 @@ fn docmeth(w: &mut Writer, item: &clean::Item) -> bool {
None => {}
}
docmeth(w, method.item());
if_ok!(docmeth(w, method.item()));
}
}
None => {}
}
})
Ok(())
}))
}
}
write!(w, "</div>");
if_ok!(write!(w, "</div>"));
Ok(())
}
fn item_typedef(w: &mut Writer, it: &clean::Item, t: &clean::Typedef) {
write!(w, "<pre class='typedef'>type {}{} = {};</pre>",
it.name.get_ref().as_slice(),
t.generics,
t.type_);
fn item_typedef(w: &mut Writer, it: &clean::Item,
t: &clean::Typedef) -> fmt::Result {
if_ok!(write!(w, "<pre class='typedef'>type {}{} = {};</pre>",
it.name.get_ref().as_slice(),
t.generics,
t.type_));
document(w, it);
document(w, it)
}
impl<'a> fmt::Show for Sidebar<'a> {
fn fmt(s: &Sidebar<'a>, fmt: &mut fmt::Formatter) {
fn fmt(s: &Sidebar<'a>, fmt: &mut fmt::Formatter) -> fmt::Result {
let cx = s.cx;
let it = s.item;
write!(fmt.buf, "<p class='location'>");
if_ok!(write!(fmt.buf, "<p class='location'>"));
let len = cx.current.len() - if it.is_mod() {1} else {0};
for (i, name) in cx.current.iter().take(len).enumerate() {
if i > 0 { write!(fmt.buf, "&\\#8203;::") }
write!(fmt.buf, "<a href='{}index.html'>{}</a>",
cx.root_path.slice_to((cx.current.len() - i - 1) * 3), *name);
if i > 0 {
if_ok!(write!(fmt.buf, "&\\#8203;::"));
}
if_ok!(write!(fmt.buf, "<a href='{}index.html'>{}</a>",
cx.root_path.slice_to((cx.current.len() - i - 1) * 3),
*name));
}
write!(fmt.buf, "</p>");
if_ok!(write!(fmt.buf, "</p>"));
fn block(w: &mut Writer, short: &str, longty: &str,
cur: &clean::Item, cx: &Context) {
cur: &clean::Item, cx: &Context) -> fmt::Result {
let items = match cx.sidebar.find_equiv(&short) {
Some(items) => items.as_slice(),
None => return
None => return Ok(())
};
write!(w, "<div class='block {}'><h2>{}</h2>", short, longty);
if_ok!(write!(w, "<div class='block {}'><h2>{}</h2>", short, longty));
for item in items.iter() {
let class = if cur.name.get_ref() == item &&
short == shortty(cur) { "current" } else { "" };
write!(w, "<a class='{ty} {class}' href='{curty, select,
if_ok!(write!(w, "<a class='{ty} {class}' href='{curty, select,
mod{../}
other{}
}{tysel, select,
@@ -1525,16 +1554,18 @@ fn block(w: &mut Writer, short: &str, longty: &str,
tysel = short,
class = class,
curty = shortty(cur),
name = item.as_slice());
name = item.as_slice()));
}
write!(w, "</div>");
if_ok!(write!(w, "</div>"));
Ok(())
}
block(fmt.buf, "mod", "Modules", it, cx);
block(fmt.buf, "struct", "Structs", it, cx);
block(fmt.buf, "enum", "Enums", it, cx);
block(fmt.buf, "trait", "Traits", it, cx);
block(fmt.buf, "fn", "Functions", it, cx);
if_ok!(block(fmt.buf, "mod", "Modules", it, cx));
if_ok!(block(fmt.buf, "struct", "Structs", it, cx));
if_ok!(block(fmt.buf, "enum", "Enums", it, cx));
if_ok!(block(fmt.buf, "trait", "Traits", it, cx));
if_ok!(block(fmt.buf, "fn", "Functions", it, cx));
Ok(())
}
}
@@ -1557,7 +1588,7 @@ fn build_sidebar(m: &clean::Module) -> HashMap<~str, ~[~str]> {
}
impl<'a> fmt::Show for Source<'a> {
fn fmt(s: &Source<'a>, fmt: &mut fmt::Formatter) {
fn fmt(s: &Source<'a>, fmt: &mut fmt::Formatter) -> fmt::Result {
let Source(s) = *s;
let lines = s.lines().len();
let mut cols = 0;
@@ -1566,13 +1597,14 @@ fn fmt(s: &Source<'a>, fmt: &mut fmt::Formatter) {
cols += 1;
tmp /= 10;
}
write!(fmt.buf, "<pre class='line-numbers'>");
if_ok!(write!(fmt.buf, "<pre class='line-numbers'>"));
for i in range(1, lines + 1) {
write!(fmt.buf, "<span id='{0:u}'>{0:1$u}</span>\n", i, cols);
if_ok!(write!(fmt.buf, "<span id='{0:u}'>{0:1$u}</span>\n", i, cols));
}
write!(fmt.buf, "</pre>");
write!(fmt.buf, "<pre class='rust'>");
write!(fmt.buf, "{}", Escape(s.as_slice()));
write!(fmt.buf, "</pre>");
if_ok!(write!(fmt.buf, "</pre>"));
if_ok!(write!(fmt.buf, "<pre class='rust'>"));
if_ok!(write!(fmt.buf, "{}", Escape(s.as_slice())));
if_ok!(write!(fmt.buf, "</pre>"));
Ok(())
}
}
+15 -7
View File
@@ -162,10 +162,16 @@ pub fn main_args(args: &[~str]) -> int {
let output = matches.opt_str("o").map(|s| Path::new(s));
match matches.opt_str("w") {
Some(~"html") | None => {
html::render::run(crate, output.unwrap_or(Path::new("doc")))
match html::render::run(crate, output.unwrap_or(Path::new("doc"))) {
Ok(()) => {}
Err(e) => fail!("failed to generate documentation: {}", e),
}
}
Some(~"json") => {
json_output(crate, res, output.unwrap_or(Path::new("doc.json")))
match json_output(crate, res, output.unwrap_or(Path::new("doc.json"))) {
Ok(()) => {}
Err(e) => fail!("failed to write json: {}", e),
}
}
Some(s) => {
println!("unknown output format: {}", s);
@@ -276,8 +282,8 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output {
/// run over the deserialized output.
fn json_input(input: &str) -> Result<Output, ~str> {
let mut input = match File::open(&Path::new(input)) {
Some(f) => f,
None => return Err(format!("couldn't open {} for reading", input)),
Ok(f) => f,
Err(e) => return Err(format!("couldn't open {}: {}", input, e)),
};
match json::from_reader(&mut input) {
Err(s) => Err(s.to_str()),
@@ -312,7 +318,8 @@ fn json_input(input: &str) -> Result<Output, ~str> {
/// Outputs the crate/plugin json as a giant json blob at the specified
/// destination.
fn json_output(crate: clean::Crate, res: ~[plugins::PluginJson], dst: Path) {
fn json_output(crate: clean::Crate, res: ~[plugins::PluginJson],
dst: Path) -> io::IoResult<()> {
// {
// "schema": version,
// "crate": { parsed crate ... },
@@ -340,6 +347,7 @@ fn json_output(crate: clean::Crate, res: ~[plugins::PluginJson], dst: Path) {
json.insert(~"crate", crate_json);
json.insert(~"plugins", json::Object(plugins_json));
let mut file = File::create(&dst).unwrap();
json::Object(json).to_writer(&mut file);
let mut file = if_ok!(File::create(&dst));
if_ok!(json::Object(json).to_writer(&mut file));
Ok(())
}
+2 -2
View File
@@ -127,8 +127,8 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>) {
let exe = outdir.path().join("rust_out");
let out = run::process_output(exe.as_str().unwrap(), []);
match out {
None => fail!("couldn't run the test"),
Some(out) => {
Err(e) => fail!("couldn't run the test: {}", e),
Ok(out) => {
if !out.status.success() {
fail!("test executable failed:\n{}",
str::from_utf8(out.error));
+5 -4
View File
@@ -140,9 +140,9 @@ pub fn readdir(loop_: &Loop, path: &CString, flags: c_int)
let mut paths = ~[];
let path = CString::new(path.with_ref(|p| p), false);
let parent = Path::new(path);
c_str::from_c_multistring(req.get_ptr() as *libc::c_char,
Some(req.get_result() as uint),
|rel| {
let _ = c_str::from_c_multistring(req.get_ptr() as *libc::c_char,
Some(req.get_result() as uint),
|rel| {
let p = rel.as_bytes();
paths.push(parent.join(p.slice_to(rel.len())));
});
@@ -378,7 +378,8 @@ fn drop(&mut self) {
rtio::CloseAsynchronously => {
unsafe {
let req = uvll::malloc_req(uvll::UV_FS);
uvll::uv_fs_close(self.loop_.handle, req, self.fd, close_cb);
assert_eq!(uvll::uv_fs_close(self.loop_.handle, req,
self.fd, close_cb), 0);
}
extern fn close_cb(req: *uvll::uv_fs_t) {
+2 -2
View File
@@ -176,7 +176,7 @@ fn test_homing_closes_correctly() {
});
let task = pool.task(TaskOpts::new(), proc() {
port.recv();
drop(port.recv());
});
pool.spawn_sched().send(sched::TaskFromFriend(task));
@@ -197,7 +197,7 @@ fn test_homing_read() {
let listener = UdpWatcher::bind(local_loop(), addr2);
chan.send((listener.unwrap(), addr1));
let mut listener = UdpWatcher::bind(local_loop(), addr1).unwrap();
listener.sendto([1, 2, 3, 4], addr2);
listener.sendto([1, 2, 3, 4], addr2).unwrap();
});
let task = pool.task(TaskOpts::new(), proc() {
+2 -2
View File
@@ -52,7 +52,7 @@ pub fn onetime(loop_: &mut Loop, f: proc()) {
let data = uvll::get_data_for_uv_handle(handle);
let f: ~proc() = cast::transmute(data);
(*f)();
uvll::uv_idle_stop(handle);
assert_eq!(uvll::uv_idle_stop(handle), 0);
uvll::uv_close(handle, close_cb);
}
}
@@ -122,7 +122,7 @@ fn call(&mut self) {
}
}
};
task.wake().map(|t| t.reawaken(true));
let _ = task.wake().map(|t| t.reawaken(true));
}
}
+3 -2
View File
@@ -40,6 +40,7 @@
#[crate_type = "dylib"];
#[feature(macro_rules)];
#[deny(unused_result, unused_must_use)];
#[cfg(test)] extern mod green;
@@ -207,7 +208,7 @@ fn wait_until_woken_after(slot: *mut Option<BlockedTask>, f: ||) {
fn wakeup(slot: &mut Option<BlockedTask>) {
assert!(slot.is_some());
slot.take_unwrap().wake().map(|t| t.reawaken(true));
let _ = slot.take_unwrap().wake().map(|t| t.reawaken(true));
}
pub struct Request {
@@ -276,7 +277,7 @@ pub fn new() -> Loop {
pub fn wrap(handle: *uvll::uv_loop_t) -> Loop { Loop { handle: handle } }
pub fn run(&mut self) {
unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) };
assert_eq!(unsafe { uvll::uv_run(self.handle, uvll::RUN_DEFAULT) }, 0);
}
pub fn close(&mut self) {
+6 -5
View File
@@ -33,14 +33,15 @@ pub fn dumb_println(args: &fmt::Arguments) {
struct Stderr;
impl io::Writer for Stderr {
fn write(&mut self, data: &[u8]) {
unsafe {
fn write(&mut self, data: &[u8]) -> io::IoResult<()> {
let _ = unsafe {
libc::write(libc::STDERR_FILENO,
data.as_ptr() as *libc::c_void,
data.len() as libc::size_t);
}
data.len() as libc::size_t)
};
Ok(()) // just ignore the errors
}
}
let mut w = Stderr;
fmt::writeln(&mut w as &mut io::Writer, args);
let _ = fmt::writeln(&mut w as &mut io::Writer, args);
}
+6 -6
View File
@@ -953,11 +953,11 @@ fn test_read_and_block() {
spawn(proc() {
let port2 = port.recv();
let mut stream = TcpWatcher::connect(local_loop(), addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
port2.recv();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
port2.recv();
});
@@ -1008,7 +1008,7 @@ fn test_simple_tcp_server_and_client_on_diff_threads() {
while stream.is_err() {
stream = TcpWatcher::connect(local_loop(), addr);
}
stream.unwrap().write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.unwrap().write([0, 1, 2, 3, 4, 5, 6, 7]).unwrap();
}
#[should_fail] #[test]
@@ -1028,7 +1028,7 @@ fn tcp_stream_fail_cleanup() {
let w = TcpListener::bind(local_loop(), addr).unwrap();
let mut w = w.listen().unwrap();
chan.send(());
w.accept();
drop(w.accept().unwrap());
});
port.recv();
let _w = TcpWatcher::connect(local_loop(), addr).unwrap();
+1 -1
View File
@@ -306,7 +306,7 @@ fn connect_fail() {
let p = PipeListener::bind(local_loop(), &path2.to_c_str()).unwrap();
let mut p = p.listen().unwrap();
chan.send(());
p.accept();
drop(p.accept().unwrap());
});
port.recv();
let _c = PipeWatcher::connect(local_loop(), &path.to_c_str()).unwrap();
+1 -1
View File
@@ -67,7 +67,7 @@ pub struct Queue {
loop {
match state.consumer.pop() {
mpsc::Data(Task(task)) => {
task.wake().map(|t| t.reawaken(true));
let _ = task.wake().map(|t| t.reawaken(true));
}
mpsc::Data(Increment) => unsafe {
if state.refcnt == 0 {
+1 -1
View File
@@ -86,7 +86,7 @@ fn closing_channel_during_drop_doesnt_kill_everything() {
chan);
spawn(proc() {
port.try_recv();
let _ = port.recv_opt();
});
// when we drop the SignalWatcher we're going to destroy the channel,
+9 -9
View File
@@ -138,11 +138,11 @@ fn period(&mut self, msecs: u64) -> Port<()> {
match timer.action.take_unwrap() {
WakeTask(task) => {
task.wake().map(|t| t.reawaken(true));
let _ = task.wake().map(|t| t.reawaken(true));
}
SendOnce(chan) => { chan.try_send(()); }
SendOnce(chan) => { let _ = chan.try_send(()); }
SendMany(chan, id) => {
chan.try_send(());
let _ = chan.try_send(());
// Note that the above operation could have performed some form of
// scheduling. This means that the timer may have decided to insert
@@ -246,7 +246,7 @@ fn closing_channel_during_drop_doesnt_kill_everything() {
let timer_port = timer.period(1000);
spawn(proc() {
timer_port.recv_opt();
let _ = timer_port.recv_opt();
});
// when we drop the TimerWatcher we're going to destroy the channel,
@@ -260,10 +260,10 @@ fn reset_doesnt_switch_tasks() {
let timer_port = timer.period(1000);
spawn(proc() {
timer_port.recv_opt();
let _ = timer_port.recv_opt();
});
timer.oneshot(1);
drop(timer.oneshot(1));
}
#[test]
fn reset_doesnt_switch_tasks2() {
@@ -272,7 +272,7 @@ fn reset_doesnt_switch_tasks2() {
let timer_port = timer.period(1000);
spawn(proc() {
timer_port.recv_opt();
let _ = timer_port.recv_opt();
});
timer.sleep(1);
@@ -299,7 +299,7 @@ fn sender_goes_away_period() {
#[test]
fn receiver_goes_away_oneshot() {
let mut timer1 = TimerWatcher::new(local_loop());
timer1.oneshot(1);
drop(timer1.oneshot(1));
let mut timer2 = TimerWatcher::new(local_loop());
// while sleeping, the prevous timer should fire and not have its
// callback do something terrible.
@@ -309,7 +309,7 @@ fn receiver_goes_away_oneshot() {
#[test]
fn receiver_goes_away_period() {
let mut timer1 = TimerWatcher::new(local_loop());
timer1.period(1);
drop(timer1.period(1));
let mut timer2 = TimerWatcher::new(local_loop());
// while sleeping, the prevous timer should fire and not have its
// callback do something terrible.
+1 -1
View File
@@ -71,7 +71,7 @@ fn drop(&mut self) {
// after the loop has been closed because during the closing of the loop
// the handle is required to be used apparently.
let handle = self.uvio.handle_pool.get_ref().handle();
self.uvio.handle_pool.take();
drop(self.uvio.handle_pool.take());
self.uvio.loop_.close();
unsafe { uvll::free_handle(handle) }
}
+1 -1
View File
@@ -1252,7 +1252,7 @@ fn no_runtime() {
spawn(proc() {
let _p = port;
});
task::try(proc() {
let _ = task::try(proc() {
chan.send(1);
});
}
+117 -110
View File
@@ -163,9 +163,10 @@
```rust
# use std;
# mod fmt { pub type Result = (); }
# struct T;
# trait SomeName<T> {
fn fmt(value: &T, f: &mut std::fmt::Formatter);
fn fmt(value: &T, f: &mut std::fmt::Formatter) -> fmt::Result;
# }
```
@@ -174,7 +175,14 @@
implementation to correctly adhere to the requested formatting parameters. The
values of these parameters will be listed in the fields of the `Formatter`
struct. In order to help with this, the `Formatter` struct also provides some
helper methods. An example of implementing the formatting traits would look
helper methods.
Additionally, the return value of this function is `fmt::Result` which is a
typedef to `Result<(), IoError>` (also known as `IoError<()>`). Formatting
implementations should ensure that they return errors from `write!` correctly
(propagating errors upward).
An example of implementing the formatting traits would look
like:
```rust
@@ -187,7 +195,7 @@ struct Vector2D {
}
impl fmt::Show for Vector2D {
fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) {
fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) -> fmt::Result {
// The `f.buf` value is of the type `&mut io::Writer`, which is what th
// write! macro is expecting. Note that this formatting ignores the
// various flags provided to format strings.
@@ -198,7 +206,7 @@ fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) {
// Different traits allow different forms of output of a type. The meaning of
// this format is to print the magnitude of a vector.
impl fmt::Binary for Vector2D {
fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) {
fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) -> fmt::Result {
let magnitude = (obj.x * obj.x + obj.y * obj.y) as f64;
let magnitude = magnitude.sqrt();
@@ -207,7 +215,7 @@ fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) {
// for details, and the function `pad` can be used to pad strings.
let decimals = f.precision.unwrap_or(3);
let string = f64::to_str_exact(magnitude, decimals);
f.pad_integral(string.as_bytes(), "", true);
f.pad_integral(string.as_bytes(), "", true)
}
}
@@ -242,6 +250,7 @@ fn main() {
actually invoking the `write` function defined in this module. Example usage is:
```rust
# #[allow(unused_must_use)];
use std::io;
let mut w = io::MemWriter::new();
@@ -468,16 +477,20 @@ fn main() {
*/
#[cfg(not(stage0))]
use prelude::*;
use cast;
use char::Char;
use container::Container;
use io::MemWriter;
use io;
use str;
use iter::{Iterator, range};
use num::Signed;
use option::{Option,Some,None};
use repr;
use result::{Ok, Err};
use str::StrSlice;
use str;
use util;
use vec::ImmutableVector;
use vec;
// NOTE this is just because the `prelude::*` import above includes
@@ -485,22 +498,11 @@ fn main() {
#[cfg(stage0)]
pub use Default = fmt::Show; // export required for `format!()` etc.
#[cfg(stage0)]
use container::Container;
#[cfg(stage0)]
use iter::{Iterator, range};
#[cfg(stage0)]
use option::{Option,Some,None};
#[cfg(stage0)]
use vec::ImmutableVector;
#[cfg(stage0)]
use str::StrSlice;
#[cfg(stage0)]
use num::Signed;
pub mod parse;
pub mod rt;
pub type Result = io::IoResult<()>;
/// A struct to represent both where to emit formatting strings to and how they
/// should be formatted. A mutable version of this is passed to all formatting
/// traits.
@@ -527,7 +529,7 @@ pub struct Formatter<'a> {
/// compile time it is ensured that the function and the value have the correct
/// types, and then this struct is used to canonicalize arguments to one type.
pub struct Argument<'a> {
priv formatter: extern "Rust" fn(&util::Void, &mut Formatter),
priv formatter: extern "Rust" fn(&util::Void, &mut Formatter) -> Result,
priv value: &'a util::Void,
}
@@ -561,50 +563,50 @@ pub struct Arguments<'a> {
/// to this trait. There is not an explicit way of selecting this trait to be
/// used for formatting, it is only if no other format is specified.
#[allow(missing_doc)]
pub trait Show { fn fmt(&Self, &mut Formatter); }
pub trait Show { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `b` character
#[allow(missing_doc)]
pub trait Bool { fn fmt(&Self, &mut Formatter); }
pub trait Bool { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `c` character
#[allow(missing_doc)]
pub trait Char { fn fmt(&Self, &mut Formatter); }
pub trait Char { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `i` and `d` characters
#[allow(missing_doc)]
pub trait Signed { fn fmt(&Self, &mut Formatter); }
pub trait Signed { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `u` character
#[allow(missing_doc)]
pub trait Unsigned { fn fmt(&Self, &mut Formatter); }
pub trait Unsigned { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `o` character
#[allow(missing_doc)]
pub trait Octal { fn fmt(&Self, &mut Formatter); }
pub trait Octal { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `b` character
#[allow(missing_doc)]
pub trait Binary { fn fmt(&Self, &mut Formatter); }
pub trait Binary { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `x` character
#[allow(missing_doc)]
pub trait LowerHex { fn fmt(&Self, &mut Formatter); }
pub trait LowerHex { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `X` character
#[allow(missing_doc)]
pub trait UpperHex { fn fmt(&Self, &mut Formatter); }
pub trait UpperHex { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `s` character
#[allow(missing_doc)]
pub trait String { fn fmt(&Self, &mut Formatter); }
pub trait String { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `?` character
#[allow(missing_doc)]
pub trait Poly { fn fmt(&Self, &mut Formatter); }
pub trait Poly { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `p` character
#[allow(missing_doc)]
pub trait Pointer { fn fmt(&Self, &mut Formatter); }
pub trait Pointer { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `f` character
#[allow(missing_doc)]
pub trait Float { fn fmt(&Self, &mut Formatter); }
pub trait Float { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `e` character
#[allow(missing_doc)]
pub trait LowerExp { fn fmt(&Self, &mut Formatter); }
pub trait LowerExp { fn fmt(&Self, &mut Formatter) -> Result; }
/// Format trait for the `E` character
#[allow(missing_doc)]
pub trait UpperExp { fn fmt(&Self, &mut Formatter); }
pub trait UpperExp { fn fmt(&Self, &mut Formatter) -> Result; }
// FIXME #11938 - UFCS would make us able call the above methods
// directly Show::show(x, fmt).
@@ -617,7 +619,7 @@ macro_rules! uniform_fn_call_workaround {
($( $name: ident, $trait_: ident; )*) => {
$(
#[doc(hidden)]
pub fn $name<T: $trait_>(x: &T, fmt: &mut Formatter) {
pub fn $name<T: $trait_>(x: &T, fmt: &mut Formatter) -> Result {
$trait_::fmt(x, fmt)
}
)*
@@ -653,21 +655,22 @@ pub fn $name<T: $trait_>(x: &T, fmt: &mut Formatter) {
/// # Example
///
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::fmt;
/// use std::io;
///
/// let w = &mut io::stdout() as &mut io::Writer;
/// format_args!(|args| { fmt::write(w, args) }, "Hello, {}!", "world");
/// format_args!(|args| { fmt::write(w, args); }, "Hello, {}!", "world");
/// ```
pub fn write(output: &mut io::Writer, args: &Arguments) {
pub fn write(output: &mut io::Writer, args: &Arguments) -> Result {
unsafe { write_unsafe(output, args.fmt, args.args) }
}
/// The `writeln` function takes the same arguments as `write`, except that it
/// will also write a newline (`\n`) character at the end of the format string.
pub fn writeln(output: &mut io::Writer, args: &Arguments) {
unsafe { write_unsafe(output, args.fmt, args.args) }
output.write(['\n' as u8]);
pub fn writeln(output: &mut io::Writer, args: &Arguments) -> Result {
let first = unsafe { write_unsafe(output, args.fmt, args.args) };
first.and_then(|()| output.write(['\n' as u8]))
}
/// The `write_unsafe` function takes an output stream, a precompiled format
@@ -692,7 +695,7 @@ pub fn writeln(output: &mut io::Writer, args: &Arguments) {
/// format string.
pub unsafe fn write_unsafe(output: &mut io::Writer,
fmt: &[rt::Piece],
args: &[Argument]) {
args: &[Argument]) -> Result {
let mut formatter = Formatter {
flags: 0,
width: None,
@@ -704,8 +707,9 @@ pub unsafe fn write_unsafe(output: &mut io::Writer,
curarg: args.iter(),
};
for piece in fmt.iter() {
formatter.run(piece, None);
if_ok!(formatter.run(piece, None));
}
Ok(())
}
/// The format function takes a precompiled format string and a list of
@@ -752,7 +756,7 @@ pub fn format(args: &Arguments) -> ~str {
/// format string.
pub unsafe fn format_unsafe(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
let mut output = MemWriter::new();
write_unsafe(&mut output as &mut io::Writer, fmt, args);
write_unsafe(&mut output as &mut io::Writer, fmt, args).unwrap();
return str::from_utf8_owned(output.unwrap()).unwrap();
}
@@ -762,10 +766,10 @@ impl<'a> Formatter<'a> {
// at runtime. This consumes all of the compile-time statics generated by
// the format! syntax extension.
fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) {
fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) -> Result {
match *piece {
rt::String(s) => { self.buf.write(s.as_bytes()); }
rt::CurrentArgument(()) => { self.buf.write(cur.unwrap().as_bytes()); }
rt::String(s) => self.buf.write(s.as_bytes()),
rt::CurrentArgument(()) => self.buf.write(cur.unwrap().as_bytes()),
rt::Argument(ref arg) => {
// Fill in the format parameters into the formatter
self.fill = arg.format.fill;
@@ -782,8 +786,8 @@ fn run(&mut self, piece: &rt::Piece, cur: Option<&str>) {
// Then actually do some printing
match arg.method {
None => { (value.formatter)(value.value, self); }
Some(ref method) => { self.execute(*method, value); }
None => (value.formatter)(value.value, self),
Some(ref method) => self.execute(*method, value)
}
}
}
@@ -804,7 +808,7 @@ fn getcount(&mut self, cnt: &rt::Count) -> Option<uint> {
}
}
fn execute(&mut self, method: &rt::Method, arg: Argument) {
fn execute(&mut self, method: &rt::Method, arg: Argument) -> Result {
match *method {
// Pluralization is selection upon a numeric value specified as the
// parameter.
@@ -847,7 +851,7 @@ fn execute(&mut self, method: &rt::Method, arg: Argument) {
}
}
self.runplural(value, *default);
self.runplural(value, *default)
}
// Select is just a matching against the string specified.
@@ -860,24 +864,26 @@ fn execute(&mut self, method: &rt::Method, arg: Argument) {
for s in selectors.iter() {
if s.selector == value {
for piece in s.result.iter() {
self.run(piece, Some(value));
if_ok!(self.run(piece, Some(value)));
}
return;
return Ok(());
}
}
for piece in default.iter() {
self.run(piece, Some(value));
if_ok!(self.run(piece, Some(value)));
}
Ok(())
}
}
}
fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) {
fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) -> Result {
::uint::to_str_bytes(value, 10, |buf| {
let valuestr = str::from_utf8(buf).unwrap();
for piece in pieces.iter() {
self.run(piece, Some(valuestr));
if_ok!(self.run(piece, Some(valuestr)));
}
Ok(())
})
}
@@ -899,7 +905,7 @@ fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) {
/// This function will correctly account for the flags provided as well as
/// the minimum width. It will not take precision into account.
pub fn pad_integral(&mut self, s: &[u8], alternate_prefix: &str,
positive: bool) {
positive: bool) -> Result {
use fmt::parse::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
let mut actual_len = s.len();
@@ -916,32 +922,32 @@ pub fn pad_integral(&mut self, s: &[u8], alternate_prefix: &str,
let sign = |this: &mut Formatter| {
if !signprinted {
if this.flags & 1 << (FlagSignPlus as uint) != 0 && positive {
this.buf.write(['+' as u8]);
if_ok!(this.buf.write(['+' as u8]));
} else if !positive {
this.buf.write(['-' as u8]);
if_ok!(this.buf.write(['-' as u8]));
}
if this.flags & 1 << (FlagAlternate as uint) != 0 {
this.buf.write(alternate_prefix.as_bytes());
if_ok!(this.buf.write(alternate_prefix.as_bytes()));
}
signprinted = true;
}
Ok(())
};
let emit = |this: &mut Formatter| {
sign(this);
this.buf.write(s);
sign(this).and_then(|()| this.buf.write(s))
};
match self.width {
None => { emit(self) }
Some(min) if actual_len >= min => { emit(self) }
None => emit(self),
Some(min) if actual_len >= min => emit(self),
Some(min) => {
if self.flags & 1 << (FlagSignAwareZeroPad as uint) != 0 {
self.fill = '0';
sign(self);
if_ok!(sign(self));
}
self.with_padding(min - actual_len, parse::AlignRight, |me| {
emit(me);
emit(me)
})
}
}
@@ -958,11 +964,10 @@ pub fn pad_integral(&mut self, s: &[u8], alternate_prefix: &str,
/// is longer than this length
///
/// Notably this function ignored the `flag` parameters
pub fn pad(&mut self, s: &str) {
pub fn pad(&mut self, s: &str) -> Result {
// Make sure there's a fast path up front
if self.width.is_none() && self.precision.is_none() {
self.buf.write(s.as_bytes());
return
return self.buf.write(s.as_bytes());
}
// The `precision` field can be interpreted as a `max-width` for the
// string being formatted
@@ -974,8 +979,7 @@ pub fn pad(&mut self, s: &str) {
let char_len = s.char_len();
if char_len >= max {
let nchars = ::cmp::min(max, char_len);
self.buf.write(s.slice_chars(0, nchars).as_bytes());
return
return self.buf.write(s.slice_chars(0, nchars).as_bytes());
}
}
None => {}
@@ -985,7 +989,7 @@ pub fn pad(&mut self, s: &str) {
match self.width {
// If we're under the maximum length, and there's no minimum length
// requirements, then we can just emit the string
None => { self.buf.write(s.as_bytes()) }
None => self.buf.write(s.as_bytes()),
// If we're under the maximum width, check if we're over the minimum
// width, if so it's as easy as just emitting the string.
@@ -997,7 +1001,7 @@ pub fn pad(&mut self, s: &str) {
// up the minimum width with the specified string + some alignment.
Some(width) => {
self.with_padding(width - s.len(), parse::AlignLeft, |me| {
me.buf.write(s.as_bytes());
me.buf.write(s.as_bytes())
})
}
}
@@ -1006,29 +1010,30 @@ pub fn pad(&mut self, s: &str) {
fn with_padding(&mut self,
padding: uint,
default: parse::Alignment,
f: |&mut Formatter|) {
f: |&mut Formatter| -> Result) -> Result {
let align = match self.align {
parse::AlignUnknown => default,
parse::AlignLeft | parse::AlignRight => self.align
};
if align == parse::AlignLeft {
f(self);
if_ok!(f(self));
}
let mut fill = [0u8, ..4];
let len = self.fill.encode_utf8(fill);
for _ in range(0, padding) {
self.buf.write(fill.slice_to(len));
if_ok!(self.buf.write(fill.slice_to(len)));
}
if align == parse::AlignRight {
f(self);
if_ok!(f(self));
}
Ok(())
}
}
/// This is a function which calls are emitted to by the compiler itself to
/// create the Argument structures that are passed into the `format` function.
#[doc(hidden)] #[inline]
pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter),
pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result,
t: &'a T) -> Argument<'a> {
unsafe {
Argument {
@@ -1055,41 +1060,41 @@ pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
// Implementations of the core formatting traits
impl Bool for bool {
fn fmt(b: &bool, f: &mut Formatter) {
String::fmt(&(if *b {"true"} else {"false"}), f);
fn fmt(b: &bool, f: &mut Formatter) -> Result {
String::fmt(&(if *b {"true"} else {"false"}), f)
}
}
impl<'a, T: str::Str> String for T {
fn fmt(s: &T, f: &mut Formatter) {
f.pad(s.as_slice());
fn fmt(s: &T, f: &mut Formatter) -> Result {
f.pad(s.as_slice())
}
}
impl Char for char {
fn fmt(c: &char, f: &mut Formatter) {
fn fmt(c: &char, f: &mut Formatter) -> Result {
let mut utf8 = [0u8, ..4];
let amt = c.encode_utf8(utf8);
let s: &str = unsafe { cast::transmute(utf8.slice_to(amt)) };
String::fmt(&s, f);
String::fmt(&s, f)
}
}
macro_rules! int_base(($ty:ident, $into:ident, $base:expr,
$name:ident, $prefix:expr) => {
impl $name for $ty {
fn fmt(c: &$ty, f: &mut Formatter) {
fn fmt(c: &$ty, f: &mut Formatter) -> Result {
::$into::to_str_bytes(*c as $into, $base, |buf| {
f.pad_integral(buf, $prefix, true);
f.pad_integral(buf, $prefix, true)
})
}
}
})
macro_rules! upper_hex(($ty:ident, $into:ident) => {
impl UpperHex for $ty {
fn fmt(c: &$ty, f: &mut Formatter) {
fn fmt(c: &$ty, f: &mut Formatter) -> Result {
::$into::to_str_bytes(*c as $into, 16, |buf| {
upperhex(buf, f);
upperhex(buf, f)
})
}
}
@@ -1097,7 +1102,7 @@ fn fmt(c: &$ty, f: &mut Formatter) {
// Not sure why, but this causes an "unresolved enum variant, struct or const"
// when inlined into the above macro...
#[doc(hidden)]
pub fn upperhex(buf: &[u8], f: &mut Formatter) {
pub fn upperhex(buf: &[u8], f: &mut Formatter) -> Result {
let mut local = [0u8, ..16];
for i in ::iter::range(0, buf.len()) {
local[i] = match buf[i] as char {
@@ -1105,16 +1110,16 @@ pub fn upperhex(buf: &[u8], f: &mut Formatter) {
c => c as u8,
}
}
f.pad_integral(local.slice_to(buf.len()), "0x", true);
f.pad_integral(local.slice_to(buf.len()), "0x", true)
}
macro_rules! integer(($signed:ident, $unsigned:ident) => {
// Signed is special because it actuall emits the negative sign,
// nothing else should do that, however.
impl Signed for $signed {
fn fmt(c: &$signed, f: &mut Formatter) {
fn fmt(c: &$signed, f: &mut Formatter) -> Result {
::$unsigned::to_str_bytes(c.abs() as $unsigned, 10, |buf| {
f.pad_integral(buf, "", *c >= 0);
f.pad_integral(buf, "", *c >= 0)
})
}
}
@@ -1138,35 +1143,35 @@ fn fmt(c: &$signed, f: &mut Formatter) {
macro_rules! floating(($ty:ident) => {
impl Float for $ty {
fn fmt(f: &$ty, fmt: &mut Formatter) {
fn fmt(f: &$ty, fmt: &mut Formatter) -> Result {
// FIXME: this shouldn't perform an allocation
let s = match fmt.precision {
Some(i) => ::$ty::to_str_exact(f.abs(), i),
None => ::$ty::to_str_digits(f.abs(), 6)
};
fmt.pad_integral(s.as_bytes(), "", *f >= 0.0);
fmt.pad_integral(s.as_bytes(), "", *f >= 0.0)
}
}
impl LowerExp for $ty {
fn fmt(f: &$ty, fmt: &mut Formatter) {
fn fmt(f: &$ty, fmt: &mut Formatter) -> Result {
// FIXME: this shouldn't perform an allocation
let s = match fmt.precision {
Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, false),
None => ::$ty::to_str_exp_digits(f.abs(), 6, false)
};
fmt.pad_integral(s.as_bytes(), "", *f >= 0.0);
fmt.pad_integral(s.as_bytes(), "", *f >= 0.0)
}
}
impl UpperExp for $ty {
fn fmt(f: &$ty, fmt: &mut Formatter) {
fn fmt(f: &$ty, fmt: &mut Formatter) -> Result {
// FIXME: this shouldn't perform an allocation
let s = match fmt.precision {
Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, true),
None => ::$ty::to_str_exp_digits(f.abs(), 6, true)
};
fmt.pad_integral(s.as_bytes(), "", *f >= 0.0);
fmt.pad_integral(s.as_bytes(), "", *f >= 0.0)
}
}
})
@@ -1174,39 +1179,41 @@ fn fmt(f: &$ty, fmt: &mut Formatter) {
floating!(f64)
impl<T> Poly for T {
fn fmt(t: &T, f: &mut Formatter) {
fn fmt(t: &T, f: &mut Formatter) -> Result {
match (f.width, f.precision) {
(None, None) => {
repr::write_repr(f.buf, t);
repr::write_repr(f.buf, t)
}
// If we have a specified width for formatting, then we have to make
// this allocation of a new string
_ => {
let s = repr::repr_to_str(t);
f.pad(s);
f.pad(s)
}
}
}
}
impl<T> Pointer for *T {
fn fmt(t: &*T, f: &mut Formatter) {
fn fmt(t: &*T, f: &mut Formatter) -> Result {
f.flags |= 1 << (parse::FlagAlternate as uint);
::uint::to_str_bytes(*t as uint, 16, |buf| {
f.pad_integral(buf, "0x", true);
f.pad_integral(buf, "0x", true)
})
}
}
impl<T> Pointer for *mut T {
fn fmt(t: &*mut T, f: &mut Formatter) { Pointer::fmt(&(*t as *T), f) }
fn fmt(t: &*mut T, f: &mut Formatter) -> Result {
Pointer::fmt(&(*t as *T), f)
}
}
// Implementation of Show for various core types
macro_rules! delegate(($ty:ty to $other:ident) => {
impl<'a> Show for $ty {
fn fmt(me: &$ty, f: &mut Formatter) {
fn fmt(me: &$ty, f: &mut Formatter) -> Result {
$other::fmt(me, f)
}
}
@@ -1229,10 +1236,10 @@ fn fmt(me: &$ty, f: &mut Formatter) {
delegate!(f64 to Float)
impl<T> Show for *T {
fn fmt(me: &*T, f: &mut Formatter) { Pointer::fmt(me, f) }
fn fmt(me: &*T, f: &mut Formatter) -> Result { Pointer::fmt(me, f) }
}
impl<T> Show for *mut T {
fn fmt(me: &*mut T, f: &mut Formatter) { Pointer::fmt(me, f) }
fn fmt(me: &*mut T, f: &mut Formatter) -> Result { Pointer::fmt(me, f) }
}
// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
+7 -9
View File
@@ -27,13 +27,14 @@
#[allow(missing_doc)];
use container::Container;
use io::{Writer, IoResult};
use iter::Iterator;
use num::ToStrRadix;
use option::{Some, None};
use io::Writer;
use result::Ok;
use str::OwnedStr;
use to_bytes::IterBytes;
use vec::ImmutableVector;
use num::ToStrRadix;
// Alias `SipState` to `State`.
pub use State = hash::SipState;
@@ -164,7 +165,7 @@ macro_rules! compress (
impl Writer for SipState {
// Methods for io::writer
#[inline]
fn write(&mut self, msg: &[u8]) {
fn write(&mut self, msg: &[u8]) -> IoResult<()> {
let length = msg.len();
self.length += length;
@@ -180,7 +181,7 @@ fn write(&mut self, msg: &[u8]) {
t += 1;
}
self.ntail += length;
return;
return Ok(())
}
let mut t = 0;
@@ -222,17 +223,14 @@ fn write(&mut self, msg: &[u8]) {
t += 1
}
self.ntail = left;
}
fn flush(&mut self) {
// No-op
Ok(())
}
}
impl Streaming for SipState {
#[inline]
fn input(&mut self, buf: &[u8]) {
self.write(buf);
self.write(buf).unwrap();
}
#[inline]
+102 -92
View File
@@ -11,10 +11,11 @@
//! Buffering wrappers for I/O traits
use container::Container;
use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE};
use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult};
use iter::ExactSize;
use num;
use option::{Option, Some, None};
use option::{Some, None};
use result::{Ok, Err};
use vec::{OwnedVector, ImmutableVector, MutableVector};
use vec;
@@ -30,14 +31,13 @@
/// ```rust
/// use std::io::{BufferedReader, File};
///
/// # let _g = ::std::io::ignore_io_error();
/// let file = File::open(&Path::new("message.txt"));
/// let mut reader = BufferedReader::new(file);
///
/// let mut buf = [0, ..100];
/// match reader.read(buf) {
/// Some(nread) => println!("Read {} bytes", nread),
/// None => println!("At the end of the file!")
/// Ok(nread) => println!("Read {} bytes", nread),
/// Err(e) => println!("error reading: {}", e)
/// }
/// ```
pub struct BufferedReader<R> {
@@ -86,17 +86,12 @@ pub fn unwrap(self) -> R { self.inner }
}
impl<R: Reader> Buffer for BufferedReader<R> {
fn fill<'a>(&'a mut self) -> &'a [u8] {
fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> {
if self.pos == self.cap {
match self.inner.read(self.buf) {
Some(cap) => {
self.pos = 0;
self.cap = cap;
}
None => { self.eof = true; }
}
self.cap = if_ok!(self.inner.read(self.buf));
self.pos = 0;
}
return self.buf.slice(self.pos, self.cap);
Ok(self.buf.slice(self.pos, self.cap))
}
fn consume(&mut self, amt: uint) {
@@ -106,18 +101,15 @@ fn consume(&mut self, amt: uint) {
}
impl<R: Reader> Reader for BufferedReader<R> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
let nread = {
let available = self.fill();
let available = if_ok!(self.fill());
let nread = num::min(available.len(), buf.len());
vec::bytes::copy_memory(buf, available.slice_to(nread));
nread
};
self.pos += nread;
if nread == 0 && buf.len() != 0 && self.eof {
return None;
}
Some(nread)
Ok(nread)
}
}
@@ -128,9 +120,9 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
/// # Example
///
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::{BufferedWriter, File};
///
/// # let _g = ::std::io::ignore_io_error();
/// let file = File::open(&Path::new("message.txt"));
/// let mut writer = BufferedWriter::new(file);
///
@@ -161,10 +153,13 @@ pub fn new(inner: W) -> BufferedWriter<W> {
BufferedWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
}
fn flush_buf(&mut self) {
fn flush_buf(&mut self) -> IoResult<()> {
if self.pos != 0 {
self.inner.write(self.buf.slice_to(self.pos));
let ret = self.inner.write(self.buf.slice_to(self.pos));
self.pos = 0;
ret
} else {
Ok(())
}
}
@@ -178,29 +173,30 @@ pub fn get_ref<'a>(&'a self) -> &'a W { &self.inner }
///
/// The buffer is flushed before returning the writer.
pub fn unwrap(mut self) -> W {
self.flush_buf();
// FIXME: is failing the right thing to do if flushing fails?
self.flush_buf().unwrap();
self.inner
}
}
impl<W: Writer> Writer for BufferedWriter<W> {
fn write(&mut self, buf: &[u8]) {
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
if self.pos + buf.len() > self.buf.len() {
self.flush_buf();
if_ok!(self.flush_buf());
}
if buf.len() > self.buf.len() {
self.inner.write(buf);
self.inner.write(buf)
} else {
let dst = self.buf.mut_slice_from(self.pos);
vec::bytes::copy_memory(dst, buf);
self.pos += buf.len();
Ok(())
}
}
fn flush(&mut self) {
self.flush_buf();
self.inner.flush();
fn flush(&mut self) -> IoResult<()> {
self.flush_buf().and_then(|()| self.inner.flush())
}
}
@@ -234,18 +230,19 @@ pub fn unwrap(self) -> W { self.inner.unwrap() }
}
impl<W: Writer> Writer for LineBufferedWriter<W> {
fn write(&mut self, buf: &[u8]) {
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
match buf.iter().rposition(|&b| b == '\n' as u8) {
Some(i) => {
self.inner.write(buf.slice_to(i + 1));
self.inner.flush();
self.inner.write(buf.slice_from(i + 1));
if_ok!(self.inner.write(buf.slice_to(i + 1)));
if_ok!(self.inner.flush());
if_ok!(self.inner.write(buf.slice_from(i + 1)));
Ok(())
}
None => self.inner.write(buf),
}
}
fn flush(&mut self) { self.inner.flush() }
fn flush(&mut self) -> IoResult<()> { self.inner.flush() }
}
struct InternalBufferedWriter<W>(BufferedWriter<W>);
@@ -258,7 +255,9 @@ fn get_mut_ref<'a>(&'a mut self) -> &'a mut BufferedWriter<W> {
}
impl<W: Reader> Reader for InternalBufferedWriter<W> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.get_mut_ref().inner.read(buf) }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
self.get_mut_ref().inner.read(buf)
}
}
/// Wraps a Stream and buffers input and output to and from it
@@ -268,9 +267,9 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.get_mut_ref().inner.re
/// # Example
///
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::{BufferedStream, File};
///
/// # let _g = ::std::io::ignore_io_error();
/// let file = File::open(&Path::new("message.txt"));
/// let mut stream = BufferedStream::new(file);
///
@@ -279,8 +278,8 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.get_mut_ref().inner.re
///
/// let mut buf = [0, ..100];
/// match stream.read(buf) {
/// Some(nread) => println!("Read {} bytes", nread),
/// None => println!("At the end of the stream!")
/// Ok(nread) => println!("Read {} bytes", nread),
/// Err(e) => println!("error reading: {}", e)
/// }
/// ```
pub struct BufferedStream<S> {
@@ -326,17 +325,23 @@ pub fn unwrap(self) -> S {
}
impl<S: Stream> Buffer for BufferedStream<S> {
fn fill<'a>(&'a mut self) -> &'a [u8] { self.inner.fill() }
fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { self.inner.fill() }
fn consume(&mut self, amt: uint) { self.inner.consume(amt) }
}
impl<S: Stream> Reader for BufferedStream<S> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.inner.read(buf) }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
self.inner.read(buf)
}
}
impl<S: Stream> Writer for BufferedStream<S> {
fn write(&mut self, buf: &[u8]) { self.inner.inner.get_mut_ref().write(buf) }
fn flush(&mut self) { self.inner.inner.get_mut_ref().flush() }
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
self.inner.inner.get_mut_ref().write(buf)
}
fn flush(&mut self) -> IoResult<()> {
self.inner.inner.get_mut_ref().flush()
}
}
#[cfg(test)]
@@ -354,13 +359,13 @@ mod test {
pub struct NullStream;
impl Reader for NullStream {
fn read(&mut self, _: &mut [u8]) -> Option<uint> {
None
fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> {
Err(io::standard_error(io::EndOfFile))
}
}
impl Writer for NullStream {
fn write(&mut self, _: &[u8]) { }
fn write(&mut self, _: &[u8]) -> io::IoResult<()> { Ok(()) }
}
/// A dummy reader intended at testing short-reads propagation.
@@ -369,8 +374,11 @@ pub struct ShortReader {
}
impl Reader for ShortReader {
fn read(&mut self, _: &mut [u8]) -> Option<uint> {
self.lengths.shift()
fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> {
match self.lengths.shift() {
Some(i) => Ok(i),
None => Err(io::standard_error(io::EndOfFile))
}
}
}
@@ -381,24 +389,24 @@ fn test_buffered_reader() {
let mut buf = [0, 0, 0];
let nread = reader.read(buf);
assert_eq!(Some(2), nread);
assert_eq!(Ok(2), nread);
assert_eq!([0, 1, 0], buf);
let mut buf = [0];
let nread = reader.read(buf);
assert_eq!(Some(1), nread);
assert_eq!(Ok(1), nread);
assert_eq!([2], buf);
let mut buf = [0, 0, 0];
let nread = reader.read(buf);
assert_eq!(Some(1), nread);
assert_eq!(Ok(1), nread);
assert_eq!([3, 0, 0], buf);
let nread = reader.read(buf);
assert_eq!(Some(1), nread);
assert_eq!(Ok(1), nread);
assert_eq!([4, 0, 0], buf);
assert_eq!(None, reader.read(buf));
assert!(reader.read(buf).is_err());
}
#[test]
@@ -406,35 +414,35 @@ fn test_buffered_writer() {
let inner = MemWriter::new();
let mut writer = BufferedWriter::with_capacity(2, inner);
writer.write([0, 1]);
writer.write([0, 1]).unwrap();
assert_eq!([], writer.get_ref().get_ref());
writer.write([2]);
writer.write([2]).unwrap();
assert_eq!([0, 1], writer.get_ref().get_ref());
writer.write([3]);
writer.write([3]).unwrap();
assert_eq!([0, 1], writer.get_ref().get_ref());
writer.flush();
writer.flush().unwrap();
assert_eq!([0, 1, 2, 3], writer.get_ref().get_ref());
writer.write([4]);
writer.write([5]);
writer.write([4]).unwrap();
writer.write([5]).unwrap();
assert_eq!([0, 1, 2, 3], writer.get_ref().get_ref());
writer.write([6]);
writer.write([6]).unwrap();
assert_eq!([0, 1, 2, 3, 4, 5],
writer.get_ref().get_ref());
writer.write([7, 8]);
writer.write([7, 8]).unwrap();
assert_eq!([0, 1, 2, 3, 4, 5, 6],
writer.get_ref().get_ref());
writer.write([9, 10, 11]);
writer.write([9, 10, 11]).unwrap();
assert_eq!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
writer.get_ref().get_ref());
writer.flush();
writer.flush().unwrap();
assert_eq!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
writer.get_ref().get_ref());
}
@@ -442,7 +450,7 @@ fn test_buffered_writer() {
#[test]
fn test_buffered_writer_inner_flushes() {
let mut w = BufferedWriter::with_capacity(3, MemWriter::new());
w.write([0, 1]);
w.write([0, 1]).unwrap();
assert_eq!([], w.get_ref().get_ref());
let w = w.unwrap();
assert_eq!([0, 1], w.get_ref());
@@ -455,47 +463,49 @@ fn test_buffered_stream() {
struct S;
impl io::Writer for S {
fn write(&mut self, _: &[u8]) {}
fn write(&mut self, _: &[u8]) -> io::IoResult<()> { Ok(()) }
}
impl io::Reader for S {
fn read(&mut self, _: &mut [u8]) -> Option<uint> { None }
fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> {
Err(io::standard_error(io::EndOfFile))
}
}
let mut stream = BufferedStream::new(S);
let mut buf = [];
stream.read(buf);
stream.write(buf);
stream.flush();
assert!(stream.read(buf).is_err());
stream.write(buf).unwrap();
stream.flush().unwrap();
}
#[test]
fn test_read_until() {
let inner = MemReader::new(~[0, 1, 2, 1, 0]);
let mut reader = BufferedReader::with_capacity(2, inner);
assert_eq!(reader.read_until(0), Some(~[0]));
assert_eq!(reader.read_until(2), Some(~[1, 2]));
assert_eq!(reader.read_until(1), Some(~[1]));
assert_eq!(reader.read_until(8), Some(~[0]));
assert_eq!(reader.read_until(9), None);
assert_eq!(reader.read_until(0), Ok(~[0]));
assert_eq!(reader.read_until(2), Ok(~[1, 2]));
assert_eq!(reader.read_until(1), Ok(~[1]));
assert_eq!(reader.read_until(8), Ok(~[0]));
assert!(reader.read_until(9).is_err());
}
#[test]
fn test_line_buffer() {
let mut writer = LineBufferedWriter::new(MemWriter::new());
writer.write([0]);
writer.write([0]).unwrap();
assert_eq!(writer.get_ref().get_ref(), []);
writer.write([1]);
writer.write([1]).unwrap();
assert_eq!(writer.get_ref().get_ref(), []);
writer.flush();
writer.flush().unwrap();
assert_eq!(writer.get_ref().get_ref(), [0, 1]);
writer.write([0, '\n' as u8, 1, '\n' as u8, 2]);
writer.write([0, '\n' as u8, 1, '\n' as u8, 2]).unwrap();
assert_eq!(writer.get_ref().get_ref(),
[0, 1, 0, '\n' as u8, 1, '\n' as u8]);
writer.flush();
writer.flush().unwrap();
assert_eq!(writer.get_ref().get_ref(),
[0, 1, 0, '\n' as u8, 1, '\n' as u8, 2]);
writer.write([3, '\n' as u8]);
writer.write([3, '\n' as u8]).unwrap();
assert_eq!(writer.get_ref().get_ref(),
[0, 1, 0, '\n' as u8, 1, '\n' as u8, 2, 3, '\n' as u8]);
}
@@ -504,10 +514,10 @@ fn test_line_buffer() {
fn test_read_line() {
let in_buf = MemReader::new(bytes!("a\nb\nc").to_owned());
let mut reader = BufferedReader::with_capacity(2, in_buf);
assert_eq!(reader.read_line(), Some(~"a\n"));
assert_eq!(reader.read_line(), Some(~"b\n"));
assert_eq!(reader.read_line(), Some(~"c"));
assert_eq!(reader.read_line(), None);
assert_eq!(reader.read_line(), Ok(~"a\n"));
assert_eq!(reader.read_line(), Ok(~"b\n"));
assert_eq!(reader.read_line(), Ok(~"c"));
assert!(reader.read_line().is_err());
}
#[test]
@@ -526,20 +536,20 @@ fn test_short_reads() {
let inner = ShortReader{lengths: ~[0, 1, 2, 0, 1, 0]};
let mut reader = BufferedReader::new(inner);
let mut buf = [0, 0];
assert_eq!(reader.read(buf), Some(0));
assert_eq!(reader.read(buf), Some(1));
assert_eq!(reader.read(buf), Some(2));
assert_eq!(reader.read(buf), Some(0));
assert_eq!(reader.read(buf), Some(1));
assert_eq!(reader.read(buf), Some(0));
assert_eq!(reader.read(buf), None);
assert_eq!(reader.read(buf), Ok(0));
assert_eq!(reader.read(buf), Ok(1));
assert_eq!(reader.read(buf), Ok(2));
assert_eq!(reader.read(buf), Ok(0));
assert_eq!(reader.read(buf), Ok(1));
assert_eq!(reader.read(buf), Ok(0));
assert!(reader.read(buf).is_err());
}
#[test]
fn read_char_buffered() {
let buf = [195u8, 159u8];
let mut reader = BufferedReader::with_capacity(1, BufReader::new(buf));
assert_eq!(reader.read_char(), Some('ß'));
assert_eq!(reader.read_char(), Ok('ß'));
}
#[bench]
+26 -36
View File
@@ -14,7 +14,7 @@
use cmp;
use io;
use option::{None, Option, Some};
use super::{Reader, Writer};
use super::{Reader, Writer, IoResult};
use vec::{bytes, CloneableVector, MutableVector, ImmutableVector};
/// Allows reading from a port.
@@ -49,7 +49,7 @@ pub fn new(port: Port<~[u8]>) -> PortReader {
}
impl Reader for PortReader {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
let mut num_read = 0;
loop {
match self.buf {
@@ -71,10 +71,9 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
self.closed = self.buf.is_none();
}
if self.closed && num_read == 0 {
io::io_error::cond.raise(io::standard_error(io::EndOfFile));
None
Err(io::standard_error(io::EndOfFile))
} else {
Some(num_read)
Ok(num_read)
}
}
}
@@ -98,13 +97,15 @@ pub fn new(chan: Chan<~[u8]>) -> ChanWriter {
}
impl Writer for ChanWriter {
fn write(&mut self, buf: &[u8]) {
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
if !self.chan.try_send(buf.to_owned()) {
io::io_error::cond.raise(io::IoError {
Err(io::IoError {
kind: io::BrokenPipe,
desc: "Pipe closed",
detail: None
});
})
} else {
Ok(())
}
}
}
@@ -132,36 +133,28 @@ fn test_port_reader() {
let mut buf = ~[0u8, ..3];
assert_eq!(Some(0), reader.read([]));
assert_eq!(Ok(0), reader.read([]));
assert_eq!(Some(3), reader.read(buf));
assert_eq!(Ok(3), reader.read(buf));
assert_eq!(~[1,2,3], buf);
assert_eq!(Some(3), reader.read(buf));
assert_eq!(Ok(3), reader.read(buf));
assert_eq!(~[4,5,6], buf);
assert_eq!(Some(2), reader.read(buf));
assert_eq!(Ok(2), reader.read(buf));
assert_eq!(~[7,8,6], buf);
let mut err = None;
let result = io::io_error::cond.trap(|io::standard_error(k, _, _)| {
err = Some(k)
}).inside(|| {
reader.read(buf)
});
assert_eq!(Some(io::EndOfFile), err);
assert_eq!(None, result);
match reader.read(buf) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::EndOfFile),
}
assert_eq!(~[7,8,6], buf);
// Ensure it continues to fail in the same way.
err = None;
let result = io::io_error::cond.trap(|io::standard_error(k, _, _)| {
err = Some(k)
}).inside(|| {
reader.read(buf)
});
assert_eq!(Some(io::EndOfFile), err);
assert_eq!(None, result);
match reader.read(buf) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::EndOfFile),
}
assert_eq!(~[7,8,6], buf);
}
@@ -169,18 +162,15 @@ fn test_port_reader() {
fn test_chan_writer() {
let (port, chan) = Chan::new();
let mut writer = ChanWriter::new(chan);
writer.write_be_u32(42);
writer.write_be_u32(42).unwrap();
let wanted = ~[0u8, 0u8, 0u8, 42u8];
let got = task::try(proc() { port.recv() }).unwrap();
assert_eq!(wanted, got);
let mut err = None;
io::io_error::cond.trap(|io::IoError { kind, .. } | {
err = Some(kind)
}).inside(|| {
writer.write_u8(1)
});
assert_eq!(Some(io::BrokenPipe), err);
match writer.write_u8(1) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::BrokenPipe),
}
}
}
+49 -85
View File
@@ -46,7 +46,7 @@ pub fn new(r: &'r mut R) -> Bytes<'r, R> {
impl<'r, R: Reader> Iterator<u8> for Bytes<'r, R> {
#[inline]
fn next(&mut self) -> Option<u8> {
self.reader.read_byte()
self.reader.read_byte().ok()
}
}
@@ -125,23 +125,22 @@ pub fn u64_from_be_bytes(data: &[u8],
#[cfg(test)]
mod test {
use unstable::finally::Finally;
use prelude::*;
use io;
use io::{MemReader, MemWriter};
use io::{io_error, placeholder_error};
struct InitialZeroByteReader {
count: int,
}
impl Reader for InitialZeroByteReader {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
if self.count == 0 {
self.count = 1;
Some(0)
Ok(0)
} else {
buf[0] = 10;
Some(1)
Ok(1)
}
}
}
@@ -149,17 +148,16 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
struct EofReader;
impl Reader for EofReader {
fn read(&mut self, _: &mut [u8]) -> Option<uint> {
None
fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> {
Err(io::standard_error(io::EndOfFile))
}
}
struct ErroringReader;
impl Reader for ErroringReader {
fn read(&mut self, _: &mut [u8]) -> Option<uint> {
io_error::cond.raise(placeholder_error());
None
fn read(&mut self, _: &mut [u8]) -> io::IoResult<uint> {
Err(io::standard_error(io::InvalidInput))
}
}
@@ -168,16 +166,16 @@ struct PartialReader {
}
impl Reader for PartialReader {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
if self.count == 0 {
self.count = 1;
buf[0] = 10;
buf[1] = 11;
Some(2)
Ok(2)
} else {
buf[0] = 12;
buf[1] = 13;
Some(2)
Ok(2)
}
}
}
@@ -187,14 +185,13 @@ struct ErroringLaterReader {
}
impl Reader for ErroringLaterReader {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
if self.count == 0 {
self.count = 1;
buf[0] = 10;
Some(1)
Ok(1)
} else {
io_error::cond.raise(placeholder_error());
None
Err(io::standard_error(io::InvalidInput))
}
}
}
@@ -204,19 +201,19 @@ struct ThreeChunkReader {
}
impl Reader for ThreeChunkReader {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
if self.count == 0 {
self.count = 1;
buf[0] = 10;
buf[1] = 11;
Some(2)
Ok(2)
} else if self.count == 1 {
self.count = 2;
buf[0] = 12;
buf[1] = 13;
Some(2)
Ok(2)
} else {
None
Err(io::standard_error(io::EndOfFile))
}
}
}
@@ -225,7 +222,7 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read_byte() {
let mut reader = MemReader::new(~[10]);
let byte = reader.read_byte();
assert!(byte == Some(10));
assert!(byte == Ok(10));
}
#[test]
@@ -234,24 +231,21 @@ fn read_byte_0_bytes() {
count: 0,
};
let byte = reader.read_byte();
assert!(byte == Some(10));
assert!(byte == Ok(10));
}
#[test]
fn read_byte_eof() {
let mut reader = EofReader;
let byte = reader.read_byte();
assert!(byte == None);
assert!(byte.is_err());
}
#[test]
fn read_byte_error() {
let mut reader = ErroringReader;
io_error::cond.trap(|_| {
}).inside(|| {
let byte = reader.read_byte();
assert!(byte == None);
});
let byte = reader.read_byte();
assert!(byte.is_err());
}
#[test]
@@ -267,23 +261,21 @@ fn bytes_0_bytes() {
fn bytes_eof() {
let mut reader = EofReader;
let byte = reader.bytes().next();
assert!(byte == None);
assert!(byte.is_none());
}
#[test]
fn bytes_error() {
let mut reader = ErroringReader;
let mut it = reader.bytes();
io_error::cond.trap(|_| ()).inside(|| {
let byte = it.next();
assert!(byte == None);
})
let byte = it.next();
assert!(byte.is_none());
}
#[test]
fn read_bytes() {
let mut reader = MemReader::new(~[10, 11, 12, 13]);
let bytes = reader.read_bytes(4);
let bytes = reader.read_bytes(4).unwrap();
assert!(bytes == ~[10, 11, 12, 13]);
}
@@ -292,24 +284,21 @@ fn read_bytes_partial() {
let mut reader = PartialReader {
count: 0,
};
let bytes = reader.read_bytes(4);
let bytes = reader.read_bytes(4).unwrap();
assert!(bytes == ~[10, 11, 12, 13]);
}
#[test]
fn read_bytes_eof() {
let mut reader = MemReader::new(~[10, 11]);
io_error::cond.trap(|_| {
}).inside(|| {
assert!(reader.read_bytes(4) == ~[10, 11]);
})
assert!(reader.read_bytes(4).is_err());
}
#[test]
fn push_bytes() {
let mut reader = MemReader::new(~[10, 11, 12, 13]);
let mut buf = ~[8, 9];
reader.push_bytes(&mut buf, 4);
reader.push_bytes(&mut buf, 4).unwrap();
assert!(buf == ~[8, 9, 10, 11, 12, 13]);
}
@@ -319,7 +308,7 @@ fn push_bytes_partial() {
count: 0,
};
let mut buf = ~[8, 9];
reader.push_bytes(&mut buf, 4);
reader.push_bytes(&mut buf, 4).unwrap();
assert!(buf == ~[8, 9, 10, 11, 12, 13]);
}
@@ -327,11 +316,8 @@ fn push_bytes_partial() {
fn push_bytes_eof() {
let mut reader = MemReader::new(~[10, 11]);
let mut buf = ~[8, 9];
io_error::cond.trap(|_| {
}).inside(|| {
reader.push_bytes(&mut buf, 4);
assert!(buf == ~[8, 9, 10, 11]);
})
assert!(reader.push_bytes(&mut buf, 4).is_err());
assert!(buf == ~[8, 9, 10, 11]);
}
#[test]
@@ -340,38 +326,16 @@ fn push_bytes_error() {
count: 0,
};
let mut buf = ~[8, 9];
io_error::cond.trap(|_| { } ).inside(|| {
reader.push_bytes(&mut buf, 4);
});
assert!(reader.push_bytes(&mut buf, 4).is_err());
assert!(buf == ~[8, 9, 10]);
}
#[test]
#[should_fail]
#[ignore] // borrow issues with RefCell
fn push_bytes_fail_reset_len() {
// push_bytes unsafely sets the vector length. This is testing that
// upon failure the length is reset correctly.
let _reader = ErroringLaterReader {
count: 0,
};
// FIXME (#7049): Figure out some other way to do this.
//let buf = RefCell::new(~[8, 9]);
(|| {
//reader.push_bytes(buf.borrow_mut().get(), 4);
}).finally(|| {
// NB: Using rtassert here to trigger abort on failure since this is a should_fail test
// FIXME: #7049 This fails because buf is still borrowed
//rtassert!(buf.borrow().get() == ~[8, 9, 10]);
})
}
#[test]
fn read_to_end() {
let mut reader = ThreeChunkReader {
count: 0,
};
let buf = reader.read_to_end();
let buf = reader.read_to_end().unwrap();
assert!(buf == ~[10, 11, 12, 13]);
}
@@ -381,7 +345,7 @@ fn read_to_end_error() {
let mut reader = ThreeChunkReader {
count: 0,
};
let buf = reader.read_to_end();
let buf = reader.read_to_end().unwrap();
assert!(buf == ~[10, 11]);
}
@@ -391,12 +355,12 @@ fn test_read_write_le_mem() {
let mut writer = MemWriter::new();
for i in uints.iter() {
writer.write_le_u64(*i);
writer.write_le_u64(*i).unwrap();
}
let mut reader = MemReader::new(writer.unwrap());
for i in uints.iter() {
assert!(reader.read_le_u64() == *i);
assert!(reader.read_le_u64().unwrap() == *i);
}
}
@@ -407,12 +371,12 @@ fn test_read_write_be() {
let mut writer = MemWriter::new();
for i in uints.iter() {
writer.write_be_u64(*i);
writer.write_be_u64(*i).unwrap();
}
let mut reader = MemReader::new(writer.unwrap());
for i in uints.iter() {
assert!(reader.read_be_u64() == *i);
assert!(reader.read_be_u64().unwrap() == *i);
}
}
@@ -422,14 +386,14 @@ fn test_read_be_int_n() {
let mut writer = MemWriter::new();
for i in ints.iter() {
writer.write_be_i32(*i);
writer.write_be_i32(*i).unwrap();
}
let mut reader = MemReader::new(writer.unwrap());
for i in ints.iter() {
// this tests that the sign extension is working
// (comparing the values as i32 would not test this)
assert!(reader.read_be_int_n(4) == *i as i64);
assert!(reader.read_be_int_n(4).unwrap() == *i as i64);
}
}
@@ -439,10 +403,10 @@ fn test_read_f32() {
let buf = ~[0x41, 0x02, 0x00, 0x00];
let mut writer = MemWriter::new();
writer.write(buf);
writer.write(buf).unwrap();
let mut reader = MemReader::new(writer.unwrap());
let f = reader.read_be_f32();
let f = reader.read_be_f32().unwrap();
assert!(f == 8.1250);
}
@@ -451,12 +415,12 @@ fn test_read_write_f32() {
let f:f32 = 8.1250;
let mut writer = MemWriter::new();
writer.write_be_f32(f);
writer.write_le_f32(f);
writer.write_be_f32(f).unwrap();
writer.write_le_f32(f).unwrap();
let mut reader = MemReader::new(writer.unwrap());
assert!(reader.read_be_f32() == 8.1250);
assert!(reader.read_le_f32() == 8.1250);
assert!(reader.read_be_f32().unwrap() == 8.1250);
assert!(reader.read_le_f32().unwrap() == 8.1250);
}
#[test]
+356 -411
View File
@@ -14,11 +14,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 `Path` object.
with various filesystem operations. They all operate on `Path` objects.
All operations in this module, including those as part of `File` et al
block the task during execution. Most will raise `std::io::io_error`
conditions in the event of failure.
block the task during execution. In the event of failure, all functions/methods
will return an `IoResult` type with an `Err` value.
Also included in this module is an implementation block on the `Path` object
defined in `std::path::Path`. The impl adds useful methods about inspecting the
@@ -27,21 +27,25 @@
# Example
use std::io::{File, fs};
```rust
# #[allow(unused_must_use)];
use std::io::{File, fs};
let path = Path::new("foo.txt");
let path = Path::new("foo.txt");
// create the file, whether it exists or not
let mut file = File::create(&path);
file.write(bytes!("foobar"));
// create the file, whether it exists or not
let mut file = File::create(&path);
file.write(bytes!("foobar"));
# drop(file);
// open the file in read-only mode
let mut file = File::open(&path);
file.read_to_end();
// open the file in read-only mode
let mut file = File::open(&path);
file.read_to_end();
println!("{}", path.stat().size);
fs::symlink(&path, &Path::new("bar.txt"));
fs::unlink(&path);
println!("{}", path.stat().unwrap().size);
# drop(file);
fs::unlink(&path);
```
*/
@@ -50,7 +54,7 @@
use iter::Iterator;
use super::{Reader, Writer, Seek};
use super::{SeekStyle, Read, Write, Open, IoError, Truncate,
FileMode, FileAccess, FileStat, io_error, FilePermission};
FileMode, FileAccess, FileStat, IoResult, FilePermission};
use rt::rtio::{RtioFileStream, IoFactory, LocalIo};
use io;
use option::{Some, None, Option};
@@ -64,11 +68,12 @@
/// Can be constructed via `File::open()`, `File::create()`, and
/// `File::open_mode()`.
///
/// # Errors
/// # Error
///
/// This type will raise an io_error condition if operations are attempted against
/// it for which its underlying file descriptor was not configured at creation
/// time, via the `FileAccess` parameter to `File::open_mode()`.
/// This type will return errors as an `IoResult<T>` if operations are
/// attempted against it for which its underlying file descriptor was not
/// configured at creation time, via the `FileAccess` parameter to
/// `File::open_mode()`.
pub struct File {
priv fd: ~RtioFileStream,
priv path: Path,
@@ -81,22 +86,19 @@ impl File {
///
/// # Example
///
/// use std::io::{File, io_error, Open, ReadWrite};
/// ```rust,should_fail
/// use std::io::{File, Open, ReadWrite};
///
/// let p = Path::new("/some/file/path.txt");
/// let p = Path::new("/some/file/path.txt");
///
/// io_error::cond.trap(|_| {
/// // hoo-boy...
/// }).inside(|| {
/// let file = match File::open_mode(&p, Open, ReadWrite) {
/// Some(s) => s,
/// None => fail!("whoops! I'm sure this raised, anyways..")
/// };
/// // do some stuff with that file
/// let file = match File::open_mode(&p, Open, ReadWrite) {
/// Ok(f) => f,
/// Err(e) => fail!("file error: {}", e),
/// };
/// // do some stuff with that file
///
/// // the file will be closed at the end of this block
/// })
/// // ..
/// // the file will be closed at the end of this block
/// ```
///
/// `FileMode` and `FileAccess` provide information about the permissions
/// context in which a given stream is created. More information about them
@@ -106,12 +108,12 @@ impl File {
///
/// Note that, with this function, a `File` is returned regardless of the
/// access-limitations indicated by `FileAccess` (e.g. calling `write` on a
/// `File` opened as `Read` will raise an `io_error` condition at runtime).
/// `File` opened as `Read` will return an error at runtime).
///
/// # Errors
/// # Error
///
/// This function will raise an `io_error` condition under a number of
/// different circumstances, to include but not limited to:
/// This function will return an error under a number of different
/// circumstances, to include but not limited to:
///
/// * Opening a file that does not exist with `Read` access.
/// * Attempting to open a file with a `FileAccess` that the user lacks
@@ -119,7 +121,7 @@ impl File {
/// * Filesystem-level errors (full disk, etc)
pub fn open_mode(path: &Path,
mode: FileMode,
access: FileAccess) -> Option<File> {
access: FileAccess) -> IoResult<File> {
LocalIo::maybe_raise(|io| {
io.fs_open(&path.to_c_str(), mode, access).map(|fd| {
File {
@@ -139,10 +141,12 @@ pub fn open_mode(path: &Path,
///
/// # Example
///
/// use std::io::File;
/// ```rust
/// use std::io::File;
///
/// let contents = File::open(&Path::new("foo.txt")).read_to_end();
pub fn open(path: &Path) -> Option<File> {
/// let contents = File::open(&Path::new("foo.txt")).read_to_end();
/// ```
pub fn open(path: &Path) -> IoResult<File> {
File::open_mode(path, Open, Read)
}
@@ -154,11 +158,16 @@ pub fn open(path: &Path) -> Option<File> {
///
/// # Example
///
/// use std::io::File;
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::File;
///
/// let mut f = File::create(&Path::new("foo.txt"));
/// f.write(bytes!("This is a sample file"));
pub fn create(path: &Path) -> Option<File> {
/// let mut f = File::create(&Path::new("foo.txt"));
/// f.write(bytes!("This is a sample file"));
/// # drop(f);
/// # ::std::io::fs::unlink(&Path::new("foo.txt"));
/// ```
pub fn create(path: &Path) -> IoResult<File> {
File::open_mode(path, Truncate, Write)
}
@@ -170,24 +179,16 @@ pub fn path<'a>(&'a self) -> &'a Path {
/// Synchronizes all modifications to this file to its permanent storage
/// device. This will flush any internal buffers necessary to perform this
/// operation.
///
/// # Errors
///
/// This function will raise on the `io_error` condition on failure.
pub fn fsync(&mut self) {
let _ = self.fd.fsync().map_err(|e| io_error::cond.raise(e));
pub fn fsync(&mut self) -> IoResult<()> {
self.fd.fsync()
}
/// This function is similar to `fsync`, except that it may not synchronize
/// file metadata to the filesystem. This is intended for use case which
/// must synchronize content, but don't need the metadata on disk. The goal
/// of this method is to reduce disk operations.
///
/// # Errors
///
/// This function will raise on the `io_error` condition on failure.
pub fn datasync(&mut self) {
let _ = self.fd.datasync().map_err(|e| io_error::cond.raise(e));
pub fn datasync(&mut self) -> IoResult<()> {
self.fd.datasync()
}
/// Either truncates or extends the underlying file, updating the size of
@@ -198,12 +199,8 @@ pub fn datasync(&mut self) {
/// be shrunk. If it is greater than the current file's size, then the file
/// will be extended to `size` and have all of the intermediate data filled
/// in with 0s.
///
/// # Errors
///
/// On error, this function will raise on the `io_error` condition.
pub fn truncate(&mut self, size: i64) {
let _ = self.fd.truncate(size).map_err(|e| io_error::cond.raise(e));
pub fn truncate(&mut self, size: i64) -> IoResult<()> {
self.fd.truncate(size)
}
/// Tests whether this stream has reached EOF.
@@ -219,24 +216,25 @@ pub fn eof(&self) -> bool {
///
/// # Example
///
/// use std::io::fs;
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::fs;
///
/// let p = Path::new("/some/file/path.txt");
/// fs::unlink(&p);
/// // if we made it here without failing, then the
/// // unlink operation was successful
/// let p = Path::new("/some/file/path.txt");
/// fs::unlink(&p);
/// ```
///
/// Note that, just because an unlink call was successful, it is not
/// guaranteed that a file is immediately deleted (e.g. depending on
/// platform, other open file descriptors may prevent immediate removal)
///
/// # Errors
/// # Error
///
/// This function will raise an `io_error` condition if the path points to a
/// directory, the user lacks permissions to remove the file, or if some
/// other filesystem-level error occurs.
pub fn unlink(path: &Path) {
LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str()));
/// This function will return an error if the path points to a directory, the
/// user lacks permissions to remove the file, or if some other filesystem-level
/// error occurs.
pub fn unlink(path: &Path) -> IoResult<()> {
LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str()))
}
/// Given a path, query the file system to get information about a file,
@@ -249,48 +247,25 @@ pub fn unlink(path: &Path) {
///
/// # Example
///
/// use std::io;
/// use std::io::fs;
/// ```rust
/// use std::io::fs;
///
/// let p = Path::new("/some/file/path.txt");
/// match io::result(|| fs::stat(&p)) {
/// Ok(stat) => { /* ... */ }
/// Err(e) => { /* handle error */ }
/// }
/// let p = Path::new("/some/file/path.txt");
/// match fs::stat(&p) {
/// Ok(stat) => { /* ... */ }
/// Err(e) => { /* handle error */ }
/// }
/// ```
///
/// # Errors
/// # Error
///
/// This call will raise an `io_error` condition if the user lacks the
/// requisite permissions to perform a `stat` call on the given path or if
/// there is no entry in the filesystem at the provided path.
pub fn stat(path: &Path) -> FileStat {
/// This call will return an error if the user lacks the requisite permissions
/// to perform a `stat` call on the given path or if there is no entry in the
/// filesystem at the provided path.
pub fn stat(path: &Path) -> IoResult<FileStat> {
LocalIo::maybe_raise(|io| {
io.fs_stat(&path.to_c_str())
}).unwrap_or_else(dummystat)
}
fn dummystat() -> FileStat {
FileStat {
path: Path::new(""),
size: 0,
kind: io::TypeFile,
perm: 0,
created: 0,
modified: 0,
accessed: 0,
unstable: io::UnstableFileStat {
device: 0,
inode: 0,
rdev: 0,
nlink: 0,
uid: 0,
gid: 0,
blksize: 0,
blocks: 0,
flags: 0,
gen: 0,
}
}
})
}
/// Perform the same operation as the `stat` function, except that this
@@ -298,31 +273,33 @@ fn dummystat() -> FileStat {
/// information about the symlink file instead of the file that it points
/// to.
///
/// # Errors
/// # Error
///
/// See `stat`
pub fn lstat(path: &Path) -> FileStat {
pub fn lstat(path: &Path) -> IoResult<FileStat> {
LocalIo::maybe_raise(|io| {
io.fs_lstat(&path.to_c_str())
}).unwrap_or_else(dummystat)
})
}
/// Rename a file or directory to a new name.
///
/// # Example
///
/// use std::io::fs;
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::fs;
///
/// fs::rename(&Path::new("foo"), &Path::new("bar"));
/// // Oh boy, nothing was raised!
/// fs::rename(&Path::new("foo"), &Path::new("bar"));
/// ```
///
/// # Errors
/// # Error
///
/// Will raise an `io_error` condition if the provided `path` doesn't exist,
/// the process lacks permissions to view the contents, or if some other
/// intermittent I/O error occurs.
pub fn rename(from: &Path, to: &Path) {
LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str()));
/// Will return an error if the provided `path` doesn't exist, the process lacks
/// permissions to view the contents, or if some other intermittent I/O error
/// occurs.
pub fn rename(from: &Path, to: &Path) -> IoResult<()> {
LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str()))
}
/// Copies the contents of one file to another. This function will also
@@ -333,15 +310,17 @@ pub fn rename(from: &Path, to: &Path) {
///
/// # Example
///
/// use std::io::fs;
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::fs;
///
/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt"));
/// // Oh boy, nothing was raised!
/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt"));
/// ```
///
/// # Errors
/// # Error
///
/// Will raise an `io_error` condition is the following situations, but is
/// not limited to just these cases:
/// Will return an error in the following situations, but is not limited to
/// just these cases:
///
/// * The `from` path is not a file
/// * The `from` file does not exist
@@ -351,27 +330,29 @@ pub fn rename(from: &Path, to: &Path) {
/// Note that this copy is not atomic in that once the destination is
/// ensured to not exist, there is nothing preventing the destination from
/// being created and then destroyed by this operation.
pub fn copy(from: &Path, to: &Path) {
pub fn copy(from: &Path, to: &Path) -> IoResult<()> {
if !from.is_file() {
return io_error::cond.raise(IoError {
return Err(IoError {
kind: io::MismatchedFileTypeForOperation,
desc: "the source path is not an existing file",
detail: None,
});
})
}
let mut reader = match File::open(from) { Some(f) => f, None => return };
let mut writer = match File::create(to) { Some(f) => f, None => return };
let mut reader = if_ok!(File::open(from));
let mut writer = if_ok!(File::create(to));
let mut buf = [0, ..io::DEFAULT_BUF_SIZE];
loop {
match reader.read(buf) {
Some(amt) => writer.write(buf.slice_to(amt)),
None => break
}
let amt = match reader.read(buf) {
Ok(n) => n,
Err(ref e) if e.kind == io::EndOfFile => { break }
Err(e) => return Err(e)
};
if_ok!(writer.write(buf.slice_to(amt)));
}
chmod(to, from.stat().perm)
chmod(to, if_ok!(from.stat()).perm)
}
/// Changes the permission mode bits found on a file or a directory. This
@@ -379,61 +360,51 @@ pub fn copy(from: &Path, to: &Path) {
///
/// # Example
///
/// use std::io;
/// use std::io::fs;
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io;
/// use std::io::fs;
///
/// fs::chmod(&Path::new("file.txt"), io::UserFile);
/// fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite);
/// fs::chmod(&Path::new("dir"), io::UserDir);
/// fs::chmod(&Path::new("file.exe"), io::UserExec);
/// fs::chmod(&Path::new("file.txt"), io::UserFile);
/// fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite);
/// fs::chmod(&Path::new("dir"), io::UserDir);
/// fs::chmod(&Path::new("file.exe"), io::UserExec);
/// ```
///
/// # Errors
/// # Error
///
/// If this function encounters an I/O error, it will raise on the `io_error`
/// condition. Some possible error situations are not having the permission to
/// If this function encounters an I/O error, it will return an `Err` value.
/// Some possible error situations are not having the permission to
/// change the attributes of a file or the file not existing.
pub fn chmod(path: &Path, mode: io::FilePermission) {
LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode));
pub fn chmod(path: &Path, mode: io::FilePermission) -> IoResult<()> {
LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode))
}
/// Change the user and group owners of a file at the specified path.
///
/// # Errors
///
/// This function will raise on the `io_error` condition on failure.
pub fn chown(path: &Path, uid: int, gid: int) {
LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid));
pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> {
LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid))
}
/// Creates a new hard link on the filesystem. The `dst` path will be a
/// link pointing to the `src` path. Note that systems often require these
/// two paths to both be located on the same filesystem.
///
/// # Errors
///
/// This function will raise on the `io_error` condition on failure.
pub fn link(src: &Path, dst: &Path) {
LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str()));
pub fn link(src: &Path, dst: &Path) -> IoResult<()> {
LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str()))
}
/// Creates a new symbolic link on the filesystem. The `dst` path will be a
/// symlink pointing to the `src` path.
///
/// # Errors
///
/// This function will raise on the `io_error` condition on failure.
pub fn symlink(src: &Path, dst: &Path) {
LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str()));
pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> {
LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str()))
}
/// Reads a symlink, returning the file that the symlink points to.
///
/// # Errors
/// # Error
///
/// This function will raise on the `io_error` condition on failure. Failure
/// conditions include reading a file that does not exist or reading a file
/// which is not a symlink.
pub fn readlink(path: &Path) -> Option<Path> {
/// This function will return an error on failure. Failure conditions include
/// reading a file that does not exist or reading a file which is not a symlink.
pub fn readlink(path: &Path) -> IoResult<Path> {
LocalIo::maybe_raise(|io| io.fs_readlink(&path.to_c_str()))
}
@@ -441,75 +412,85 @@ pub fn readlink(path: &Path) -> Option<Path> {
///
/// # Example
///
/// use std::libc::S_IRWXU;
/// use std::io::fs;
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io;
/// use std::io::fs;
///
/// let p = Path::new("/some/dir");
/// fs::mkdir(&p, S_IRWXU as int);
/// // If we got here, our directory exists! Hooray!
/// let p = Path::new("/some/dir");
/// fs::mkdir(&p, io::UserRWX);
/// ```
///
/// # Errors
/// # Error
///
/// This call will raise an `io_error` condition if the user lacks permissions
/// to make a new directory at the provided path, or if the directory already
/// exists.
pub fn mkdir(path: &Path, mode: FilePermission) {
LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode));
/// This call will return an error if the user lacks permissions to make a new
/// directory at the provided path, or if the directory already exists.
pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> {
LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode))
}
/// Remove an existing, empty directory
///
/// # Example
///
/// use std::io::fs;
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::fs;
///
/// let p = Path::new("/some/dir");
/// fs::rmdir(&p);
/// // good riddance, you mean ol' directory
/// let p = Path::new("/some/dir");
/// fs::rmdir(&p);
/// ```
///
/// # Errors
/// # Error
///
/// This call will raise an `io_error` condition if the user lacks permissions
/// to remove the directory at the provided path, or if the directory isn't
/// empty.
pub fn rmdir(path: &Path) {
LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str()));
/// This call will return an error if the user lacks permissions to remove the
/// directory at the provided path, or if the directory isn't empty.
pub fn rmdir(path: &Path) -> IoResult<()> {
LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str()))
}
/// Retrieve a vector containing all entries within a provided directory
///
/// # Example
///
/// use std::io::fs;
/// ```rust
/// use std::io;
/// use std::io::fs;
///
/// // one possible implementation of fs::walk_dir only visiting files
/// fn visit_dirs(dir: &Path, cb: |&Path|) {
/// if dir.is_dir() {
/// let contents = fs::readdir(dir).unwrap();
/// for entry in contents.iter() {
/// if entry.is_dir() { visit_dirs(entry, cb); }
/// else { cb(entry); }
/// // one possible implementation of fs::walk_dir only visiting files
/// fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> {
/// if dir.is_dir() {
/// let contents = if_ok!(fs::readdir(dir));
/// for entry in contents.iter() {
/// if entry.is_dir() {
/// if_ok!(visit_dirs(entry, |p| cb(p)));
/// } else {
/// cb(entry);
/// }
/// }
/// else { fail!("nope"); }
/// Ok(())
/// } else {
/// Err(io::standard_error(io::InvalidInput))
/// }
/// }
/// ```
///
/// # Errors
/// # Error
///
/// Will raise an `io_error` condition if the provided `from` doesn't exist,
/// the process lacks permissions to view the contents or if the `path` points
/// at a non-directory file
pub fn readdir(path: &Path) -> ~[Path] {
/// Will return an error if the provided `from` doesn't exist, the process lacks
/// permissions to view the contents or if the `path` points at a non-directory
/// file
pub fn readdir(path: &Path) -> IoResult<~[Path]> {
LocalIo::maybe_raise(|io| {
io.fs_readdir(&path.to_c_str(), 0)
}).unwrap_or_else(|| ~[])
})
}
/// Returns an iterator which will recursively walk the directory structure
/// rooted at `path`. The path given will not be iterated over, and this will
/// perform iteration in a top-down order.
pub fn walk_dir(path: &Path) -> Directories {
Directories { stack: readdir(path) }
pub fn walk_dir(path: &Path) -> IoResult<Directories> {
Ok(Directories { stack: if_ok!(readdir(path)) })
}
/// An iterator which walks over a directory
@@ -522,7 +503,10 @@ fn next(&mut self) -> Option<Path> {
match self.stack.shift() {
Some(path) => {
if path.is_dir() {
self.stack.push_all_move(readdir(&path));
match readdir(&path) {
Ok(dirs) => { self.stack.push_all_move(dirs); }
Err(..) => {}
}
}
Some(path)
}
@@ -534,19 +518,18 @@ fn next(&mut self) -> Option<Path> {
/// Recursively create a directory and all of its parent components if they
/// are missing.
///
/// # Errors
/// # Error
///
/// This function will raise on the `io_error` condition if an error
/// happens, see `fs::mkdir` for more information about error conditions
/// and performance.
pub fn mkdir_recursive(path: &Path, mode: FilePermission) {
/// This function will return an `Err` value if an error happens, see
/// `fs::mkdir` for more information about error conditions and performance.
pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> {
// tjc: if directory exists but with different permissions,
// should we return false?
if path.is_dir() {
return
return Ok(())
}
if path.filename().is_some() {
mkdir_recursive(&path.dir_path(), mode);
if_ok!(mkdir_recursive(&path.dir_path(), mode));
}
mkdir(path, mode)
}
@@ -554,92 +537,64 @@ pub fn mkdir_recursive(path: &Path, mode: FilePermission) {
/// Removes a directory at this path, after removing all its contents. Use
/// carefully!
///
/// # Errors
/// # Error
///
/// This function will raise on the `io_error` condition if an error
/// happens. See `file::unlink` and `fs::readdir` for possible error
/// conditions.
pub fn rmdir_recursive(path: &Path) {
let children = readdir(path);
/// This function will return an `Err` value if an error happens. See
/// `file::unlink` and `fs::readdir` for possible error conditions.
pub fn rmdir_recursive(path: &Path) -> IoResult<()> {
let children = if_ok!(readdir(path));
for child in children.iter() {
if child.is_dir() {
rmdir_recursive(child);
if_ok!(rmdir_recursive(child));
} else {
unlink(child);
if_ok!(unlink(child));
}
}
// Directory should now be empty
rmdir(path);
rmdir(path)
}
/// Changes the timestamps for a file's last modification and access time.
/// The file at the path specified will have its last access time set to
/// `atime` and its modification time set to `mtime`. The times specified should
/// be in milliseconds.
///
/// # Errors
///
/// This function will raise on the `io_error` condition if an error
/// happens.
// FIXME(#10301) these arguments should not be u64
pub fn change_file_times(path: &Path, atime: u64, mtime: u64) {
LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime));
pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> {
LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime))
}
impl Reader for File {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
match self.fd.read(buf) {
Ok(read) => {
self.last_nread = read;
match read {
0 => None,
_ => Some(read as uint)
0 => Err(io::standard_error(io::EndOfFile)),
_ => Ok(read as uint)
}
},
Err(ioerr) => {
// EOF is indicated by returning None
if ioerr.kind != io::EndOfFile {
io_error::cond.raise(ioerr);
}
return None;
}
Err(e) => Err(e),
}
}
}
impl Writer for File {
fn write(&mut self, buf: &[u8]) {
match self.fd.write(buf) {
Ok(()) => (),
Err(ioerr) => {
io_error::cond.raise(ioerr);
}
}
}
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.fd.write(buf) }
}
impl Seek for File {
fn tell(&self) -> u64 {
let res = self.fd.tell();
match res {
Ok(cursor) => cursor,
Err(ioerr) => {
io_error::cond.raise(ioerr);
return -1;
}
}
fn tell(&self) -> IoResult<u64> {
self.fd.tell()
}
fn seek(&mut self, pos: i64, style: SeekStyle) {
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
match self.fd.seek(pos, style) {
Ok(_) => {
// successful seek resets EOF indicator
self.last_nread = -1;
()
},
Err(ioerr) => {
io_error::cond.raise(ioerr);
Ok(())
}
Err(e) => Err(e),
}
}
}
@@ -650,17 +605,17 @@ impl path::Path {
/// Consult the `file::stat` documentation for more info.
///
/// This call preserves identical runtime/error semantics with `file::stat`.
pub fn stat(&self) -> FileStat { stat(self) }
pub fn stat(&self) -> IoResult<FileStat> { stat(self) }
/// Boolean value indicator whether the underlying file exists on the local
/// filesystem. This will return true if the path points to either a
/// directory or a file.
///
/// # Errors
/// # Error
///
/// Will not raise a condition
pub fn exists(&self) -> bool {
io::result(|| self.stat()).is_ok()
self.stat().is_ok()
}
/// Whether the underlying implementation (be it a file path, or something
@@ -668,11 +623,11 @@ pub fn exists(&self) -> bool {
/// to non-existent locations or directories or other non-regular files
/// (named pipes, etc).
///
/// # Errors
/// # Error
///
/// Will not raise a condition
pub fn is_file(&self) -> bool {
match io::result(|| self.stat()) {
match self.stat() {
Ok(s) => s.kind == io::TypeFile,
Err(..) => false
}
@@ -683,11 +638,11 @@ pub fn is_file(&self) -> bool {
/// Will return false for paths to non-existent locations or if the item is
/// not a directory (eg files, named pipes, links, etc)
///
/// # Errors
/// # Error
///
/// Will not raise a condition
pub fn is_dir(&self) -> bool {
match io::result(|| self.stat()) {
match self.stat() {
Ok(s) => s.kind == io::TypeDirectory,
Err(..) => false
}
@@ -698,8 +653,7 @@ pub fn is_dir(&self) -> bool {
#[allow(unused_imports)]
mod test {
use prelude::*;
use io::{SeekSet, SeekCur, SeekEnd, io_error, Read, Open,
ReadWrite};
use io::{SeekSet, SeekCur, SeekEnd, Read, Open, ReadWrite};
use io;
use str;
use io::fs::{File, rmdir, mkdir, readdir, rmdir_recursive,
@@ -729,7 +683,7 @@ fn drop(&mut self) {
// Gee, seeing how we're testing the fs module I sure hope that we
// at least implement this correctly!
let TempDir(ref p) = *self;
io::fs::rmdir_recursive(p);
io::fs::rmdir_recursive(p).unwrap();
}
}
@@ -737,7 +691,7 @@ pub fn tmpdir() -> TempDir {
use os;
use rand;
let ret = os::tmpdir().join(format!("rust-{}", rand::random::<u32>()));
io::fs::mkdir(&ret, io::UserRWX);
io::fs::mkdir(&ret, io::UserRWX).unwrap();
TempDir(ret)
}
@@ -747,7 +701,7 @@ pub fn tmpdir() -> TempDir {
let filename = &tmpdir.join("file_rt_io_file_test.txt");
{
let mut write_stream = File::open_mode(filename, Open, ReadWrite);
write_stream.write(message.as_bytes());
write_stream.write(message.as_bytes()).unwrap();
}
{
let mut read_stream = File::open_mode(filename, Open, Read);
@@ -758,30 +712,20 @@ pub fn tmpdir() -> TempDir {
};
assert_eq!(read_str, message.to_owned());
}
unlink(filename);
unlink(filename).unwrap();
})
iotest!(fn invalid_path_raises() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_that_does_not_exist.txt");
let mut called = false;
io_error::cond.trap(|_| {
called = true;
}).inside(|| {
let result = File::open_mode(filename, Open, Read);
assert!(result.is_none());
});
assert!(called);
let result = File::open_mode(filename, Open, Read);
assert!(result.is_err());
})
iotest!(fn file_test_iounlinking_invalid_path_should_raise_condition() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
let mut called = false;
io_error::cond.trap(|_| {
called = true;
}).inside(|| unlink(filename));
assert!(called);
assert!(unlink(filename).is_err());
})
iotest!(fn file_test_io_non_positional_read() {
@@ -791,20 +735,20 @@ pub fn tmpdir() -> TempDir {
let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
{
let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
rw_stream.write(message.as_bytes());
rw_stream.write(message.as_bytes()).unwrap();
}
{
let mut read_stream = File::open_mode(filename, Open, Read);
{
let read_buf = read_mem.mut_slice(0, 4);
read_stream.read(read_buf);
read_stream.read(read_buf).unwrap();
}
{
let read_buf = read_mem.mut_slice(4, 8);
read_stream.read(read_buf);
read_stream.read(read_buf).unwrap();
}
}
unlink(filename);
unlink(filename).unwrap();
let read_str = str::from_utf8(read_mem).unwrap();
assert_eq!(read_str, message);
})
@@ -819,16 +763,16 @@ pub fn tmpdir() -> TempDir {
let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
{
let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
rw_stream.write(message.as_bytes());
rw_stream.write(message.as_bytes()).unwrap();
}
{
let mut read_stream = File::open_mode(filename, Open, Read);
read_stream.seek(set_cursor as i64, SeekSet);
tell_pos_pre_read = read_stream.tell();
read_stream.read(read_mem);
tell_pos_post_read = read_stream.tell();
read_stream.seek(set_cursor as i64, SeekSet).unwrap();
tell_pos_pre_read = read_stream.tell().unwrap();
read_stream.read(read_mem).unwrap();
tell_pos_post_read = read_stream.tell().unwrap();
}
unlink(filename);
unlink(filename).unwrap();
let read_str = str::from_utf8(read_mem).unwrap();
assert_eq!(read_str, message.slice(4, 8));
assert_eq!(tell_pos_pre_read, set_cursor);
@@ -845,15 +789,15 @@ pub fn tmpdir() -> TempDir {
let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
{
let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
rw_stream.write(initial_msg.as_bytes());
rw_stream.seek(seek_idx as i64, SeekSet);
rw_stream.write(overwrite_msg.as_bytes());
rw_stream.write(initial_msg.as_bytes()).unwrap();
rw_stream.seek(seek_idx as i64, SeekSet).unwrap();
rw_stream.write(overwrite_msg.as_bytes()).unwrap();
}
{
let mut read_stream = File::open_mode(filename, Open, Read);
read_stream.read(read_mem);
read_stream.read(read_mem).unwrap();
}
unlink(filename);
unlink(filename).unwrap();
let read_str = str::from_utf8(read_mem).unwrap();
assert!(read_str == final_msg.to_owned());
})
@@ -869,24 +813,24 @@ pub fn tmpdir() -> TempDir {
let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
{
let mut rw_stream = File::open_mode(filename, Open, ReadWrite);
rw_stream.write(initial_msg.as_bytes());
rw_stream.write(initial_msg.as_bytes()).unwrap();
}
{
let mut read_stream = File::open_mode(filename, Open, Read);
read_stream.seek(-4, SeekEnd);
read_stream.read(read_mem);
read_stream.seek(-4, SeekEnd).unwrap();
read_stream.read(read_mem).unwrap();
assert_eq!(str::from_utf8(read_mem).unwrap(), chunk_three);
read_stream.seek(-9, SeekCur);
read_stream.read(read_mem);
read_stream.seek(-9, SeekCur).unwrap();
read_stream.read(read_mem).unwrap();
assert_eq!(str::from_utf8(read_mem).unwrap(), chunk_two);
read_stream.seek(0, SeekSet);
read_stream.read(read_mem);
read_stream.seek(0, SeekSet).unwrap();
read_stream.read(read_mem).unwrap();
assert_eq!(str::from_utf8(read_mem).unwrap(), chunk_one);
}
unlink(filename);
unlink(filename).unwrap();
})
iotest!(fn file_test_stat_is_correct_on_is_file() {
@@ -895,36 +839,36 @@ pub fn tmpdir() -> TempDir {
{
let mut fs = File::open_mode(filename, Open, ReadWrite);
let msg = "hw";
fs.write(msg.as_bytes());
fs.write(msg.as_bytes()).unwrap();
}
let stat_res = stat(filename);
let stat_res = stat(filename).unwrap();
assert_eq!(stat_res.kind, io::TypeFile);
unlink(filename);
unlink(filename).unwrap();
})
iotest!(fn file_test_stat_is_correct_on_is_dir() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_stat_correct_on_is_dir");
mkdir(filename, io::UserRWX);
let stat_res = filename.stat();
mkdir(filename, io::UserRWX).unwrap();
let stat_res = filename.stat().unwrap();
assert!(stat_res.kind == io::TypeDirectory);
rmdir(filename);
rmdir(filename).unwrap();
})
iotest!(fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
let tmpdir = tmpdir();
let dir = &tmpdir.join("fileinfo_false_on_dir");
mkdir(dir, io::UserRWX);
mkdir(dir, io::UserRWX).unwrap();
assert!(dir.is_file() == false);
rmdir(dir);
rmdir(dir).unwrap();
})
iotest!(fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
let tmpdir = tmpdir();
let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
File::create(file).write(bytes!("foo"));
File::create(file).write(bytes!("foo")).unwrap();
assert!(file.exists());
unlink(file);
unlink(file).unwrap();
assert!(!file.exists());
})
@@ -932,10 +876,10 @@ pub fn tmpdir() -> TempDir {
let tmpdir = tmpdir();
let dir = &tmpdir.join("before_and_after_dir");
assert!(!dir.exists());
mkdir(dir, io::UserRWX);
mkdir(dir, io::UserRWX).unwrap();
assert!(dir.exists());
assert!(dir.is_dir());
rmdir(dir);
rmdir(dir).unwrap();
assert!(!dir.exists());
})
@@ -943,21 +887,21 @@ pub fn tmpdir() -> TempDir {
use std::str;
let tmpdir = tmpdir();
let dir = &tmpdir.join("di_readdir");
mkdir(dir, io::UserRWX);
mkdir(dir, io::UserRWX).unwrap();
let prefix = "foo";
for n in range(0,3) {
let f = dir.join(format!("{}.txt", n));
let mut w = File::create(&f);
let mut w = File::create(&f).unwrap();
let msg_str = (prefix + n.to_str().to_owned()).to_owned();
let msg = msg_str.as_bytes();
w.write(msg);
w.write(msg).unwrap();
}
let files = readdir(dir);
let files = readdir(dir).unwrap();
let mut mem = [0u8, .. 4];
for f in files.iter() {
{
let n = f.filestem_str();
File::open(f).read(mem);
File::open(f).read(mem).unwrap();
let read_str = str::from_utf8(mem).unwrap();
let expected = match n {
None|Some("") => fail!("really shouldn't happen.."),
@@ -965,13 +909,13 @@ pub fn tmpdir() -> TempDir {
};
assert_eq!(expected.as_slice(), read_str);
}
unlink(f);
unlink(f).unwrap();
}
rmdir(dir);
rmdir(dir).unwrap();
})
iotest!(fn recursive_mkdir_slash() {
mkdir_recursive(&Path::new("/"), io::UserRWX);
mkdir_recursive(&Path::new("/"), io::UserRWX).unwrap();
})
iotest!(fn unicode_path_is_dir() {
@@ -982,12 +926,12 @@ pub fn tmpdir() -> TempDir {
let mut dirpath = tmpdir.path().clone();
dirpath.push(format!("test-가一ー你好"));
mkdir(&dirpath, io::UserRWX);
mkdir(&dirpath, io::UserRWX).unwrap();
assert!(dirpath.is_dir());
let mut filepath = dirpath;
filepath.push("unicode-file-\uac00\u4e00\u30fc\u4f60\u597d.rs");
File::create(&filepath); // ignore return; touch only
File::create(&filepath).unwrap(); // ignore return; touch only
assert!(!filepath.is_dir());
assert!(filepath.exists());
})
@@ -999,7 +943,7 @@ pub fn tmpdir() -> TempDir {
let tmpdir = tmpdir();
let unicode = tmpdir.path();
let unicode = unicode.join(format!("test-각丁ー再见"));
mkdir(&unicode, io::UserRWX);
mkdir(&unicode, io::UserRWX).unwrap();
assert!(unicode.exists());
assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
})
@@ -1007,7 +951,7 @@ pub fn tmpdir() -> TempDir {
iotest!(fn copy_file_does_not_exist() {
let from = Path::new("test/nonexistent-bogus-path");
let to = Path::new("test/other-bogus-path");
match io::result(|| copy(&from, &to)) {
match copy(&from, &to) {
Ok(..) => fail!(),
Err(..) => {
assert!(!from.exists());
@@ -1021,20 +965,20 @@ pub fn tmpdir() -> TempDir {
let input = tmpdir.join("in.txt");
let out = tmpdir.join("out.txt");
File::create(&input).write(bytes!("hello"));
copy(&input, &out);
let contents = File::open(&out).read_to_end();
File::create(&input).write(bytes!("hello")).unwrap();
copy(&input, &out).unwrap();
let contents = File::open(&out).read_to_end().unwrap();
assert_eq!(contents.as_slice(), bytes!("hello"));
assert_eq!(input.stat().perm, out.stat().perm);
assert_eq!(input.stat().unwrap().perm, out.stat().unwrap().perm);
})
iotest!(fn copy_file_dst_dir() {
let tmpdir = tmpdir();
let out = tmpdir.join("out");
File::create(&out);
match io::result(|| copy(&out, tmpdir.path())) {
File::create(&out).unwrap();
match copy(&out, tmpdir.path()) {
Ok(..) => fail!(), Err(..) => {}
}
})
@@ -1044,11 +988,11 @@ pub fn tmpdir() -> TempDir {
let input = tmpdir.join("in");
let output = tmpdir.join("out");
File::create(&input).write("foo".as_bytes());
File::create(&output).write("bar".as_bytes());
copy(&input, &output);
File::create(&input).write("foo".as_bytes()).unwrap();
File::create(&output).write("bar".as_bytes()).unwrap();
copy(&input, &output).unwrap();
assert_eq!(File::open(&output).read_to_end(),
assert_eq!(File::open(&output).read_to_end().unwrap(),
(bytes!("foo")).to_owned());
})
@@ -1056,7 +1000,7 @@ pub fn tmpdir() -> TempDir {
let tmpdir = tmpdir();
let out = tmpdir.join("out");
match io::result(|| copy(tmpdir.path(), &out)) {
match copy(tmpdir.path(), &out) {
Ok(..) => fail!(), Err(..) => {}
}
assert!(!out.exists());
@@ -1067,13 +1011,13 @@ pub fn tmpdir() -> TempDir {
let input = tmpdir.join("in.txt");
let out = tmpdir.join("out.txt");
File::create(&input);
chmod(&input, io::UserRead);
copy(&input, &out);
assert!(out.stat().perm & io::UserWrite == 0);
File::create(&input).unwrap();
chmod(&input, io::UserRead).unwrap();
copy(&input, &out).unwrap();
assert!(out.stat().unwrap().perm & io::UserWrite == 0);
chmod(&input, io::UserFile);
chmod(&out, io::UserFile);
chmod(&input, io::UserFile).unwrap();
chmod(&out, io::UserFile).unwrap();
})
#[cfg(not(windows))] // FIXME(#10264) operation not permitted?
@@ -1082,26 +1026,27 @@ pub fn tmpdir() -> TempDir {
let input = tmpdir.join("in.txt");
let out = tmpdir.join("out.txt");
File::create(&input).write("foobar".as_bytes());
symlink(&input, &out);
File::create(&input).write("foobar".as_bytes()).unwrap();
symlink(&input, &out).unwrap();
if cfg!(not(windows)) {
assert_eq!(lstat(&out).kind, io::TypeSymlink);
assert_eq!(lstat(&out).unwrap().kind, io::TypeSymlink);
}
assert_eq!(stat(&out).size, stat(&input).size);
assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned());
assert_eq!(stat(&out).unwrap().size, stat(&input).unwrap().size);
assert_eq!(File::open(&out).read_to_end().unwrap(),
(bytes!("foobar")).to_owned());
})
#[cfg(not(windows))] // apparently windows doesn't like symlinks
iotest!(fn symlink_noexist() {
let tmpdir = tmpdir();
// symlinks can point to things that don't exist
symlink(&tmpdir.join("foo"), &tmpdir.join("bar"));
symlink(&tmpdir.join("foo"), &tmpdir.join("bar")).unwrap();
assert!(readlink(&tmpdir.join("bar")).unwrap() == tmpdir.join("foo"));
})
iotest!(fn readlink_not_symlink() {
let tmpdir = tmpdir();
match io::result(|| readlink(tmpdir.path())) {
match readlink(tmpdir.path()) {
Ok(..) => fail!("wanted a failure"),
Err(..) => {}
}
@@ -1112,22 +1057,23 @@ pub fn tmpdir() -> TempDir {
let input = tmpdir.join("in.txt");
let out = tmpdir.join("out.txt");
File::create(&input).write("foobar".as_bytes());
link(&input, &out);
File::create(&input).write("foobar".as_bytes()).unwrap();
link(&input, &out).unwrap();
if cfg!(not(windows)) {
assert_eq!(lstat(&out).kind, io::TypeFile);
assert_eq!(stat(&out).unstable.nlink, 2);
assert_eq!(lstat(&out).unwrap().kind, io::TypeFile);
assert_eq!(stat(&out).unwrap().unstable.nlink, 2);
}
assert_eq!(stat(&out).size, stat(&input).size);
assert_eq!(File::open(&out).read_to_end(), (bytes!("foobar")).to_owned());
assert_eq!(stat(&out).unwrap().size, stat(&input).unwrap().size);
assert_eq!(File::open(&out).read_to_end().unwrap(),
(bytes!("foobar")).to_owned());
// can't link to yourself
match io::result(|| link(&input, &input)) {
match link(&input, &input) {
Ok(..) => fail!("wanted a failure"),
Err(..) => {}
}
// can't link to something that doesn't exist
match io::result(|| link(&tmpdir.join("foo"), &tmpdir.join("bar"))) {
match link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
Ok(..) => fail!("wanted a failure"),
Err(..) => {}
}
@@ -1137,17 +1083,17 @@ pub fn tmpdir() -> TempDir {
let tmpdir = tmpdir();
let file = tmpdir.join("in.txt");
File::create(&file);
assert!(stat(&file).perm & io::UserWrite == io::UserWrite);
chmod(&file, io::UserRead);
assert!(stat(&file).perm & io::UserWrite == 0);
File::create(&file).unwrap();
assert!(stat(&file).unwrap().perm & io::UserWrite == io::UserWrite);
chmod(&file, io::UserRead).unwrap();
assert!(stat(&file).unwrap().perm & io::UserWrite == 0);
match io::result(|| chmod(&tmpdir.join("foo"), io::UserRWX)) {
match chmod(&tmpdir.join("foo"), io::UserRWX) {
Ok(..) => fail!("wanted a failure"),
Err(..) => {}
}
chmod(&file, io::UserFile);
chmod(&file, io::UserFile).unwrap();
})
iotest!(fn sync_doesnt_kill_anything() {
@@ -1155,11 +1101,11 @@ pub fn tmpdir() -> TempDir {
let path = tmpdir.join("in.txt");
let mut file = File::open_mode(&path, io::Open, io::ReadWrite).unwrap();
file.fsync();
file.datasync();
file.write(bytes!("foo"));
file.fsync();
file.datasync();
file.fsync().unwrap();
file.datasync().unwrap();
file.write(bytes!("foo")).unwrap();
file.fsync().unwrap();
file.datasync().unwrap();
drop(file);
})
@@ -1168,28 +1114,28 @@ pub fn tmpdir() -> TempDir {
let path = tmpdir.join("in.txt");
let mut file = File::open_mode(&path, io::Open, io::ReadWrite).unwrap();
file.write(bytes!("foo"));
file.fsync();
file.write(bytes!("foo")).unwrap();
file.fsync().unwrap();
// Do some simple things with truncation
assert_eq!(stat(&path).size, 3);
file.truncate(10);
assert_eq!(stat(&path).size, 10);
file.write(bytes!("bar"));
file.fsync();
assert_eq!(stat(&path).size, 10);
assert_eq!(File::open(&path).read_to_end(),
assert_eq!(stat(&path).unwrap().size, 3);
file.truncate(10).unwrap();
assert_eq!(stat(&path).unwrap().size, 10);
file.write(bytes!("bar")).unwrap();
file.fsync().unwrap();
assert_eq!(stat(&path).unwrap().size, 10);
assert_eq!(File::open(&path).read_to_end().unwrap(),
(bytes!("foobar", 0, 0, 0, 0)).to_owned());
// Truncate to a smaller length, don't seek, and then write something.
// Ensure that the intermediate zeroes are all filled in (we're seeked
// past the end of the file).
file.truncate(2);
assert_eq!(stat(&path).size, 2);
file.write(bytes!("wut"));
file.fsync();
assert_eq!(stat(&path).size, 9);
assert_eq!(File::open(&path).read_to_end(),
file.truncate(2).unwrap();
assert_eq!(stat(&path).unwrap().size, 2);
file.write(bytes!("wut")).unwrap();
file.fsync().unwrap();
assert_eq!(stat(&path).unwrap().size, 9);
assert_eq!(File::open(&path).read_to_end().unwrap(),
(bytes!("fo", 0, 0, 0, 0, "wut")).to_owned());
drop(file);
})
@@ -1197,8 +1143,7 @@ pub fn tmpdir() -> TempDir {
iotest!(fn open_flavors() {
let tmpdir = tmpdir();
match io::result(|| File::open_mode(&tmpdir.join("a"), io::Open,
io::Read)) {
match File::open_mode(&tmpdir.join("a"), io::Open, io::Read) {
Ok(..) => fail!(), Err(..) => {}
}
File::open_mode(&tmpdir.join("b"), io::Open, io::Write).unwrap();
@@ -1208,46 +1153,46 @@ pub fn tmpdir() -> TempDir {
File::open_mode(&tmpdir.join("f"), io::Truncate, io::Write).unwrap();
File::open_mode(&tmpdir.join("g"), io::Truncate, io::ReadWrite).unwrap();
File::create(&tmpdir.join("h")).write("foo".as_bytes());
File::create(&tmpdir.join("h")).write("foo".as_bytes()).unwrap();
File::open_mode(&tmpdir.join("h"), io::Open, io::Read).unwrap();
{
let mut f = File::open_mode(&tmpdir.join("h"), io::Open,
io::Read).unwrap();
match io::result(|| f.write("wut".as_bytes())) {
match f.write("wut".as_bytes()) {
Ok(..) => fail!(), Err(..) => {}
}
}
assert_eq!(stat(&tmpdir.join("h")).size, 3);
assert_eq!(stat(&tmpdir.join("h")).unwrap().size, 3);
{
let mut f = File::open_mode(&tmpdir.join("h"), io::Append,
io::Write).unwrap();
f.write("bar".as_bytes());
f.write("bar".as_bytes()).unwrap();
}
assert_eq!(stat(&tmpdir.join("h")).size, 6);
assert_eq!(stat(&tmpdir.join("h")).unwrap().size, 6);
{
let mut f = File::open_mode(&tmpdir.join("h"), io::Truncate,
io::Write).unwrap();
f.write("bar".as_bytes());
f.write("bar".as_bytes()).unwrap();
}
assert_eq!(stat(&tmpdir.join("h")).size, 3);
assert_eq!(stat(&tmpdir.join("h")).unwrap().size, 3);
})
#[test]
fn utime() {
let tmpdir = tmpdir();
let path = tmpdir.join("a");
File::create(&path);
File::create(&path).unwrap();
change_file_times(&path, 1000, 2000);
assert_eq!(path.stat().accessed, 1000);
assert_eq!(path.stat().modified, 2000);
change_file_times(&path, 1000, 2000).unwrap();
assert_eq!(path.stat().unwrap().accessed, 1000);
assert_eq!(path.stat().unwrap().modified, 2000);
}
#[test]
fn utime_noexist() {
let tmpdir = tmpdir();
match io::result(|| change_file_times(&tmpdir.join("a"), 100, 200)) {
match change_file_times(&tmpdir.join("a"), 100, 200) {
Ok(..) => fail!(),
Err(..) => {}
}
+114 -106
View File
@@ -13,9 +13,10 @@
use cmp::max;
use cmp::min;
use container::Container;
use option::{Option, Some, None};
use super::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, io_error,
OtherIoError};
use option::None;
use result::{Err, Ok};
use io;
use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult};
use vec;
use vec::{Vector, ImmutableVector, MutableVector, OwnedCloneableVector};
@@ -24,6 +25,7 @@
/// # Example
///
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::MemWriter;
///
/// let mut w = MemWriter::new();
@@ -59,7 +61,7 @@ pub fn unwrap(self) -> ~[u8] { self.buf }
}
impl Writer for MemWriter {
fn write(&mut self, buf: &[u8]) {
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
// 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;
@@ -86,14 +88,15 @@ fn write(&mut self, buf: &[u8]) {
// Bump us forward
self.pos += buf.len();
Ok(())
}
}
// FIXME(#10432)
impl Seek for MemWriter {
fn tell(&self) -> u64 { self.pos as u64 }
fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
fn seek(&mut self, pos: i64, style: SeekStyle) {
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
// compute offset as signed and clamp to prevent overflow
let offset = match style {
SeekSet => { 0 }
@@ -102,6 +105,7 @@ fn seek(&mut self, pos: i64, style: SeekStyle) {
} as i64;
self.pos = max(0, offset+pos) as uint;
Ok(())
}
}
@@ -110,11 +114,12 @@ fn seek(&mut self, pos: i64, style: SeekStyle) {
/// # Example
///
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::MemReader;
///
/// let mut r = MemReader::new(~[0, 1, 2]);
///
/// assert_eq!(r.read_to_end(), ~[0, 1, 2]);
/// assert_eq!(r.read_to_end().unwrap(), ~[0, 1, 2]);
/// ```
pub struct MemReader {
priv buf: ~[u8],
@@ -148,8 +153,8 @@ pub fn unwrap(self) -> ~[u8] { self.buf }
}
impl Reader for MemReader {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
if self.eof() { return None }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
if self.eof() { return Err(io::standard_error(io::EndOfFile)) }
let write_len = min(buf.len(), self.buf.len() - self.pos);
{
@@ -161,28 +166,31 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
self.pos += write_len;
assert!(self.pos <= self.buf.len());
return Some(write_len);
return Ok(write_len);
}
}
impl Seek for MemReader {
fn tell(&self) -> u64 { self.pos as u64 }
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
fn seek(&mut self, _pos: i64, _style: SeekStyle) -> IoResult<()> { fail!() }
}
impl Buffer for MemReader {
fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) }
fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> {
Ok(self.buf.slice_from(self.pos))
}
fn consume(&mut self, amt: uint) { self.pos += amt; }
}
/// Writes to a fixed-size byte slice
///
/// If a write will not fit in the buffer, it raises the `io_error`
/// condition and does not write any data.
/// If a write will not fit in the buffer, it returns an error and does not
/// write any data.
///
/// # Example
///
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::BufWriter;
///
/// let mut buf = [0, ..4];
@@ -207,28 +215,28 @@ pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> {
}
impl<'a> Writer for BufWriter<'a> {
fn write(&mut self, buf: &[u8]) {
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
// raises a condition if the entire write does not fit in the buffer
let max_size = self.buf.len();
if self.pos >= max_size || (self.pos + buf.len()) > max_size {
io_error::cond.raise(IoError {
kind: OtherIoError,
return Err(IoError {
kind: io::OtherIoError,
desc: "Trying to write past end of buffer",
detail: None
});
return;
})
}
vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos), buf);
self.pos += buf.len();
Ok(())
}
}
// FIXME(#10432)
impl<'a> Seek for BufWriter<'a> {
fn tell(&self) -> u64 { self.pos as u64 }
fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
fn seek(&mut self, pos: i64, style: SeekStyle) {
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
// compute offset as signed and clamp to prevent overflow
let offset = match style {
SeekSet => { 0 }
@@ -237,6 +245,7 @@ fn seek(&mut self, pos: i64, style: SeekStyle) {
} as i64;
self.pos = max(0, offset+pos) as uint;
Ok(())
}
}
@@ -246,12 +255,13 @@ fn seek(&mut self, pos: i64, style: SeekStyle) {
/// # Example
///
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::io::BufReader;
///
/// let mut buf = [0, 1, 2, 3];
/// let mut r = BufReader::new(buf);
///
/// assert_eq!(r.read_to_end(), ~[0, 1, 2, 3]);
/// assert_eq!(r.read_to_end().unwrap(), ~[0, 1, 2, 3]);
/// ```
pub struct BufReader<'a> {
priv buf: &'a [u8],
@@ -274,8 +284,8 @@ pub fn eof(&self) -> bool { self.pos == self.buf.len() }
}
impl<'a> Reader for BufReader<'a> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
if self.eof() { return None }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
if self.eof() { return Err(io::standard_error(io::EndOfFile)) }
let write_len = min(buf.len(), self.buf.len() - self.pos);
{
@@ -287,18 +297,19 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
self.pos += write_len;
assert!(self.pos <= self.buf.len());
return Some(write_len);
return Ok(write_len);
}
}
impl<'a> Seek for BufReader<'a> {
fn tell(&self) -> u64 { self.pos as u64 }
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
fn seek(&mut self, _pos: i64, _style: SeekStyle) -> IoResult<()> { fail!() }
}
impl<'a> Buffer for BufReader<'a> {
fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) }
fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> {
Ok(self.buf.slice_from(self.pos))
}
fn consume(&mut self, amt: uint) { self.pos += amt; }
}
@@ -307,33 +318,34 @@ mod test {
use prelude::*;
use super::*;
use io::*;
use io;
#[test]
fn test_mem_writer() {
let mut writer = MemWriter::new();
assert_eq!(writer.tell(), 0);
writer.write([0]);
assert_eq!(writer.tell(), 1);
writer.write([1, 2, 3]);
writer.write([4, 5, 6, 7]);
assert_eq!(writer.tell(), 8);
assert_eq!(writer.tell(), Ok(0));
writer.write([0]).unwrap();
assert_eq!(writer.tell(), Ok(1));
writer.write([1, 2, 3]).unwrap();
writer.write([4, 5, 6, 7]).unwrap();
assert_eq!(writer.tell(), Ok(8));
assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7]);
writer.seek(0, SeekSet);
assert_eq!(writer.tell(), 0);
writer.write([3, 4]);
writer.seek(0, SeekSet).unwrap();
assert_eq!(writer.tell(), Ok(0));
writer.write([3, 4]).unwrap();
assert_eq!(writer.get_ref(), [3, 4, 2, 3, 4, 5, 6, 7]);
writer.seek(1, SeekCur);
writer.write([0, 1]);
writer.seek(1, SeekCur).unwrap();
writer.write([0, 1]).unwrap();
assert_eq!(writer.get_ref(), [3, 4, 2, 0, 1, 5, 6, 7]);
writer.seek(-1, SeekEnd);
writer.write([1, 2]);
writer.seek(-1, SeekEnd).unwrap();
writer.write([1, 2]).unwrap();
assert_eq!(writer.get_ref(), [3, 4, 2, 0, 1, 5, 6, 1, 2]);
writer.seek(1, SeekEnd);
writer.write([1]);
writer.seek(1, SeekEnd).unwrap();
writer.write([1]).unwrap();
assert_eq!(writer.get_ref(), [3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]);
}
@@ -342,12 +354,12 @@ fn test_buf_writer() {
let mut buf = [0 as u8, ..8];
{
let mut writer = BufWriter::new(buf);
assert_eq!(writer.tell(), 0);
writer.write([0]);
assert_eq!(writer.tell(), 1);
writer.write([1, 2, 3]);
writer.write([4, 5, 6, 7]);
assert_eq!(writer.tell(), 8);
assert_eq!(writer.tell(), Ok(0));
writer.write([0]).unwrap();
assert_eq!(writer.tell(), Ok(1));
writer.write([1, 2, 3]).unwrap();
writer.write([4, 5, 6, 7]).unwrap();
assert_eq!(writer.tell(), Ok(8));
}
assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7]);
}
@@ -357,24 +369,24 @@ fn test_buf_writer_seek() {
let mut buf = [0 as u8, ..8];
{
let mut writer = BufWriter::new(buf);
assert_eq!(writer.tell(), 0);
writer.write([1]);
assert_eq!(writer.tell(), 1);
assert_eq!(writer.tell(), Ok(0));
writer.write([1]).unwrap();
assert_eq!(writer.tell(), Ok(1));
writer.seek(2, SeekSet);
assert_eq!(writer.tell(), 2);
writer.write([2]);
assert_eq!(writer.tell(), 3);
writer.seek(2, SeekSet).unwrap();
assert_eq!(writer.tell(), Ok(2));
writer.write([2]).unwrap();
assert_eq!(writer.tell(), Ok(3));
writer.seek(-2, SeekCur);
assert_eq!(writer.tell(), 1);
writer.write([3]);
assert_eq!(writer.tell(), 2);
writer.seek(-2, SeekCur).unwrap();
assert_eq!(writer.tell(), Ok(1));
writer.write([3]).unwrap();
assert_eq!(writer.tell(), Ok(2));
writer.seek(-1, SeekEnd);
assert_eq!(writer.tell(), 7);
writer.write([4]);
assert_eq!(writer.tell(), 8);
writer.seek(-1, SeekEnd).unwrap();
assert_eq!(writer.tell(), Ok(7));
writer.write([4]).unwrap();
assert_eq!(writer.tell(), Ok(8));
}
assert_eq!(buf, [1, 3, 2, 0, 0, 0, 0, 4]);
@@ -384,35 +396,31 @@ fn test_buf_writer_seek() {
fn test_buf_writer_error() {
let mut buf = [0 as u8, ..2];
let mut writer = BufWriter::new(buf);
writer.write([0]);
writer.write([0]).unwrap();
let mut called = false;
io_error::cond.trap(|err| {
assert_eq!(err.kind, OtherIoError);
called = true;
}).inside(|| {
writer.write([0, 0]);
});
assert!(called);
match writer.write([0, 0]) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::OtherIoError),
}
}
#[test]
fn test_mem_reader() {
let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]);
let mut buf = [];
assert_eq!(reader.read(buf), Some(0));
assert_eq!(reader.tell(), 0);
assert_eq!(reader.read(buf), Ok(0));
assert_eq!(reader.tell(), Ok(0));
let mut buf = [0];
assert_eq!(reader.read(buf), Some(1));
assert_eq!(reader.tell(), 1);
assert_eq!(reader.read(buf), Ok(1));
assert_eq!(reader.tell(), Ok(1));
assert_eq!(buf, [0]);
let mut buf = [0, ..4];
assert_eq!(reader.read(buf), Some(4));
assert_eq!(reader.tell(), 5);
assert_eq!(reader.read(buf), Ok(4));
assert_eq!(reader.tell(), Ok(5));
assert_eq!(buf, [1, 2, 3, 4]);
assert_eq!(reader.read(buf), Some(3));
assert_eq!(reader.read(buf), Ok(3));
assert_eq!(buf.slice(0, 3), [5, 6, 7]);
assert_eq!(reader.read(buf), None);
assert!(reader.read(buf).is_err());
}
#[test]
@@ -420,64 +428,64 @@ fn test_buf_reader() {
let in_buf = ~[0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = BufReader::new(in_buf);
let mut buf = [];
assert_eq!(reader.read(buf), Some(0));
assert_eq!(reader.tell(), 0);
assert_eq!(reader.read(buf), Ok(0));
assert_eq!(reader.tell(), Ok(0));
let mut buf = [0];
assert_eq!(reader.read(buf), Some(1));
assert_eq!(reader.tell(), 1);
assert_eq!(reader.read(buf), Ok(1));
assert_eq!(reader.tell(), Ok(1));
assert_eq!(buf, [0]);
let mut buf = [0, ..4];
assert_eq!(reader.read(buf), Some(4));
assert_eq!(reader.tell(), 5);
assert_eq!(reader.read(buf), Ok(4));
assert_eq!(reader.tell(), Ok(5));
assert_eq!(buf, [1, 2, 3, 4]);
assert_eq!(reader.read(buf), Some(3));
assert_eq!(reader.read(buf), Ok(3));
assert_eq!(buf.slice(0, 3), [5, 6, 7]);
assert_eq!(reader.read(buf), None);
assert!(reader.read(buf).is_err());
}
#[test]
fn test_read_char() {
let b = bytes!("Việt");
let mut r = BufReader::new(b);
assert_eq!(r.read_char(), Some('V'));
assert_eq!(r.read_char(), Some('i'));
assert_eq!(r.read_char(), Some('ệ'));
assert_eq!(r.read_char(), Some('t'));
assert_eq!(r.read_char(), None);
assert_eq!(r.read_char(), Ok('V'));
assert_eq!(r.read_char(), Ok('i'));
assert_eq!(r.read_char(), Ok('ệ'));
assert_eq!(r.read_char(), Ok('t'));
assert!(r.read_char().is_err());
}
#[test]
fn test_read_bad_char() {
let b = bytes!(0x80);
let mut r = BufReader::new(b);
assert_eq!(r.read_char(), None);
assert!(r.read_char().is_err());
}
#[test]
fn test_write_strings() {
let mut writer = MemWriter::new();
writer.write_str("testing");
writer.write_line("testing");
writer.write_str("testing");
writer.write_str("testing").unwrap();
writer.write_line("testing").unwrap();
writer.write_str("testing").unwrap();
let mut r = BufReader::new(writer.get_ref());
assert_eq!(r.read_to_str(), ~"testingtesting\ntesting");
assert_eq!(r.read_to_str().unwrap(), ~"testingtesting\ntesting");
}
#[test]
fn test_write_char() {
let mut writer = MemWriter::new();
writer.write_char('a');
writer.write_char('\n');
writer.write_char('ệ');
writer.write_char('a').unwrap();
writer.write_char('\n').unwrap();
writer.write_char('ệ').unwrap();
let mut r = BufReader::new(writer.get_ref());
assert_eq!(r.read_to_str(), ~"a\n");
assert_eq!(r.read_to_str().unwrap(), ~"a\n");
}
#[test]
fn test_read_whole_string_bad() {
let buf = [0xff];
let mut r = BufReader::new(buf);
match result(|| r.read_to_str()) {
match r.read_to_str() {
Ok(..) => fail!(),
Err(..) => {}
}
+334 -392
View File
@@ -29,7 +29,6 @@
use std::io::BufferedReader;
use std::io::stdin;
# let _g = ::std::io::ignore_io_error();
let mut stdin = BufferedReader::new(stdin());
for line in stdin.lines() {
print!("{}", line);
@@ -41,16 +40,15 @@
```rust
use std::io::File;
# let _g = ::std::io::ignore_io_error();
let contents = File::open(&Path::new("message.txt")).read_to_end();
```
* Write a line to a file
```rust
# #[allow(unused_must_use)];
use std::io::File;
# let _g = ::std::io::ignore_io_error();
let mut file = File::create(&Path::new("message.txt"));
file.write(bytes!("hello, file!\n"));
# drop(file);
@@ -63,7 +61,6 @@
use std::io::BufferedReader;
use std::io::File;
# let _g = ::std::io::ignore_io_error();
let path = Path::new("message.txt");
let mut file = BufferedReader::new(File::open(&path));
for line in file.lines() {
@@ -77,7 +74,6 @@
use std::io::BufferedReader;
use std::io::File;
# let _g = ::std::io::ignore_io_error();
let path = Path::new("message.txt");
let mut file = BufferedReader::new(File::open(&path));
let lines: ~[~str] = file.lines().collect();
@@ -88,10 +84,10 @@
`write_str` and `write_line` methods.
```rust,should_fail
# #[allow(unused_must_use)];
use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
# let _g = ::std::io::ignore_io_error();
let addr = from_str::<SocketAddr>("127.0.0.1:8080").unwrap();
let mut socket = TcpStream::connect(addr).unwrap();
socket.write(bytes!("GET / HTTP/1.0\n\n"));
@@ -168,72 +164,51 @@
# Error Handling
I/O is an area where nearly every operation can result in unexpected
errors. It should allow errors to be handled efficiently.
It needs to be convenient to use I/O when you don't care
about dealing with specific errors.
errors. Errors should be painfully visible when they happen, and handling them
should be easy to work with. It should be convenient to handle specific I/O
errors, and it should also be convenient to not deal with I/O errors.
Rust's I/O employs a combination of techniques to reduce boilerplate
while still providing feedback about errors. The basic strategy:
* Errors are fatal by default, resulting in task failure
* Errors raise the `io_error` condition which provides an opportunity to inspect
an IoError object containing details.
* Return values must have a sensible null or zero value which is returned
if a condition is handled successfully. This may be an `Option`, an empty
vector, or other designated error value.
* Common traits are implemented for `Option`, e.g. `impl<R: Reader> Reader for Option<R>`,
so that nullable values do not have to be 'unwrapped' before use.
* All I/O operations return `IoResult<T>` which is equivalent to
`Result<T, IoError>`. The core `Result` type is defined in the `std::result`
module.
* If the `Result` type goes unused, then the compiler will by default emit a
warning about the unused result.
* Common traits are implemented for `IoResult`, e.g.
`impl<R: Reader> Reader for IoResult<R>`, so that error values do not have
to be 'unwrapped' before use.
These features combine in the API to allow for expressions like
`File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n"))`
without having to worry about whether "diary.txt" exists or whether
the write succeeds. As written, if either `new` or `write_line`
encounters an error the task will fail.
encounters an error then the result of the entire expression will
be an error.
If you wanted to handle the error though you might write:
```rust
# #[allow(unused_must_use)];
use std::io::File;
use std::io::{IoError, io_error};
let mut error = None;
io_error::cond.trap(|e: IoError| {
error = Some(e);
}).inside(|| {
File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n"));
});
if error.is_some() {
println!("failed to write my diary");
match File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n")) {
Ok(()) => { /* succeeded */ }
Err(e) => println!("failed to write to my diary: {}", e),
}
# ::std::io::fs::unlink(&Path::new("diary.txt"));
```
FIXME: Need better condition handling syntax
In this case the condition handler will have the opportunity to
inspect the IoError raised by either the call to `new` or the call to
`write_line`, but then execution will continue.
So what actually happens if `new` encounters an error? To understand
that it's important to know that what `new` returns is not a `File`
but an `Option<File>`. If the file does not open, and the condition
is handled, then `new` will simply return `None`. Because there is an
implementation of `Writer` (the trait required ultimately required for
types to implement `write_line`) there is no need to inspect or unwrap
the `Option<File>` and we simply call `write_line` on it. If `new`
returned a `None` then the followup call to `write_line` will also
raise an error.
## Concerns about this strategy
This structure will encourage a programming style that is prone
to errors similar to null pointer dereferences.
In particular code written to ignore errors and expect conditions to be unhandled
will start passing around null or zero objects when wrapped in a condition handler.
* FIXME: How should we use condition handlers that return values?
* FIXME: Should EOF raise default conditions when EOF is not an error?
So what actually happens if `create` encounters an error?
It's important to know that what `new` returns is not a `File`
but an `IoResult<File>`. If the file does not open, then `new` will simply
return `Err(..)`. Because there is an implementation of `Writer` (the trait
required ultimately required for types to implement `write_line`) there is no
need to inspect or unwrap the `IoResult<File>` and we simply call `write_line`
on it. If `new` returned an `Err(..)` then the followup call to `write_line`
will also return an error.
# Issues with i/o scheduler affinity, work stealing, task pinning
@@ -287,18 +262,19 @@
*/
#[allow(missing_doc)];
#[deny(unused_must_use)];
use cast;
use char::Char;
use condition::Guard;
use container::Container;
use fmt;
use int;
use iter::Iterator;
use option::{Option, Some, None};
use path::Path;
use result::{Ok, Err, Result};
use str;
use str::{StrSlice, OwnedStr};
use str;
use to_str::ToStr;
use uint;
use unstable::finally::Finally;
@@ -347,8 +323,8 @@
/// Non-blocking access to stdin, stdout, stderr
pub mod stdio;
/// Implementations for Option
mod option;
/// Implementations for Result
mod result;
/// Extension traits
pub mod extensions;
@@ -373,17 +349,30 @@
// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA
static DEFAULT_BUF_SIZE: uint = 1024 * 64;
pub type IoResult<T> = Result<T, IoError>;
/// The type passed to I/O condition handlers to indicate error
///
/// # FIXME
///
/// Is something like this sufficient? It's kind of archaic
#[deriving(Eq, Clone)]
pub struct IoError {
kind: IoErrorKind,
desc: &'static str,
detail: Option<~str>
}
impl fmt::Show for IoError {
fn fmt(err: &IoError, fmt: &mut fmt::Formatter) -> fmt::Result {
if_ok!(fmt.buf.write_str(err.desc));
match err.detail {
Some(ref s) => write!(fmt.buf, " ({})", *s),
None => Ok(())
}
}
}
// FIXME: #8242 implementing manually because deriving doesn't work for some reason
impl ToStr for IoError {
fn to_str(&self) -> ~str {
@@ -398,9 +387,8 @@ fn to_str(&self) -> ~str {
}
}
#[deriving(Eq)]
#[deriving(Eq, Clone)]
pub enum IoErrorKind {
PreviousIoError,
OtherIoError,
EndOfFile,
FileNotFound,
@@ -424,7 +412,6 @@ pub enum IoErrorKind {
impl ToStr for IoErrorKind {
fn to_str(&self) -> ~str {
match *self {
PreviousIoError => ~"PreviousIoError",
OtherIoError => ~"OtherIoError",
EndOfFile => ~"EndOfFile",
FileNotFound => ~"FileNotFound",
@@ -446,184 +433,130 @@ fn to_str(&self) -> ~str {
}
}
// FIXME: Can't put doc comments on macros
// Raised by `I/O` operations on error.
condition! {
pub io_error: IoError -> ();
}
/// Helper for wrapper calls where you want to
/// ignore any io_errors that might be raised
pub fn ignore_io_error() -> Guard<'static,IoError,()> {
io_error::cond.trap(|_| {
// just swallow the error.. downstream users
// who can make a decision based on a None result
// won't care
}).guard()
}
/// Helper for catching an I/O error and wrapping it in a Result object. The
/// return result will be the last I/O error that happened or the result of the
/// closure if no error occurred.
pub fn result<T>(cb: || -> T) -> Result<T, IoError> {
let mut err = None;
let ret = io_error::cond.trap(|e| {
if err.is_none() {
err = Some(e);
}
}).inside(cb);
match err {
Some(e) => Err(e),
None => Ok(ret),
}
}
pub trait Reader {
// Only two methods which need to get implemented for this trait
// Only method which need to get implemented for this trait
/// Read bytes, up to the length of `buf` and place them in `buf`.
/// Returns the number of bytes read. The number of bytes read my
/// be less than the number requested, even 0. Returns `None` on EOF.
/// be less than the number requested, even 0. Returns `Err` on EOF.
///
/// # Failure
/// # Error
///
/// 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` (FIXME see below).
///
/// # FIXME
///
/// * Should raise_default error on eof?
/// * If the condition is handled it should still return the bytes read,
/// in which case there's no need to return Option - but then you *have*
/// to install a handler to detect eof.
///
/// This doesn't take a `len` argument like the old `read`.
/// Will people often need to slice their vectors to call this
/// and will that be annoying?
/// Is it actually possible for 0 bytes to be read successfully?
fn read(&mut self, buf: &mut [u8]) -> Option<uint>;
/// If an error occurs during this I/O operation, then it is returned as
/// `Err(IoError)`. Note that end-of-file is considered an error, and can be
/// inspected for in the error's `kind` field. Also note that reading 0
/// bytes is not considered an error in all circumstances
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>;
// Convenient helper methods based on the above methods
/// Reads a single byte. Returns `None` on EOF.
///
/// # Failure
///
/// Raises the same conditions as the `read` method. Returns
/// `None` if the condition is handled.
fn read_byte(&mut self) -> Option<u8> {
/// Reads a single byte. Returns `Err` on EOF.
fn read_byte(&mut self) -> IoResult<u8> {
let mut buf = [0];
match self.read(buf) {
Some(0) => {
debug!("read 0 bytes. trying again");
self.read_byte()
loop {
match self.read(buf) {
Ok(0) => {
debug!("read 0 bytes. trying again");
}
Ok(1) => return Ok(buf[0]),
Ok(_) => unreachable!(),
Err(e) => return Err(e)
}
Some(1) => Some(buf[0]),
Some(_) => unreachable!(),
None => None
}
}
/// Reads `len` bytes and appends them to a vector.
///
/// May push fewer than the requested number of bytes on error
/// or EOF. Returns true on success, false on EOF or error.
///
/// # Failure
///
/// 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) {
unsafe {
let start_len = buf.len();
let mut total_read = 0;
/// or EOF. If `Ok(())` is returned, then all of the requested bytes were
/// pushed on to the vector, otherwise the amount `len` bytes couldn't be
/// read (an error was encountered), and the error is returned.
fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) -> IoResult<()> {
let start_len = buf.len();
let mut total_read = 0;
buf.reserve_additional(len);
buf.set_len(start_len + len);
buf.reserve_additional(len);
unsafe { buf.set_len(start_len + len); }
(|| {
while total_read < len {
let len = buf.len();
let slice = buf.mut_slice(start_len + total_read, len);
match self.read(slice) {
Some(nread) => {
total_read += nread;
}
None => {
io_error::cond.raise(standard_error(EndOfFile));
break;
}
(|| {
while total_read < len {
let len = buf.len();
let slice = buf.mut_slice(start_len + total_read, len);
match self.read(slice) {
Ok(nread) => {
total_read += nread;
}
Err(e) => return Err(e)
}
}).finally(|| buf.set_len(start_len + total_read))
}
}
Ok(())
}).finally(|| unsafe { buf.set_len(start_len + total_read) })
}
/// Reads `len` bytes and gives you back a new vector of length `len`
///
/// # Failure
/// # Error
///
/// 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] {
/// Fails with the same conditions as `read`. Additionally returns error on
/// on EOF. Note that if an error is returned, then some number of bytes may
/// have already been consumed from the underlying reader, and they are lost
/// (not returned as part of the error). If this is unacceptable, then it is
/// recommended to use the `push_bytes` or `read` methods.
fn read_bytes(&mut self, len: uint) -> IoResult<~[u8]> {
let mut buf = vec::with_capacity(len);
self.push_bytes(&mut buf, len);
return buf;
match self.push_bytes(&mut buf, len) {
Ok(()) => Ok(buf),
Err(e) => Err(e),
}
}
/// Reads all remaining bytes from the stream.
///
/// # Failure
/// # Error
///
/// Raises the same conditions as the `read` method except for
/// `EndOfFile` which is swallowed.
fn read_to_end(&mut self) -> ~[u8] {
/// Returns any non-EOF error immediately. Previously read bytes are
/// discarded when an error is returned.
///
/// When EOF is encountered, all bytes read up to that point are returned.
fn read_to_end(&mut self) -> IoResult<~[u8]> {
let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE);
let mut keep_reading = true;
io_error::cond.trap(|e| {
if e.kind == EndOfFile {
keep_reading = false;
} else {
io_error::cond.raise(e)
loop {
match self.push_bytes(&mut buf, DEFAULT_BUF_SIZE) {
Ok(()) => {}
Err(ref e) if e.kind == EndOfFile => break,
Err(e) => return Err(e)
}
}).inside(|| {
while keep_reading {
self.push_bytes(&mut buf, DEFAULT_BUF_SIZE)
}
});
return buf;
}
return Ok(buf);
}
/// Reads all of the remaining bytes of this stream, interpreting them as a
/// UTF-8 encoded stream. The corresponding string is returned.
///
/// # Failure
/// # Error
///
/// This function will raise all the same conditions as the `read` method,
/// along with raising a condition if the input is not valid UTF-8.
fn read_to_str(&mut self) -> ~str {
match str::from_utf8_owned(self.read_to_end()) {
Some(s) => s,
None => {
io_error::cond.raise(standard_error(InvalidInput));
~""
/// This function returns all of the same errors as `read_to_end` with an
/// additional error if the reader's contents are not a valid sequence of
/// UTF-8 bytes.
fn read_to_str(&mut self) -> IoResult<~str> {
self.read_to_end().and_then(|s| {
match str::from_utf8_owned(s) {
Some(s) => Ok(s),
None => Err(standard_error(InvalidInput)),
}
}
})
}
/// Create an iterator that reads a single byte on
/// each iteration, until EOF.
///
/// # Failure
/// # Error
///
/// Raises the same conditions as the `read` method, for
/// each call to its `.next()` method.
/// Ends the iteration if the condition is handled.
/// The iterator protocol causes all specifics about errors encountered to
/// be swallowed. All errors will be signified by returning `None` from the
/// iterator. If this is undesirable, it is recommended to use the
/// `read_byte` method.
fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self> {
extensions::Bytes::new(self)
}
@@ -633,225 +566,219 @@ fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self> {
/// Reads `n` little-endian unsigned integer bytes.
///
/// `n` must be between 1 and 8, inclusive.
fn read_le_uint_n(&mut self, nbytes: uint) -> u64 {
fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult<u64> {
assert!(nbytes > 0 && nbytes <= 8);
let mut val = 0u64;
let mut pos = 0;
let mut i = nbytes;
while i > 0 {
val += (self.read_u8() as u64) << pos;
val += (if_ok!(self.read_u8()) as u64) << pos;
pos += 8;
i -= 1;
}
val
Ok(val)
}
/// Reads `n` little-endian signed integer bytes.
///
/// `n` must be between 1 and 8, inclusive.
fn read_le_int_n(&mut self, nbytes: uint) -> i64 {
extend_sign(self.read_le_uint_n(nbytes), nbytes)
fn read_le_int_n(&mut self, nbytes: uint) -> IoResult<i64> {
self.read_le_uint_n(nbytes).map(|i| extend_sign(i, nbytes))
}
/// Reads `n` big-endian unsigned integer bytes.
///
/// `n` must be between 1 and 8, inclusive.
fn read_be_uint_n(&mut self, nbytes: uint) -> u64 {
fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult<u64> {
assert!(nbytes > 0 && nbytes <= 8);
let mut val = 0u64;
let mut i = nbytes;
while i > 0 {
i -= 1;
val += (self.read_u8() as u64) << i * 8;
val += (if_ok!(self.read_u8()) as u64) << i * 8;
}
val
Ok(val)
}
/// Reads `n` big-endian signed integer bytes.
///
/// `n` must be between 1 and 8, inclusive.
fn read_be_int_n(&mut self, nbytes: uint) -> i64 {
extend_sign(self.read_be_uint_n(nbytes), nbytes)
fn read_be_int_n(&mut self, nbytes: uint) -> IoResult<i64> {
self.read_be_uint_n(nbytes).map(|i| extend_sign(i, nbytes))
}
/// Reads a little-endian unsigned integer.
///
/// The number of bytes returned is system-dependant.
fn read_le_uint(&mut self) -> uint {
self.read_le_uint_n(uint::BYTES) as uint
fn read_le_uint(&mut self) -> IoResult<uint> {
self.read_le_uint_n(uint::BYTES).map(|i| i as uint)
}
/// Reads a little-endian integer.
///
/// The number of bytes returned is system-dependant.
fn read_le_int(&mut self) -> int {
self.read_le_int_n(int::BYTES) as int
fn read_le_int(&mut self) -> IoResult<int> {
self.read_le_int_n(int::BYTES).map(|i| i as int)
}
/// Reads a big-endian unsigned integer.
///
/// The number of bytes returned is system-dependant.
fn read_be_uint(&mut self) -> uint {
self.read_be_uint_n(uint::BYTES) as uint
fn read_be_uint(&mut self) -> IoResult<uint> {
self.read_be_uint_n(uint::BYTES).map(|i| i as uint)
}
/// Reads a big-endian integer.
///
/// The number of bytes returned is system-dependant.
fn read_be_int(&mut self) -> int {
self.read_be_int_n(int::BYTES) as int
fn read_be_int(&mut self) -> IoResult<int> {
self.read_be_int_n(int::BYTES).map(|i| i as int)
}
/// Reads a big-endian `u64`.
///
/// `u64`s are 8 bytes long.
fn read_be_u64(&mut self) -> u64 {
fn read_be_u64(&mut self) -> IoResult<u64> {
self.read_be_uint_n(8)
}
/// Reads a big-endian `u32`.
///
/// `u32`s are 4 bytes long.
fn read_be_u32(&mut self) -> u32 {
self.read_be_uint_n(4) as u32
fn read_be_u32(&mut self) -> IoResult<u32> {
self.read_be_uint_n(4).map(|i| i as u32)
}
/// Reads a big-endian `u16`.
///
/// `u16`s are 2 bytes long.
fn read_be_u16(&mut self) -> u16 {
self.read_be_uint_n(2) as u16
fn read_be_u16(&mut self) -> IoResult<u16> {
self.read_be_uint_n(2).map(|i| i as u16)
}
/// Reads a big-endian `i64`.
///
/// `i64`s are 8 bytes long.
fn read_be_i64(&mut self) -> i64 {
fn read_be_i64(&mut self) -> IoResult<i64> {
self.read_be_int_n(8)
}
/// Reads a big-endian `i32`.
///
/// `i32`s are 4 bytes long.
fn read_be_i32(&mut self) -> i32 {
self.read_be_int_n(4) as i32
fn read_be_i32(&mut self) -> IoResult<i32> {
self.read_be_int_n(4).map(|i| i as i32)
}
/// Reads a big-endian `i16`.
///
/// `i16`s are 2 bytes long.
fn read_be_i16(&mut self) -> i16 {
self.read_be_int_n(2) as i16
fn read_be_i16(&mut self) -> IoResult<i16> {
self.read_be_int_n(2).map(|i| i as i16)
}
/// Reads a big-endian `f64`.
///
/// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
fn read_be_f64(&mut self) -> f64 {
unsafe {
cast::transmute::<u64, f64>(self.read_be_u64())
}
fn read_be_f64(&mut self) -> IoResult<f64> {
self.read_be_u64().map(|i| unsafe {
cast::transmute::<u64, f64>(i)
})
}
/// Reads a big-endian `f32`.
///
/// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
fn read_be_f32(&mut self) -> f32 {
unsafe {
cast::transmute::<u32, f32>(self.read_be_u32())
}
fn read_be_f32(&mut self) -> IoResult<f32> {
self.read_be_u32().map(|i| unsafe {
cast::transmute::<u32, f32>(i)
})
}
/// Reads a little-endian `u64`.
///
/// `u64`s are 8 bytes long.
fn read_le_u64(&mut self) -> u64 {
fn read_le_u64(&mut self) -> IoResult<u64> {
self.read_le_uint_n(8)
}
/// Reads a little-endian `u32`.
///
/// `u32`s are 4 bytes long.
fn read_le_u32(&mut self) -> u32 {
self.read_le_uint_n(4) as u32
fn read_le_u32(&mut self) -> IoResult<u32> {
self.read_le_uint_n(4).map(|i| i as u32)
}
/// Reads a little-endian `u16`.
///
/// `u16`s are 2 bytes long.
fn read_le_u16(&mut self) -> u16 {
self.read_le_uint_n(2) as u16
fn read_le_u16(&mut self) -> IoResult<u16> {
self.read_le_uint_n(2).map(|i| i as u16)
}
/// Reads a little-endian `i64`.
///
/// `i64`s are 8 bytes long.
fn read_le_i64(&mut self) -> i64 {
fn read_le_i64(&mut self) -> IoResult<i64> {
self.read_le_int_n(8)
}
/// Reads a little-endian `i32`.
///
/// `i32`s are 4 bytes long.
fn read_le_i32(&mut self) -> i32 {
self.read_le_int_n(4) as i32
fn read_le_i32(&mut self) -> IoResult<i32> {
self.read_le_int_n(4).map(|i| i as i32)
}
/// Reads a little-endian `i16`.
///
/// `i16`s are 2 bytes long.
fn read_le_i16(&mut self) -> i16 {
self.read_le_int_n(2) as i16
fn read_le_i16(&mut self) -> IoResult<i16> {
self.read_le_int_n(2).map(|i| i as i16)
}
/// Reads a little-endian `f64`.
///
/// `f64`s are 8 byte, IEEE754 double-precision floating point numbers.
fn read_le_f64(&mut self) -> f64 {
unsafe {
cast::transmute::<u64, f64>(self.read_le_u64())
}
fn read_le_f64(&mut self) -> IoResult<f64> {
self.read_le_u64().map(|i| unsafe {
cast::transmute::<u64, f64>(i)
})
}
/// Reads a little-endian `f32`.
///
/// `f32`s are 4 byte, IEEE754 single-precision floating point numbers.
fn read_le_f32(&mut self) -> f32 {
unsafe {
cast::transmute::<u32, f32>(self.read_le_u32())
}
fn read_le_f32(&mut self) -> IoResult<f32> {
self.read_le_u32().map(|i| unsafe {
cast::transmute::<u32, f32>(i)
})
}
/// Read a u8.
///
/// `u8`s are 1 byte.
fn read_u8(&mut self) -> u8 {
match self.read_byte() {
Some(b) => b,
None => 0
}
fn read_u8(&mut self) -> IoResult<u8> {
self.read_byte()
}
/// Read an i8.
///
/// `i8`s are 1 byte.
fn read_i8(&mut self) -> i8 {
match self.read_byte() {
Some(b) => b as i8,
None => 0
}
fn read_i8(&mut self) -> IoResult<i8> {
self.read_byte().map(|i| i as i8)
}
}
impl Reader for ~Reader {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
}
impl<'a> Reader for &'a mut Reader {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) }
}
fn extend_sign(val: u64, nbytes: uint) -> i64 {
@@ -860,19 +787,22 @@ fn extend_sign(val: u64, nbytes: uint) -> i64 {
}
pub trait Writer {
/// Write the given buffer
/// Write the entirety of a given buffer
///
/// # Failure
/// # Errors
///
/// Raises the `io_error` condition on error
fn write(&mut self, buf: &[u8]);
/// If an error happens during the I/O operation, the error is returned as
/// `Err`. Note that it is considered an error if the entire buffer could
/// not be written, and if an error is returned then it is unknown how much
/// data (if any) was actually written.
fn write(&mut self, buf: &[u8]) -> IoResult<()>;
/// Flush this output stream, ensuring that all intermediately buffered
/// contents reach their destination.
///
/// This is by default a no-op and implementers of the `Writer` trait should
/// decide whether their stream needs to be buffered or not.
fn flush(&mut self) {}
fn flush(&mut self) -> IoResult<()> { Ok(()) }
/// Write a rust string into this sink.
///
@@ -880,8 +810,8 @@ fn flush(&mut self) {}
/// If other encodings are desired, it is recommended to compose this stream
/// with another performing the conversion, or to use `write` with a
/// converted byte-array instead.
fn write_str(&mut self, s: &str) {
self.write(s.as_bytes());
fn write_str(&mut self, s: &str) -> IoResult<()> {
self.write(s.as_bytes())
}
/// Writes a string into this sink, and then writes a literal newline (`\n`)
@@ -891,125 +821,124 @@ fn write_str(&mut self, s: &str) {
///
/// If other encodings or line ending flavors are desired, it is recommended
/// that the `write` method is used specifically instead.
fn write_line(&mut self, s: &str) {
self.write_str(s);
self.write(['\n' as u8]);
fn write_line(&mut self, s: &str) -> IoResult<()> {
self.write_str(s).and_then(|()| self.write(['\n' as u8]))
}
/// Write a single char, encoded as UTF-8.
fn write_char(&mut self, c: char) {
fn write_char(&mut self, c: char) -> IoResult<()> {
let mut buf = [0u8, ..4];
let n = c.encode_utf8(buf.as_mut_slice());
self.write(buf.slice_to(n));
self.write(buf.slice_to(n))
}
/// Write the result of passing n through `int::to_str_bytes`.
fn write_int(&mut self, n: int) {
fn write_int(&mut self, n: int) -> IoResult<()> {
int::to_str_bytes(n, 10u, |bytes| self.write(bytes))
}
/// Write the result of passing n through `uint::to_str_bytes`.
fn write_uint(&mut self, n: uint) {
fn write_uint(&mut self, n: uint) -> IoResult<()> {
uint::to_str_bytes(n, 10u, |bytes| self.write(bytes))
}
/// Write a little-endian uint (number of bytes depends on system).
fn write_le_uint(&mut self, n: uint) {
fn write_le_uint(&mut self, n: uint) -> IoResult<()> {
extensions::u64_to_le_bytes(n as u64, uint::BYTES, |v| self.write(v))
}
/// Write a little-endian int (number of bytes depends on system).
fn write_le_int(&mut self, n: int) {
fn write_le_int(&mut self, n: int) -> IoResult<()> {
extensions::u64_to_le_bytes(n as u64, int::BYTES, |v| self.write(v))
}
/// Write a big-endian uint (number of bytes depends on system).
fn write_be_uint(&mut self, n: uint) {
fn write_be_uint(&mut self, n: uint) -> IoResult<()> {
extensions::u64_to_be_bytes(n as u64, uint::BYTES, |v| self.write(v))
}
/// Write a big-endian int (number of bytes depends on system).
fn write_be_int(&mut self, n: int) {
fn write_be_int(&mut self, n: int) -> IoResult<()> {
extensions::u64_to_be_bytes(n as u64, int::BYTES, |v| self.write(v))
}
/// Write a big-endian u64 (8 bytes).
fn write_be_u64(&mut self, n: u64) {
fn write_be_u64(&mut self, n: u64) -> IoResult<()> {
extensions::u64_to_be_bytes(n, 8u, |v| self.write(v))
}
/// Write a big-endian u32 (4 bytes).
fn write_be_u32(&mut self, n: u32) {
fn write_be_u32(&mut self, n: u32) -> IoResult<()> {
extensions::u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
}
/// Write a big-endian u16 (2 bytes).
fn write_be_u16(&mut self, n: u16) {
fn write_be_u16(&mut self, n: u16) -> IoResult<()> {
extensions::u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
}
/// Write a big-endian i64 (8 bytes).
fn write_be_i64(&mut self, n: i64) {
fn write_be_i64(&mut self, n: i64) -> IoResult<()> {
extensions::u64_to_be_bytes(n as u64, 8u, |v| self.write(v))
}
/// Write a big-endian i32 (4 bytes).
fn write_be_i32(&mut self, n: i32) {
fn write_be_i32(&mut self, n: i32) -> IoResult<()> {
extensions::u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
}
/// Write a big-endian i16 (2 bytes).
fn write_be_i16(&mut self, n: i16) {
fn write_be_i16(&mut self, n: i16) -> IoResult<()> {
extensions::u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
}
/// Write a big-endian IEEE754 double-precision floating-point (8 bytes).
fn write_be_f64(&mut self, f: f64) {
fn write_be_f64(&mut self, f: f64) -> IoResult<()> {
unsafe {
self.write_be_u64(cast::transmute(f))
}
}
/// Write a big-endian IEEE754 single-precision floating-point (4 bytes).
fn write_be_f32(&mut self, f: f32) {
fn write_be_f32(&mut self, f: f32) -> IoResult<()> {
unsafe {
self.write_be_u32(cast::transmute(f))
}
}
/// Write a little-endian u64 (8 bytes).
fn write_le_u64(&mut self, n: u64) {
fn write_le_u64(&mut self, n: u64) -> IoResult<()> {
extensions::u64_to_le_bytes(n, 8u, |v| self.write(v))
}
/// Write a little-endian u32 (4 bytes).
fn write_le_u32(&mut self, n: u32) {
fn write_le_u32(&mut self, n: u32) -> IoResult<()> {
extensions::u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
}
/// Write a little-endian u16 (2 bytes).
fn write_le_u16(&mut self, n: u16) {
fn write_le_u16(&mut self, n: u16) -> IoResult<()> {
extensions::u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
}
/// Write a little-endian i64 (8 bytes).
fn write_le_i64(&mut self, n: i64) {
fn write_le_i64(&mut self, n: i64) -> IoResult<()> {
extensions::u64_to_le_bytes(n as u64, 8u, |v| self.write(v))
}
/// Write a little-endian i32 (4 bytes).
fn write_le_i32(&mut self, n: i32) {
fn write_le_i32(&mut self, n: i32) -> IoResult<()> {
extensions::u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
}
/// Write a little-endian i16 (2 bytes).
fn write_le_i16(&mut self, n: i16) {
fn write_le_i16(&mut self, n: i16) -> IoResult<()> {
extensions::u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
}
/// Write a little-endian IEEE754 double-precision floating-point
/// (8 bytes).
fn write_le_f64(&mut self, f: f64) {
fn write_le_f64(&mut self, f: f64) -> IoResult<()> {
unsafe {
self.write_le_u64(cast::transmute(f))
}
@@ -1017,31 +946,31 @@ fn write_le_f64(&mut self, f: f64) {
/// Write a little-endian IEEE754 single-precision floating-point
/// (4 bytes).
fn write_le_f32(&mut self, f: f32) {
fn write_le_f32(&mut self, f: f32) -> IoResult<()> {
unsafe {
self.write_le_u32(cast::transmute(f))
}
}
/// Write a u8 (1 byte).
fn write_u8(&mut self, n: u8) {
fn write_u8(&mut self, n: u8) -> IoResult<()> {
self.write([n])
}
/// Write a i8 (1 byte).
fn write_i8(&mut self, n: i8) {
fn write_i8(&mut self, n: i8) -> IoResult<()> {
self.write([n as u8])
}
}
impl Writer for ~Writer {
fn write(&mut self, buf: &[u8]) { self.write(buf) }
fn flush(&mut self) { self.flush() }
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
fn flush(&mut self) -> IoResult<()> { self.flush() }
}
impl<'a> Writer for &'a mut Writer {
fn write(&mut self, buf: &[u8]) { self.write(buf) }
fn flush(&mut self) { self.flush() }
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) }
fn flush(&mut self) -> IoResult<()> { self.flush() }
}
pub trait Stream: Reader + Writer { }
@@ -1057,18 +986,18 @@ impl<T: Reader + Writer> Stream for T {}
/// an iteration, but continue to yield elements if iteration
/// is attempted again.
///
/// # Failure
/// # Error
///
/// Raises the same conditions as the `read` method except for `EndOfFile`
/// which is swallowed.
/// Iteration yields `None` if the condition is handled.
/// This iterator will swallow all I/O errors, transforming `Err` values to
/// `None`. If errors need to be handled, it is recommended to use the
/// `read_line` method directly.
pub struct Lines<'r, T> {
priv buffer: &'r mut T,
}
impl<'r, T: Buffer> Iterator<~str> for Lines<'r, T> {
fn next(&mut self) -> Option<~str> {
self.buffer.read_line()
self.buffer.read_line().ok()
}
}
@@ -1085,11 +1014,12 @@ pub trait Buffer: Reader {
/// consumed from this buffer returned to ensure that the bytes are never
/// returned twice.
///
/// # Failure
/// # Error
///
/// This function will raise on the `io_error` condition if a read error is
/// encountered.
fn fill<'a>(&'a mut self) -> &'a [u8];
/// This function will return an I/O error if the underlying reader was
/// read, but returned an error. Note that it is not an error to return a
/// 0-length buffer.
fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]>;
/// Tells this buffer that `amt` bytes have been consumed from the buffer,
/// so they should no longer be returned in calls to `fill` or `read`.
@@ -1103,108 +1033,117 @@ pub trait Buffer: Reader {
///
/// ```rust
/// use std::io::{BufferedReader, stdin};
/// # let _g = ::std::io::ignore_io_error();
///
/// let mut reader = BufferedReader::new(stdin());
///
/// let input = reader.read_line().unwrap_or(~"nothing");
/// let input = reader.read_line().ok().unwrap_or(~"nothing");
/// ```
///
/// # Failure
/// # Error
///
/// This function will raise on the `io_error` condition (except for
/// `EndOfFile` which is swallowed) if a read error is encountered.
/// The task will also fail if sequence of bytes leading up to
/// the newline character are not valid UTF-8.
fn read_line(&mut self) -> Option<~str> {
self.read_until('\n' as u8).map(|line| str::from_utf8_owned(line).unwrap())
/// This function has the same error semantics as `read_until`:
///
/// * All non-EOF errors will be returned immediately
/// * If an error is returned previously consumed bytes are lost
/// * EOF is only returned if no bytes have been read
/// * Reach EOF may mean that the delimiter is not present in the return
/// value
///
/// Additionally, this function can fail if the line of input read is not a
/// valid UTF-8 sequence of bytes.
fn read_line(&mut self) -> IoResult<~str> {
self.read_until('\n' as u8).and_then(|line|
match str::from_utf8_owned(line) {
Some(s) => Ok(s),
None => Err(standard_error(InvalidInput)),
}
)
}
/// Create an iterator that reads a line on each iteration until EOF.
///
/// # Failure
/// # Error
///
/// Iterator raises the same conditions as the `read` method
/// except for `EndOfFile`.
/// This iterator will transform all error values to `None`, discarding the
/// cause of the error. If this is undesirable, it is recommended to call
/// `read_line` directly.
fn lines<'r>(&'r mut self) -> Lines<'r, Self> {
Lines {
buffer: self,
}
Lines { buffer: self }
}
/// Reads a sequence of bytes leading up to a specified delimiter. Once the
/// specified byte is encountered, reading ceases and the bytes up to and
/// including the delimiter are returned.
///
/// # Failure
/// # Error
///
/// This function will raise on the `io_error` condition if a read error is
/// encountered, except that `EndOfFile` is swallowed.
fn read_until(&mut self, byte: u8) -> Option<~[u8]> {
/// If any I/O error is encountered other than EOF, the error is immediately
/// returned. Note that this may discard bytes which have already been read,
/// and those bytes will *not* be returned. It is recommended to use other
/// methods if this case is worrying.
///
/// If EOF is encountered, then this function will return EOF if 0 bytes
/// have been read, otherwise the pending byte buffer is returned. This
/// is the reason that the byte buffer returned may not always contain the
/// delimiter.
fn read_until(&mut self, byte: u8) -> IoResult<~[u8]> {
let mut res = ~[];
io_error::cond.trap(|e| {
if e.kind != EndOfFile {
io_error::cond.raise(e);
}
}).inside(|| {
let mut used;
loop {
{
let available = self.fill();
match available.iter().position(|&b| b == byte) {
Some(i) => {
res.push_all(available.slice_to(i + 1));
used = i + 1;
break
}
None => {
res.push_all(available);
used = available.len();
}
let mut used;
loop {
{
let available = match self.fill() {
Ok(n) => n,
Err(ref e) if res.len() > 0 && e.kind == EndOfFile => {
used = 0;
break
}
Err(e) => return Err(e)
};
match available.iter().position(|&b| b == byte) {
Some(i) => {
res.push_all(available.slice_to(i + 1));
used = i + 1;
break
}
None => {
res.push_all(available);
used = available.len();
}
}
if used == 0 {
break
}
self.consume(used);
}
self.consume(used);
});
return if res.len() == 0 {None} else {Some(res)};
}
self.consume(used);
Ok(res)
}
/// Reads the next utf8-encoded character from the underlying stream.
///
/// This will return `None` if the following sequence of bytes in the
/// stream are not a valid utf8-sequence, or if an I/O error is encountered.
/// # Error
///
/// # Failure
///
/// This function will raise on the `io_error` condition if a read error is
/// encountered.
fn read_char(&mut self) -> Option<char> {
let width = {
let available = self.fill();
if available.len() == 0 { return None } // read error
str::utf8_char_width(available[0])
};
if width == 0 { return None } // not uf8
let mut buf = [0, ..4];
/// If an I/O error occurs, or EOF, then this function will return `Err`.
/// This function will also return error if the stream does not contain a
/// valid utf-8 encoded codepoint as the next few bytes in the stream.
fn read_char(&mut self) -> IoResult<char> {
let first_byte = if_ok!(self.read_byte());
let width = str::utf8_char_width(first_byte);
if width == 1 { return Ok(first_byte as char) }
if width == 0 { return Err(standard_error(InvalidInput)) } // not utf8
let mut buf = [first_byte, 0, 0, 0];
{
let mut start = 0;
loop {
match self.read(buf.mut_slice(start, width)) {
Some(n) if n == width - start => break,
Some(n) if n < width - start => { start += n; }
Some(..) | None => return None // read error
let mut start = 1;
while start < width {
match if_ok!(self.read(buf.mut_slice(start, width))) {
n if n == width - start => break,
n if n < width - start => { start += n; }
_ => return Err(standard_error(InvalidInput)),
}
}
}
match str::from_utf8(buf.slice_to(width)) {
Some(s) => Some(s.char_at(0)),
None => None
Some(s) => Ok(s.char_at(0)),
None => Err(standard_error(InvalidInput))
}
}
}
@@ -1222,7 +1161,7 @@ pub enum SeekStyle {
/// * Are `u64` and `i64` the right choices?
pub trait Seek {
/// Return position of file cursor in the stream
fn tell(&self) -> u64;
fn tell(&self) -> IoResult<u64>;
/// Seek to an offset in a stream
///
@@ -1231,31 +1170,35 @@ pub trait Seek {
/// # FIXME
///
/// * What is the behavior when seeking past the end of a stream?
fn seek(&mut self, pos: i64, style: SeekStyle);
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>;
}
/// A listener is a value that can consume itself to start listening for connections.
/// A listener is a value that can consume itself to start listening for
/// connections.
///
/// Doing so produces some sort of Acceptor.
pub trait Listener<T, A: Acceptor<T>> {
/// Spin up the listener and start queuing incoming connections
///
/// # Failure
/// # Error
///
/// Raises `io_error` condition. If the condition is handled,
/// then `listen` returns `None`.
fn listen(self) -> Option<A>;
/// Returns `Err` if this listener could not be bound to listen for
/// connections. In all cases, this listener is consumed.
fn listen(self) -> IoResult<A>;
}
/// An acceptor is a value that presents incoming connections
pub trait Acceptor<T> {
/// Wait for and accept an incoming connection
///
/// # Failure
/// Raise `io_error` condition. If the condition is handled,
/// then `accept` returns `None`.
fn accept(&mut self) -> Option<T>;
/// # Error
///
/// Returns `Err` if an I/O error is encountered.
fn accept(&mut self) -> IoResult<T>;
/// Create an iterator over incoming connection attempts
/// Create an iterator over incoming connection attempts.
///
/// Note that I/O errors will be yielded by the iterator itself.
fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> {
IncomingConnections { inc: self }
}
@@ -1264,23 +1207,22 @@ fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> {
/// An infinite iterator over incoming connection attempts.
/// Calling `next` will block the task until a connection is attempted.
///
/// Since connection attempts can continue forever, this iterator always returns Some.
/// The Some contains another Option representing whether the connection attempt was succesful.
/// A successful connection will be wrapped in Some.
/// A failed connection is represented as a None and raises a condition.
/// Since connection attempts can continue forever, this iterator always returns
/// `Some`. The `Some` contains the `IoResult` representing whether the
/// connection attempt was succesful. A successful connection will be wrapped
/// in `Ok`. A failed connection is represented as an `Err`.
pub struct IncomingConnections<'a, A> {
priv inc: &'a mut A,
}
impl<'a, T, A: Acceptor<T>> Iterator<Option<T>> for IncomingConnections<'a, A> {
fn next(&mut self) -> Option<Option<T>> {
impl<'a, T, A: Acceptor<T>> Iterator<IoResult<T>> for IncomingConnections<'a, A> {
fn next(&mut self) -> Option<IoResult<T>> {
Some(self.inc.accept())
}
}
pub fn standard_error(kind: IoErrorKind) -> IoError {
let desc = match kind {
PreviousIoError => "failing due to previous I/O error",
EndOfFile => "end of file",
IoUnavailable => "I/O is unavailable",
InvalidInput => "invalid input",
@@ -1314,7 +1256,7 @@ pub enum FileMode {
}
/// Access permissions with which the file should be opened. `File`s
/// opened with `Read` will raise an `io_error` condition if written to.
/// opened with `Read` will return an error if written to.
pub enum FileAccess {
Read,
Write,
+5 -12
View File
@@ -17,8 +17,9 @@
*/
use option::{Option, Some, None};
use io::IoResult;
use io::net::ip::{SocketAddr, IpAddr};
use option::{Option, Some, None};
use rt::rtio::{IoFactory, LocalIo};
use vec::ImmutableVector;
@@ -69,11 +70,7 @@ pub struct Info {
/// 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]> {
pub fn get_host_addresses(host: &str) -> IoResult<~[IpAddr]> {
lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip))
}
@@ -87,14 +84,10 @@ pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
/// * 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.
///
/// FIXME: 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]> {
-> IoResult<~[Info]> {
LocalIo::maybe_raise(|io| io.get_host_addresses(hostname, servname, hint))
}
@@ -115,6 +108,6 @@ mod test {
iotest!(fn issue_10663() {
// Something should happen here, but this certainly shouldn't cause
// everything to die. The actual outcome we don't care too much about.
get_host_addresses("example.com");
get_host_addresses("example.com").unwrap();
} #[ignore])
}
+99 -175
View File
@@ -8,11 +8,8 @@
// 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 io::net::ip::SocketAddr;
use io::{Reader, Writer, Listener, Acceptor};
use io::{io_error, EndOfFile};
use io::{Reader, Writer, Listener, Acceptor, IoResult};
use rt::rtio::{IoFactory, LocalIo, RtioSocket, RtioTcpListener};
use rt::rtio::{RtioTcpAcceptor, RtioTcpStream};
@@ -25,57 +22,27 @@ fn new(s: ~RtioTcpStream) -> TcpStream {
TcpStream { obj: s }
}
pub fn connect(addr: SocketAddr) -> Option<TcpStream> {
pub fn connect(addr: SocketAddr) -> IoResult<TcpStream> {
LocalIo::maybe_raise(|io| {
io.tcp_connect(addr).map(TcpStream::new)
})
}
pub fn peer_name(&mut self) -> Option<SocketAddr> {
match self.obj.peer_name() {
Ok(pn) => Some(pn),
Err(ioerr) => {
debug!("failed to get peer name: {:?}", ioerr);
io_error::cond.raise(ioerr);
None
}
}
pub fn peer_name(&mut self) -> IoResult<SocketAddr> {
self.obj.peer_name()
}
pub fn socket_name(&mut self) -> Option<SocketAddr> {
match self.obj.socket_name() {
Ok(sn) => Some(sn),
Err(ioerr) => {
debug!("failed to get socket name: {:?}", ioerr);
io_error::cond.raise(ioerr);
None
}
}
pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
self.obj.socket_name()
}
}
impl Reader for TcpStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
match self.obj.read(buf) {
Ok(read) => Some(read),
Err(ioerr) => {
// EOF is indicated by returning None
if ioerr.kind != EndOfFile {
io_error::cond.raise(ioerr);
}
return None;
}
}
}
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) }
}
impl Writer for TcpStream {
fn write(&mut self, buf: &[u8]) {
match self.obj.write(buf) {
Ok(_) => (),
Err(ioerr) => io_error::cond.raise(ioerr),
}
}
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) }
}
pub struct TcpListener {
@@ -83,33 +50,20 @@ pub struct TcpListener {
}
impl TcpListener {
pub fn bind(addr: SocketAddr) -> Option<TcpListener> {
pub fn bind(addr: SocketAddr) -> IoResult<TcpListener> {
LocalIo::maybe_raise(|io| {
io.tcp_bind(addr).map(|l| TcpListener { obj: l })
})
}
pub fn socket_name(&mut self) -> Option<SocketAddr> {
match self.obj.socket_name() {
Ok(sn) => Some(sn),
Err(ioerr) => {
debug!("failed to get socket name: {:?}", ioerr);
io_error::cond.raise(ioerr);
None
}
}
pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
self.obj.socket_name()
}
}
impl Listener<TcpStream, TcpAcceptor> for TcpListener {
fn listen(self) -> Option<TcpAcceptor> {
match self.obj.listen() {
Ok(acceptor) => Some(TcpAcceptor { obj: acceptor }),
Err(ioerr) => {
io_error::cond.raise(ioerr);
None
}
}
fn listen(self) -> IoResult<TcpAcceptor> {
self.obj.listen().map(|acceptor| TcpAcceptor { obj: acceptor })
}
}
@@ -118,14 +72,8 @@ pub struct TcpAcceptor {
}
impl Acceptor<TcpStream> for TcpAcceptor {
fn accept(&mut self) -> Option<TcpStream> {
match self.obj.accept() {
Ok(s) => Some(TcpStream::new(s)),
Err(ioerr) => {
io_error::cond.raise(ioerr);
None
}
}
fn accept(&mut self) -> IoResult<TcpStream> {
self.obj.accept().map(TcpStream::new)
}
}
@@ -138,29 +86,19 @@ mod test {
// FIXME #11530 this fails on android because tests are run as root
iotest!(fn bind_error() {
let mut called = false;
io_error::cond.trap(|e| {
assert!(e.kind == PermissionDenied);
called = true;
}).inside(|| {
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
let listener = TcpListener::bind(addr);
assert!(listener.is_none());
});
assert!(called);
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
match TcpListener::bind(addr) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, PermissionDenied),
}
} #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))])
iotest!(fn connect_error() {
let mut called = false;
io_error::cond.trap(|e| {
assert_eq!(e.kind, ConnectionRefused);
called = true;
}).inside(|| {
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
let stream = TcpStream::connect(addr);
assert!(stream.is_none());
});
assert!(called);
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
match TcpStream::connect(addr) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, ConnectionRefused),
}
})
iotest!(fn smoke_test_ip4() {
@@ -170,14 +108,14 @@ mod test {
spawn(proc() {
port.recv();
let mut stream = TcpStream::connect(addr);
stream.write([99]);
stream.write([99]).unwrap();
});
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
let mut stream = acceptor.accept();
let mut buf = [0];
stream.read(buf);
stream.read(buf).unwrap();
assert!(buf[0] == 99);
})
@@ -188,14 +126,14 @@ mod test {
spawn(proc() {
port.recv();
let mut stream = TcpStream::connect(addr);
stream.write([99]);
stream.write([99]).unwrap();
});
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
let mut stream = acceptor.accept();
let mut buf = [0];
stream.read(buf);
stream.read(buf).unwrap();
assert!(buf[0] == 99);
})
@@ -214,7 +152,7 @@ mod test {
let mut stream = acceptor.accept();
let mut buf = [0];
let nread = stream.read(buf);
assert!(nread.is_none());
assert!(nread.is_err());
})
iotest!(fn read_eof_ip6() {
@@ -232,7 +170,7 @@ mod test {
let mut stream = acceptor.accept();
let mut buf = [0];
let nread = stream.read(buf);
assert!(nread.is_none());
assert!(nread.is_err());
})
iotest!(fn read_eof_twice_ip4() {
@@ -250,17 +188,15 @@ mod test {
let mut stream = acceptor.accept();
let mut buf = [0];
let nread = stream.read(buf);
assert!(nread.is_none());
io_error::cond.trap(|e| {
if cfg!(windows) {
assert_eq!(e.kind, NotConnected);
} else {
fail!();
assert!(nread.is_err());
match stream.read(buf) {
Ok(..) => fail!(),
Err(ref e) => {
assert!(e.kind == NotConnected || e.kind == EndOfFile,
"unknown kind: {:?}", e.kind);
}
}).inside(|| {
let nread = stream.read(buf);
assert!(nread.is_none());
})
}
})
iotest!(fn read_eof_twice_ip6() {
@@ -278,17 +214,15 @@ mod test {
let mut stream = acceptor.accept();
let mut buf = [0];
let nread = stream.read(buf);
assert!(nread.is_none());
io_error::cond.trap(|e| {
if cfg!(windows) {
assert_eq!(e.kind, NotConnected);
} else {
fail!();
assert!(nread.is_err());
match stream.read(buf) {
Ok(..) => fail!(),
Err(ref e) => {
assert!(e.kind == NotConnected || e.kind == EndOfFile,
"unknown kind: {:?}", e.kind);
}
}).inside(|| {
let nread = stream.read(buf);
assert!(nread.is_none());
})
}
})
iotest!(fn write_close_ip4() {
@@ -306,19 +240,16 @@ mod test {
let mut stream = acceptor.accept();
let buf = [0];
loop {
let mut stop = false;
io_error::cond.trap(|e| {
// NB: ECONNRESET on linux, EPIPE on mac, ECONNABORTED
// on windows
assert!(e.kind == ConnectionReset ||
e.kind == BrokenPipe ||
e.kind == ConnectionAborted,
"unknown error: {:?}", e);
stop = true;
}).inside(|| {
stream.write(buf);
});
if stop { break }
match stream.write(buf) {
Ok(..) => {}
Err(e) => {
assert!(e.kind == ConnectionReset ||
e.kind == BrokenPipe ||
e.kind == ConnectionAborted,
"unknown error: {:?}", e);
break;
}
}
}
})
@@ -337,19 +268,16 @@ mod test {
let mut stream = acceptor.accept();
let buf = [0];
loop {
let mut stop = false;
io_error::cond.trap(|e| {
// NB: ECONNRESET on linux, EPIPE on mac, ECONNABORTED
// on windows
assert!(e.kind == ConnectionReset ||
e.kind == BrokenPipe ||
e.kind == ConnectionAborted,
"unknown error: {:?}", e);
stop = true;
}).inside(|| {
stream.write(buf);
});
if stop { break }
match stream.write(buf) {
Ok(..) => {}
Err(e) => {
assert!(e.kind == ConnectionReset ||
e.kind == BrokenPipe ||
e.kind == ConnectionAborted,
"unknown error: {:?}", e);
break;
}
}
}
})
@@ -362,7 +290,7 @@ mod test {
port.recv();
for _ in range(0, max) {
let mut stream = TcpStream::connect(addr);
stream.write([99]);
stream.write([99]).unwrap();
}
});
@@ -370,7 +298,7 @@ mod test {
chan.send(());
for ref mut stream in acceptor.incoming().take(max) {
let mut buf = [0];
stream.read(buf);
stream.read(buf).unwrap();
assert_eq!(buf[0], 99);
}
})
@@ -384,7 +312,7 @@ mod test {
port.recv();
for _ in range(0, max) {
let mut stream = TcpStream::connect(addr);
stream.write([99]);
stream.write([99]).unwrap();
}
});
@@ -392,7 +320,7 @@ mod test {
chan.send(());
for ref mut stream in acceptor.incoming().take(max) {
let mut buf = [0];
stream.read(buf);
stream.read(buf).unwrap();
assert_eq!(buf[0], 99);
}
})
@@ -410,7 +338,7 @@ mod test {
spawn(proc() {
let mut stream = stream;
let mut buf = [0];
stream.read(buf);
stream.read(buf).unwrap();
assert!(buf[0] == i as u8);
debug!("read");
});
@@ -429,7 +357,7 @@ fn connect(i: int, addr: SocketAddr) {
// Connect again before writing
connect(i + 1, addr);
debug!("writing");
stream.write([i as u8]);
stream.write([i as u8]).unwrap();
});
}
})
@@ -447,7 +375,7 @@ fn connect(i: int, addr: SocketAddr) {
spawn(proc() {
let mut stream = stream;
let mut buf = [0];
stream.read(buf);
stream.read(buf).unwrap();
assert!(buf[0] == i as u8);
debug!("read");
});
@@ -466,7 +394,7 @@ fn connect(i: int, addr: SocketAddr) {
// Connect again before writing
connect(i + 1, addr);
debug!("writing");
stream.write([i as u8]);
stream.write([i as u8]).unwrap();
});
}
})
@@ -484,7 +412,7 @@ fn connect(i: int, addr: SocketAddr) {
spawn(proc() {
let mut stream = stream;
let mut buf = [0];
stream.read(buf);
stream.read(buf).unwrap();
assert!(buf[0] == 99);
debug!("read");
});
@@ -503,7 +431,7 @@ fn connect(i: int, addr: SocketAddr) {
// Connect again before writing
connect(i + 1, addr);
debug!("writing");
stream.write([99]);
stream.write([99]).unwrap();
});
}
})
@@ -521,7 +449,7 @@ fn connect(i: int, addr: SocketAddr) {
spawn(proc() {
let mut stream = stream;
let mut buf = [0];
stream.read(buf);
stream.read(buf).unwrap();
assert!(buf[0] == 99);
debug!("read");
});
@@ -540,7 +468,7 @@ fn connect(i: int, addr: SocketAddr) {
// Connect again before writing
connect(i + 1, addr);
debug!("writing");
stream.write([99]);
stream.write([99]).unwrap();
});
}
})
@@ -551,7 +479,7 @@ pub fn socket_name(addr: SocketAddr) {
// Make sure socket_name gives
// us the socket we binded to.
let so_name = listener.socket_name();
assert!(so_name.is_some());
assert!(so_name.is_ok());
assert_eq!(addr, so_name.unwrap());
}
@@ -561,20 +489,20 @@ pub fn peer_name(addr: SocketAddr) {
spawn(proc() {
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
acceptor.accept();
acceptor.accept().unwrap();
});
port.recv();
let stream = TcpStream::connect(addr);
assert!(stream.is_some());
assert!(stream.is_ok());
let mut stream = stream.unwrap();
// Make sure peer_name gives us the
// address/port of the peer we've
// connected to.
let peer_name = stream.peer_name();
assert!(peer_name.is_some());
assert!(peer_name.is_ok());
assert_eq!(addr, peer_name.unwrap());
}
@@ -593,37 +521,33 @@ pub fn peer_name(addr: SocketAddr) {
let addr = next_test_ip4();
let (p, c) = Chan::new();
spawn(proc() {
let mut srv = TcpListener::bind(addr).listen();
let mut srv = TcpListener::bind(addr).listen().unwrap();
c.send(());
let mut cl = srv.accept().unwrap();
cl.write([10]);
cl.write([10]).unwrap();
let mut b = [0];
cl.read(b);
cl.read(b).unwrap();
c.send(());
});
p.recv();
let mut c = TcpStream::connect(addr).unwrap();
let mut b = [0, ..10];
assert_eq!(c.read(b), Some(1));
c.write([1]);
assert_eq!(c.read(b), Ok(1));
c.write([1]).unwrap();
p.recv();
})
iotest!(fn double_bind() {
let mut called = false;
io_error::cond.trap(|e| {
assert!(e.kind == ConnectionRefused || e.kind == OtherIoError);
called = true;
}).inside(|| {
let addr = next_test_ip4();
let listener = TcpListener::bind(addr).unwrap().listen();
assert!(listener.is_some());
let listener2 = TcpListener::bind(addr).and_then(|l|
l.listen());
assert!(listener2.is_none());
});
assert!(called);
let addr = next_test_ip4();
let listener = TcpListener::bind(addr).unwrap().listen();
assert!(listener.is_ok());
match TcpListener::bind(addr).listen() {
Ok(..) => fail!(),
Err(e) => {
assert!(e.kind == ConnectionRefused || e.kind == OtherIoError);
}
}
})
iotest!(fn fast_rebind() {
@@ -632,7 +556,7 @@ pub fn peer_name(addr: SocketAddr) {
spawn(proc() {
port.recv();
let _stream = TcpStream::connect(addr);
let _stream = TcpStream::connect(addr).unwrap();
// Close
port.recv();
});
@@ -641,7 +565,7 @@ pub fn peer_name(addr: SocketAddr) {
let mut acceptor = TcpListener::bind(addr).listen();
chan.send(());
{
let _stream = acceptor.accept();
let _stream = acceptor.accept().unwrap();
// Close client
chan.send(());
}
+49 -75
View File
@@ -8,11 +8,9 @@
// 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 io::net::ip::SocketAddr;
use io::{Reader, Writer};
use io::{io_error, EndOfFile};
use io::{Reader, Writer, IoResult};
use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, LocalIo};
pub struct UdpSocket {
@@ -20,45 +18,26 @@ pub struct UdpSocket {
}
impl UdpSocket {
pub fn bind(addr: SocketAddr) -> Option<UdpSocket> {
pub fn bind(addr: SocketAddr) -> IoResult<UdpSocket> {
LocalIo::maybe_raise(|io| {
io.udp_bind(addr).map(|s| UdpSocket { obj: s })
})
}
pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, SocketAddr)> {
match self.obj.recvfrom(buf) {
Ok((nread, src)) => Some((nread, src)),
Err(ioerr) => {
// EOF is indicated by returning None
if ioerr.kind != EndOfFile {
io_error::cond.raise(ioerr);
}
None
}
}
pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> {
self.obj.recvfrom(buf)
}
pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) {
match self.obj.sendto(buf, dst) {
Ok(_) => (),
Err(ioerr) => io_error::cond.raise(ioerr),
}
pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
self.obj.sendto(buf, dst)
}
pub fn connect(self, other: SocketAddr) -> UdpStream {
UdpStream { socket: self, connectedTo: other }
}
pub fn socket_name(&mut self) -> Option<SocketAddr> {
match self.obj.socket_name() {
Ok(sn) => Some(sn),
Err(ioerr) => {
debug!("failed to get socket name: {:?}", ioerr);
io_error::cond.raise(ioerr);
None
}
}
pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
self.obj.socket_name()
}
}
@@ -76,21 +55,21 @@ pub fn disconnect(self) -> UdpSocket { self.socket }
}
impl Reader for UdpStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
let peer = self.connectedTo;
self.as_socket(|sock| {
match sock.recvfrom(buf) {
Some((_nread, src)) if src != peer => Some(0),
Some((nread, _src)) => Some(nread),
None => None,
Ok((_nread, src)) if src != peer => Ok(0),
Ok((nread, _src)) => Ok(nread),
Err(e) => Err(e),
}
})
}
}
impl Writer for UdpStream {
fn write(&mut self, buf: &[u8]) {
self.as_socket(|sock| sock.sendto(buf, self.connectedTo));
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
self.as_socket(|sock| sock.sendto(buf, self.connectedTo))
}
}
@@ -101,16 +80,11 @@ mod test {
// FIXME #11530 this fails on android because tests are run as root
iotest!(fn bind_error() {
let mut called = false;
io_error::cond.trap(|e| {
assert_eq!(e.kind, PermissionDenied);
called = true;
}).inside(|| {
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
let socket = UdpSocket::bind(addr);
assert!(socket.is_none());
});
assert!(called);
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
match UdpSocket::bind(addr) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, PermissionDenied),
}
} #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))])
iotest!(fn socket_smoke_test_ip4() {
@@ -121,29 +95,29 @@ mod test {
spawn(proc() {
match UdpSocket::bind(client_ip) {
Some(ref mut client) => {
Ok(ref mut client) => {
port.recv();
client.sendto([99], server_ip)
client.sendto([99], server_ip).unwrap()
}
None => fail!()
Err(..) => fail!()
}
chan2.send(());
});
match UdpSocket::bind(server_ip) {
Some(ref mut server) => {
Ok(ref mut server) => {
chan.send(());
let mut buf = [0];
match server.recvfrom(buf) {
Some((nread, src)) => {
Ok((nread, src)) => {
assert_eq!(nread, 1);
assert_eq!(buf[0], 99);
assert_eq!(src, client_ip);
}
None => fail!()
Err(..) => fail!()
}
}
None => fail!()
Err(..) => fail!()
}
port2.recv();
})
@@ -155,28 +129,28 @@ mod test {
spawn(proc() {
match UdpSocket::bind(client_ip) {
Some(ref mut client) => {
Ok(ref mut client) => {
port.recv();
client.sendto([99], server_ip)
client.sendto([99], server_ip).unwrap()
}
None => fail!()
Err(..) => fail!()
}
});
match UdpSocket::bind(server_ip) {
Some(ref mut server) => {
Ok(ref mut server) => {
chan.send(());
let mut buf = [0];
match server.recvfrom(buf) {
Some((nread, src)) => {
Ok((nread, src)) => {
assert_eq!(nread, 1);
assert_eq!(buf[0], 99);
assert_eq!(src, client_ip);
}
None => fail!()
Err(..) => fail!()
}
}
None => fail!()
Err(..) => fail!()
}
})
@@ -188,32 +162,32 @@ mod test {
spawn(proc() {
match UdpSocket::bind(client_ip) {
Some(client) => {
Ok(client) => {
let client = ~client;
let mut stream = client.connect(server_ip);
port.recv();
stream.write([99]);
stream.write([99]).unwrap();
}
None => fail!()
Err(..) => fail!()
}
chan2.send(());
});
match UdpSocket::bind(server_ip) {
Some(server) => {
Ok(server) => {
let server = ~server;
let mut stream = server.connect(client_ip);
chan.send(());
let mut buf = [0];
match stream.read(buf) {
Some(nread) => {
Ok(nread) => {
assert_eq!(nread, 1);
assert_eq!(buf[0], 99);
}
None => fail!()
Err(..) => fail!()
}
}
None => fail!()
Err(..) => fail!()
}
port2.recv();
})
@@ -226,32 +200,32 @@ mod test {
spawn(proc() {
match UdpSocket::bind(client_ip) {
Some(client) => {
Ok(client) => {
let client = ~client;
let mut stream = client.connect(server_ip);
port.recv();
stream.write([99]);
stream.write([99]).unwrap();
}
None => fail!()
Err(..) => fail!()
}
chan2.send(());
});
match UdpSocket::bind(server_ip) {
Some(server) => {
Ok(server) => {
let server = ~server;
let mut stream = server.connect(client_ip);
chan.send(());
let mut buf = [0];
match stream.read(buf) {
Some(nread) => {
Ok(nread) => {
assert_eq!(nread, 1);
assert_eq!(buf[0], 99);
}
None => fail!()
Err(..) => fail!()
}
}
None => fail!()
Err(..) => fail!()
}
port2.recv();
})
@@ -259,13 +233,13 @@ mod test {
pub fn socket_name(addr: SocketAddr) {
let server = UdpSocket::bind(addr);
assert!(server.is_some());
assert!(server.is_ok());
let mut server = server.unwrap();
// Make sure socket_name gives
// us the socket we binded to.
let so_name = server.socket_name();
assert!(so_name.is_some());
assert!(so_name.is_ok());
assert_eq!(addr, so_name.unwrap());
}
+50 -78
View File
@@ -28,7 +28,7 @@
use rt::rtio::{IoFactory, LocalIo, RtioUnixListener};
use rt::rtio::{RtioUnixAcceptor, RtioPipe};
use io::pipe::PipeStream;
use io::{io_error, Listener, Acceptor, Reader, Writer};
use io::{Listener, Acceptor, Reader, Writer, IoResult};
/// A stream which communicates over a named pipe.
pub struct UnixStream {
@@ -45,20 +45,17 @@ fn new(obj: ~RtioPipe) -> UnixStream {
///
/// 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::io::net::unix::UnixStream;
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::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> {
/// let server = Path::new("path/to/my/socket");
/// let mut stream = UnixStream::connect(&server);
/// stream.write([1, 2, 3]);
/// ```
pub fn connect<P: ToCStr>(path: &P) -> IoResult<UnixStream> {
LocalIo::maybe_raise(|io| {
io.unix_connect(&path.to_c_str()).map(UnixStream::new)
})
@@ -66,11 +63,11 @@ pub fn connect<P: ToCStr>(path: &P) -> Option<UnixStream> {
}
impl Reader for UnixStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.obj.read(buf) }
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) }
}
impl Writer for UnixStream {
fn write(&mut self, buf: &[u8]) { self.obj.write(buf) }
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) }
}
pub struct UnixListener {
@@ -84,23 +81,20 @@ impl UnixListener {
///
/// 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::io::net::unix::UnixListener;
/// ```
/// use std::io::net::unix::UnixListener;
/// use std::io::Listener;
///
/// 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> {
/// let server = Path::new("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) -> IoResult<UnixListener> {
LocalIo::maybe_raise(|io| {
io.unix_bind(&path.to_c_str()).map(|s| UnixListener { obj: s })
})
@@ -108,14 +102,8 @@ pub fn bind<P: ToCStr>(path: &P) -> Option<UnixListener> {
}
impl Listener<UnixStream, UnixAcceptor> for UnixListener {
fn listen(self) -> Option<UnixAcceptor> {
match self.obj.listen() {
Ok(acceptor) => Some(UnixAcceptor { obj: acceptor }),
Err(ioerr) => {
io_error::cond.raise(ioerr);
None
}
}
fn listen(self) -> IoResult<UnixAcceptor> {
self.obj.listen().map(|obj| UnixAcceptor { obj: obj })
}
}
@@ -124,14 +112,8 @@ pub struct UnixAcceptor {
}
impl Acceptor<UnixStream> for UnixAcceptor {
fn accept(&mut self) -> Option<UnixStream> {
match self.obj.accept() {
Ok(s) => Some(UnixStream::new(s)),
Err(ioerr) => {
io_error::cond.raise(ioerr);
None
}
}
fn accept(&mut self) -> IoResult<UnixStream> {
self.obj.accept().map(UnixStream::new)
}
}
@@ -159,39 +141,29 @@ fn smalltest(server: proc(UnixStream), client: proc(UnixStream)) {
#[test]
fn bind_error() {
let mut called = false;
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);
match UnixListener::bind(&("path/to/nowhere")) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, PermissionDenied),
}
}
#[test]
fn connect_error() {
let mut called = false;
io_error::cond.trap(|e| {
assert_eq!(e.kind,
if cfg!(windows) {OtherIoError} else {FileNotFound});
called = true;
}).inside(|| {
let stream = UnixStream::connect(&("path/to/nowhere"));
assert!(stream.is_none());
});
assert!(called);
match UnixStream::connect(&("path/to/nowhere")) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind,
if cfg!(windows) {OtherIoError} else {FileNotFound})
}
}
#[test]
fn smoke() {
smalltest(proc(mut server) {
let mut buf = [0];
server.read(buf);
server.read(buf).unwrap();
assert!(buf[0] == 99);
}, proc(mut client) {
client.write([99]);
client.write([99]).unwrap();
})
}
@@ -199,8 +171,8 @@ fn smoke() {
fn read_eof() {
smalltest(proc(mut server) {
let mut buf = [0];
assert!(server.read(buf).is_none());
assert!(server.read(buf).is_none());
assert!(server.read(buf).is_err());
assert!(server.read(buf).is_err());
}, proc(_client) {
// drop the client
})
@@ -210,15 +182,15 @@ fn read_eof() {
fn write_begone() {
smalltest(proc(mut server) {
let buf = [0];
let mut stop = false;
while !stop{
io_error::cond.trap(|e| {
assert!(e.kind == BrokenPipe || e.kind == NotConnected,
"unknown error {:?}", e);
stop = true;
}).inside(|| {
server.write(buf);
})
loop {
match server.write(buf) {
Ok(..) => {}
Err(e) => {
assert!(e.kind == BrokenPipe || e.kind == NotConnected,
"unknown error {:?}", e);
break;
}
}
}
}, proc(_client) {
// drop the client
@@ -236,7 +208,7 @@ fn accept_lots() {
port.recv();
for _ in range(0, times) {
let mut stream = UnixStream::connect(&path2);
stream.write([100]);
stream.write([100]).unwrap();
}
});
@@ -245,7 +217,7 @@ fn accept_lots() {
for _ in range(0, times) {
let mut client = acceptor.accept();
let mut buf = [0];
client.read(buf);
client.read(buf).unwrap();
assert_eq!(buf[0], 100);
}
}
-154
View File
@@ -1,154 +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.
//! Implementations of I/O traits for the Option type
//!
//! I/O constructors return option types to allow errors to be handled.
//! These implementations allow e.g. `Option<File>` to be used
//! as a `Reader` without unwrapping the option first.
use option::*;
use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle};
use super::{standard_error, PreviousIoError, io_error, IoError};
fn prev_io_error() -> IoError {
standard_error(PreviousIoError)
}
impl<W: Writer> Writer for Option<W> {
fn write(&mut self, buf: &[u8]) {
match *self {
Some(ref mut writer) => writer.write(buf),
None => io_error::cond.raise(prev_io_error())
}
}
fn flush(&mut self) {
match *self {
Some(ref mut writer) => writer.flush(),
None => io_error::cond.raise(prev_io_error())
}
}
}
impl<R: Reader> Reader for Option<R> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
match *self {
Some(ref mut reader) => reader.read(buf),
None => {
io_error::cond.raise(prev_io_error());
None
}
}
}
}
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 {
Some(listener) => listener.listen(),
None => {
io_error::cond.raise(prev_io_error());
None
}
}
}
}
impl<T, A: Acceptor<T>> Acceptor<T> for Option<A> {
fn accept(&mut self) -> Option<T> {
match *self {
Some(ref mut acceptor) => acceptor.accept(),
None => {
io_error::cond.raise(prev_io_error());
None
}
}
}
}
#[cfg(test)]
mod test {
use prelude::*;
use super::super::mem::*;
use super::super::{PreviousIoError, io_error};
#[test]
fn test_option_writer() {
let mut writer: Option<MemWriter> = Some(MemWriter::new());
writer.write([0, 1, 2]);
writer.flush();
assert_eq!(writer.unwrap().unwrap(), ~[0, 1, 2]);
}
#[test]
fn test_option_writer_error() {
let mut writer: Option<MemWriter> = None;
let mut called = false;
io_error::cond.trap(|err| {
assert_eq!(err.kind, PreviousIoError);
called = true;
}).inside(|| {
writer.write([0, 0, 0]);
});
assert!(called);
let mut called = false;
io_error::cond.trap(|err| {
assert_eq!(err.kind, PreviousIoError);
called = true;
}).inside(|| {
writer.flush();
});
assert!(called);
}
#[test]
fn test_option_reader() {
let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3]));
let mut buf = [0, 0];
reader.read(buf);
assert_eq!(buf, [0, 1]);
}
#[test]
fn test_option_reader_error() {
let mut reader: Option<MemReader> = None;
let mut buf = [];
let mut called = false;
io_error::cond.trap(|err| {
assert_eq!(err.kind, PreviousIoError);
called = true;
}).inside(|| {
reader.read(buf);
});
assert!(called);
}
}
+13 -33
View File
@@ -14,7 +14,7 @@
//! enough so that pipes can be created to child processes.
use prelude::*;
use io::{io_error, EndOfFile};
use io::IoResult;
use libc;
use rt::rtio::{RtioPipe, LocalIo};
@@ -32,17 +32,15 @@ impl PipeStream {
///
/// # Example
///
/// use std::libc;
/// use std::io::pipe;
/// ```rust
/// # #[allow(unused_must_use)];
/// use std::libc;
/// use std::io::pipe::PipeStream;
///
/// 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: libc::c_int) -> Option<PipeStream> {
/// let mut pipe = PipeStream::open(libc::STDERR_FILENO);
/// pipe.write(bytes!("Hello, stderr!"));
/// ```
pub fn open(fd: libc::c_int) -> IoResult<PipeStream> {
LocalIo::maybe_raise(|io| {
io.pipe_open(fd).map(|obj| PipeStream { obj: obj })
})
@@ -54,29 +52,11 @@ pub fn new(inner: ~RtioPipe) -> PipeStream {
}
impl Reader for PipeStream {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
match self.obj.read(buf) {
Ok(read) => Some(read),
Err(ioerr) => {
// EOF is indicated by returning None
if ioerr.kind != EndOfFile {
io_error::cond.raise(ioerr);
}
return None;
}
}
}
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) }
}
impl Writer for PipeStream {
fn write(&mut self, buf: &[u8]) {
match self.obj.write(buf) {
Ok(_) => (),
Err(ioerr) => {
io_error::cond.raise(ioerr);
}
}
}
fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) }
}
#[cfg(test)]
@@ -91,12 +71,12 @@ mod test {
let (p, c) = Chan::new();
spawn(proc() {
let mut out = out;
out.write([10]);
out.write([10]).unwrap();
p.recv(); // don't close the pipe until the other read has finished
});
let mut buf = [0, ..10];
input.read(buf);
input.read(buf).unwrap();
c.send(());
})
}
+14 -28
View File
@@ -14,7 +14,7 @@
use libc;
use io;
use io::io_error;
use io::IoResult;
use rt::rtio::{RtioProcess, IoFactory, LocalIo};
use fmt;
@@ -93,7 +93,7 @@ pub enum ProcessExit {
impl fmt::Show for ProcessExit {
/// Format a ProcessExit enum, to nicely present the information.
fn fmt(obj: &ProcessExit, f: &mut fmt::Formatter) {
fn fmt(obj: &ProcessExit, f: &mut fmt::Formatter) -> fmt::Result {
match *obj {
ExitStatus(code) => write!(f.buf, "exit code: {}", code),
ExitSignal(code) => write!(f.buf, "signal: {}", code),
@@ -118,7 +118,7 @@ pub fn matches_exit_status(&self, wanted: int) -> bool {
impl Process {
/// Creates a new pipe initialized, but not bound to any particular
/// source/destination
pub fn new(config: ProcessConfig) -> Option<Process> {
pub fn new(config: ProcessConfig) -> IoResult<Process> {
let mut config = Some(config);
LocalIo::maybe_raise(|io| {
io.spawn(config.take_unwrap()).map(|(p, io)| {
@@ -141,14 +141,9 @@ pub fn id(&self) -> libc::pid_t { self.handle.id() }
/// Note that this is purely a wrapper around libuv's `uv_process_kill`
/// function.
///
/// If the signal delivery fails, then the `io_error` condition is raised on
pub fn signal(&mut self, signal: int) {
match self.handle.kill(signal) {
Ok(()) => {}
Err(err) => {
io_error::cond.raise(err)
}
}
/// If the signal delivery fails, the corresponding error is returned.
pub fn signal(&mut self, signal: int) -> IoResult<()> {
self.handle.kill(signal)
}
/// Wait for the child to exit completely, returning the status that it
@@ -176,7 +171,6 @@ fn drop(&mut self) {
mod tests {
use io::process::{ProcessConfig, Process};
use prelude::*;
use str;
// FIXME(#10380)
#[cfg(unix, not(target_os="android"))]
@@ -190,7 +184,7 @@ mod tests {
io: io,
};
let p = Process::new(args);
assert!(p.is_some());
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().success());
})
@@ -206,7 +200,7 @@ mod tests {
cwd: None,
io: io,
};
match io::result(|| Process::new(args)) {
match Process::new(args) {
Ok(..) => fail!(),
Err(..) => {}
}
@@ -224,7 +218,7 @@ mod tests {
io: io,
};
let p = Process::new(args);
assert!(p.is_some());
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.wait().matches_exit_status(1));
})
@@ -240,7 +234,7 @@ mod tests {
io: io,
};
let p = Process::new(args);
assert!(p.is_some());
assert!(p.is_ok());
let mut p = p.unwrap();
match p.wait() {
process::ExitSignal(1) => {},
@@ -249,20 +243,12 @@ mod tests {
})
pub fn read_all(input: &mut Reader) -> ~str {
let mut ret = ~"";
let mut buf = [0, ..1024];
loop {
match input.read(buf) {
None => { break }
Some(n) => { ret.push_str(str::from_utf8(buf.slice_to(n)).unwrap()); }
}
}
return ret;
input.read_to_str().unwrap()
}
pub fn run_output(args: ProcessConfig) -> ~str {
let p = Process::new(args);
assert!(p.is_some());
assert!(p.is_ok());
let mut p = p.unwrap();
assert!(p.io[0].is_none());
assert!(p.io[1].is_some());
@@ -312,8 +298,8 @@ pub fn run_output(args: ProcessConfig) -> ~str {
cwd: None,
io: io,
};
let mut p = Process::new(args).expect("didn't create a proces?!");
p.io[0].get_mut_ref().write("foobar".as_bytes());
let mut p = Process::new(args).unwrap();
p.io[0].get_mut_ref().write("foobar".as_bytes()).unwrap();
p.io[0] = None; // close stdin;
let out = read_all(p.io[1].get_mut_ref() as &mut Reader);
assert!(p.wait().success());
+128
View File
@@ -0,0 +1,128 @@
// 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.
//! Implementations of I/O traits for the IoResult type
//!
//! I/O constructors return option types to allow errors to be handled.
//! These implementations allow e.g. `IoResult<File>` to be used
//! as a `Reader` without unwrapping the result first.
use clone::Clone;
use result::{Ok, Err};
use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle, IoResult};
impl<W: Writer> Writer for IoResult<W> {
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
match *self {
Ok(ref mut writer) => writer.write(buf),
Err(ref e) => Err((*e).clone())
}
}
fn flush(&mut self) -> IoResult<()> {
match *self {
Ok(ref mut writer) => writer.flush(),
Err(ref e) => Err(e.clone()),
}
}
}
impl<R: Reader> Reader for IoResult<R> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
match *self {
Ok(ref mut reader) => reader.read(buf),
Err(ref e) => Err(e.clone()),
}
}
}
impl<S: Seek> Seek for IoResult<S> {
fn tell(&self) -> IoResult<u64> {
match *self {
Ok(ref seeker) => seeker.tell(),
Err(ref e) => Err(e.clone()),
}
}
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> {
match *self {
Ok(ref mut seeker) => seeker.seek(pos, style),
Err(ref e) => Err(e.clone())
}
}
}
impl<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for IoResult<L> {
fn listen(self) -> IoResult<A> {
match self {
Ok(listener) => listener.listen(),
Err(e) => Err(e),
}
}
}
impl<T, A: Acceptor<T>> Acceptor<T> for IoResult<A> {
fn accept(&mut self) -> IoResult<T> {
match *self {
Ok(ref mut acceptor) => acceptor.accept(),
Err(ref e) => Err(e.clone()),
}
}
}
#[cfg(test)]
mod test {
use prelude::*;
use super::super::mem::*;
use io;
#[test]
fn test_option_writer() {
let mut writer: io::IoResult<MemWriter> = Ok(MemWriter::new());
writer.write([0, 1, 2]).unwrap();
writer.flush().unwrap();
assert_eq!(writer.unwrap().unwrap(), ~[0, 1, 2]);
}
#[test]
fn test_option_writer_error() {
let mut writer: io::IoResult<MemWriter> =
Err(io::standard_error(io::EndOfFile));
match writer.write([0, 0, 0]) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::EndOfFile),
}
match writer.flush() {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::EndOfFile),
}
}
#[test]
fn test_option_reader() {
let mut reader: io::IoResult<MemReader> =
Ok(MemReader::new(~[0, 1, 2, 3]));
let mut buf = [0, 0];
reader.read(buf).unwrap();
assert_eq!(buf, [0, 1]);
}
#[test]
fn test_option_reader_error() {
let mut reader: io::IoResult<MemReader> =
Err(io::standard_error(io::EndOfFile));
let mut buf = [];
match reader.read(buf) {
Ok(..) => fail!(),
Err(e) => assert_eq!(e.kind, io::EndOfFile),
}
}
}
+19 -20
View File
@@ -20,10 +20,11 @@
*/
use clone::Clone;
use result::{Ok, Err};
use comm::{Port, SharedChan};
use container::{Map, MutableMap};
use hashmap;
use option::{Some, None};
use io;
use rt::rtio::{IoFactory, LocalIo, RtioSignal};
#[repr(int)]
@@ -112,23 +113,22 @@ pub fn new() -> Listener {
/// a signal, and a later call to `recv` will return the signal that was
/// received while no task was waiting on it.
///
/// # Failure
/// # Error
///
/// 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 {
/// be returned.
pub fn register(&mut self, signum: Signum) -> io::IoResult<()> {
if self.handles.contains_key(&signum) {
return true; // self is already listening to signum, so succeed
return Ok(()); // self is already listening to signum, so succeed
}
match LocalIo::maybe_raise(|io| {
io.signal(signum, self.chan.clone())
}) {
Some(handle) => {
Ok(handle) => {
self.handles.insert(signum, handle);
true
Ok(())
}
None => false
Err(e) => Err(e)
}
}
@@ -159,7 +159,7 @@ fn sigint() {
#[test] #[cfg(unix, not(target_os="android"))] // FIXME(#10378)
fn test_io_signal_smoketest() {
let mut signal = Listener::new();
signal.register(Interrupt);
signal.register(Interrupt).unwrap();
sigint();
timer::sleep(10);
match signal.port.recv() {
@@ -172,8 +172,8 @@ fn test_io_signal_smoketest() {
fn test_io_signal_two_signal_one_signum() {
let mut s1 = Listener::new();
let mut s2 = Listener::new();
s1.register(Interrupt);
s2.register(Interrupt);
s1.register(Interrupt).unwrap();
s2.register(Interrupt).unwrap();
sigint();
timer::sleep(10);
match s1.port.recv() {
@@ -190,8 +190,8 @@ fn test_io_signal_two_signal_one_signum() {
fn test_io_signal_unregister() {
let mut s1 = Listener::new();
let mut s2 = Listener::new();
s1.register(Interrupt);
s2.register(Interrupt);
s1.register(Interrupt).unwrap();
s2.register(Interrupt).unwrap();
s2.unregister(Interrupt);
sigint();
timer::sleep(10);
@@ -203,15 +203,14 @@ fn test_io_signal_unregister() {
fn test_io_signal_invalid_signum() {
use io;
use super::User1;
use result::{Ok, Err};
let mut s = Listener::new();
let mut called = false;
io::io_error::cond.trap(|_| {
called = true;
}).inside(|| {
if s.register(User1) {
match s.register(User1) {
Ok(..) => {
fail!("Unexpected successful registry of signum {:?}", User1);
}
});
assert!(called);
Err(..) => {}
}
}
}
+39 -56
View File
@@ -18,6 +18,7 @@
# Example
```rust
# #[allow(unused_must_use)];
use std::io;
let mut out = io::stdout();
@@ -28,7 +29,7 @@
use container::Container;
use fmt;
use io::{Reader, Writer, io_error, IoError, OtherIoError,
use io::{Reader, Writer, IoResult, IoError, OtherIoError,
standard_error, EndOfFile, LineBufferedWriter};
use libc;
use option::{Option, Some, None};
@@ -114,7 +115,8 @@ fn reset_helper(w: ~Writer,
match f(t.get(), w) {
Some(mut w) => {
drop(t);
w.flush();
// FIXME: is failing right here?
w.flush().unwrap();
Some(w)
}
None => None
@@ -155,9 +157,9 @@ pub fn set_stderr(stderr: ~Writer) -> Option<~Writer> {
// // io1 aliases io2
// })
// })
fn with_task_stdout(f: |&mut Writer|) {
fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) {
let task: Option<~Task> = Local::try_take();
match task {
let result = match task {
Some(mut task) => {
// Printing may run arbitrary code, so ensure that the task is in
// TLS to allow all std services. Note that this means a print while
@@ -169,7 +171,7 @@ fn with_task_stdout(f: |&mut Writer|) {
if my_stdout.is_none() {
my_stdout = Some(~LineBufferedWriter::new(stdout()) as ~Writer);
}
f(*my_stdout.get_mut_ref());
let ret = f(*my_stdout.get_mut_ref());
// Note that we need to be careful when putting the stdout handle
// back into the task. If the handle was set to `Some` while
@@ -184,22 +186,29 @@ fn with_task_stdout(f: |&mut Writer|) {
let prev = util::replace(&mut t.get().stdout, my_stdout);
drop(t);
drop(prev);
ret
}
None => {
struct Stdout;
impl Writer for Stdout {
fn write(&mut self, data: &[u8]) {
fn write(&mut self, data: &[u8]) -> IoResult<()> {
unsafe {
libc::write(libc::STDOUT_FILENO,
data.as_ptr() as *libc::c_void,
data.len() as libc::size_t);
}
Ok(()) // just ignore the results
}
}
let mut io = Stdout;
f(&mut io as &mut Writer);
f(&mut io as &mut Writer)
}
};
match result {
Ok(()) => {}
Err(e) => fail!("failed printing to stdout: {}", e),
}
}
@@ -226,8 +235,7 @@ pub fn print(s: &str) {
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
with_task_stdout(|io| {
io.write(s.as_bytes());
io.write(['\n' as u8]);
io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8]))
})
}
@@ -249,7 +257,7 @@ pub struct StdReader {
}
impl Reader for StdReader {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
let ret = match self.inner {
TTY(ref mut tty) => tty.read(buf),
File(ref mut file) => file.read(buf).map(|i| i as uint),
@@ -260,15 +268,8 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
// return an actual EOF error, but apparently for stdin it's a
// little different. Hence, here we convert a 0 length read to an
// end-of-file indicator so the caller knows to stop reading.
Ok(0) => {
io_error::cond.raise(standard_error(EndOfFile));
None
}
Ok(amt) => Some(amt),
Err(e) => {
io_error::cond.raise(e);
None
}
Ok(0) => { Err(standard_error(EndOfFile)) }
ret @ Ok(..) | ret @ Err(..) => ret,
}
}
}
@@ -283,30 +284,21 @@ impl StdWriter {
/// 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)).
/// If successful, returns `Ok((width, height))`.
///
/// # Failure
/// # Error
///
/// This function will raise on the `io_error` condition if an error
/// happens.
pub fn winsize(&mut self) -> Option<(int, int)> {
/// This function will return an error if the output stream is not actually
/// connected to a TTY instance, or if querying the TTY instance fails.
pub fn winsize(&mut self) -> IoResult<(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
}
}
}
TTY(ref mut tty) => tty.get_winsize(),
File(..) => {
io_error::cond.raise(IoError {
Err(IoError {
kind: OtherIoError,
desc: "stream is not a tty",
detail: None,
});
None
})
}
}
}
@@ -314,24 +306,19 @@ pub fn winsize(&mut self) -> Option<(int, int)> {
/// Controls whether this output stream is a "raw stream" or simply a normal
/// stream.
///
/// # Failure
/// # Error
///
/// This function will raise on the `io_error` condition if an error
/// happens.
pub fn set_raw(&mut self, raw: bool) {
/// This function will return an error if the output stream is not actually
/// connected to a TTY instance, or if querying the TTY instance fails.
pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
match self.inner {
TTY(ref mut tty) => {
match tty.set_raw(raw) {
Ok(()) => {},
Err(e) => io_error::cond.raise(e),
}
}
TTY(ref mut tty) => tty.set_raw(raw),
File(..) => {
io_error::cond.raise(IoError {
Err(IoError {
kind: OtherIoError,
desc: "stream is not a tty",
detail: None,
});
})
}
}
}
@@ -346,14 +333,10 @@ pub fn isatty(&self) -> bool {
}
impl Writer for StdWriter {
fn write(&mut self, buf: &[u8]) {
let ret = match self.inner {
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
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)
}
}
}
@@ -376,7 +359,7 @@ mod tests {
set_stdout(~w as ~Writer);
println!("hello!");
});
assert_eq!(r.read_to_str(), ~"hello!\n");
assert_eq!(r.read_to_str().unwrap(), ~"hello!\n");
})
iotest!(fn capture_stderr() {
@@ -388,7 +371,7 @@ mod tests {
set_stderr(~w as ~Writer);
fail!("my special message");
});
let s = r.read_to_str();
let s = r.read_to_str().unwrap();
assert!(s.contains("my special message"));
})
}
+4 -3
View File
@@ -39,8 +39,8 @@
*/
use comm::Port;
use option::Option;
use rt::rtio::{IoFactory, LocalIo, RtioTimer};
use io::IoResult;
pub struct Timer {
priv obj: ~RtioTimer
@@ -48,7 +48,8 @@ pub struct Timer {
/// Sleep the current task for `msecs` milliseconds.
pub fn sleep(msecs: u64) {
let mut timer = Timer::new().expect("timer::sleep: could not create a Timer");
let timer = Timer::new();
let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");
timer.sleep(msecs)
}
@@ -57,7 +58,7 @@ impl Timer {
/// Creates a new timer which can be used to put the current task to sleep
/// for a number of milliseconds, or to possibly create channels which will
/// get notified after an amount of time has passed.
pub fn new() -> Option<Timer> {
pub fn new() -> IoResult<Timer> {
LocalIo::maybe_raise(|io| io.timer_init().map(|t| Timer { obj: t }))
}
+55 -40
View File
@@ -7,8 +7,10 @@
// <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 cmp;
use io;
use vec::bytes::MutableByteVector;
/// Wraps a `Reader`, limiting the number of bytes that can be read from it.
@@ -25,9 +27,9 @@ pub fn new<'a>(r: &'a mut R, limit: uint) -> LimitReader<'a, R> {
}
impl<'a, R: Reader> Reader for LimitReader<'a, R> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
if self.limit == 0 {
return None;
return Err(io::standard_error(io::EndOfFile));
}
let len = cmp::min(self.limit, buf.len());
@@ -43,7 +45,7 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
impl Writer for NullWriter {
#[inline]
fn write(&mut self, _buf: &[u8]) { }
fn write(&mut self, _buf: &[u8]) -> io::IoResult<()> { Ok(()) }
}
/// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero.
@@ -51,9 +53,9 @@ fn write(&mut self, _buf: &[u8]) { }
impl Reader for ZeroReader {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
buf.set_memory(0);
Some(buf.len())
Ok(buf.len())
}
}
@@ -62,8 +64,8 @@ fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
impl Reader for NullReader {
#[inline]
fn read(&mut self, _buf: &mut [u8]) -> Option<uint> {
None
fn read(&mut self, _buf: &mut [u8]) -> io::IoResult<uint> {
Err(io::standard_error(io::EndOfFile))
}
}
@@ -81,17 +83,21 @@ pub fn new(writers: ~[~Writer]) -> MultiWriter {
impl Writer for MultiWriter {
#[inline]
fn write(&mut self, buf: &[u8]) {
fn write(&mut self, buf: &[u8]) -> io::IoResult<()> {
let mut ret = Ok(());
for writer in self.writers.mut_iter() {
writer.write(buf);
ret = ret.and(writer.write(buf));
}
return ret;
}
#[inline]
fn flush(&mut self) {
fn flush(&mut self) -> io::IoResult<()> {
let mut ret = Ok(());
for writer in self.writers.mut_iter() {
writer.flush();
ret = ret.and(writer.flush());
}
return ret;
}
}
@@ -111,20 +117,25 @@ pub fn new(mut readers: I) -> ChainedReader<I, R> {
}
impl<R: Reader, I: Iterator<R>> Reader for ChainedReader<I, R> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
loop {
match self.cur_reader {
let err = match self.cur_reader {
Some(ref mut r) => {
match r.read(buf) {
Some(len) => return Some(len),
None => {}
Ok(len) => return Ok(len),
Err(ref e) if e.kind == io::EndOfFile => None,
Err(e) => Some(e),
}
}
None => break
};
self.cur_reader = self.readers.next();
match err {
Some(e) => return Err(e),
None => {}
}
self.cur_reader = self.readers.next()
}
None
Err(io::standard_error(io::EndOfFile))
}
}
@@ -150,27 +161,29 @@ pub fn unwrap(self) -> (R, W) {
}
impl<R: Reader, W: Writer> Reader for TeeReader<R, W> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
self.reader.read(buf).map(|len| {
self.writer.write(buf.slice_to(len));
len
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> {
self.reader.read(buf).and_then(|len| {
self.writer.write(buf.slice_to(len)).map(|()| len)
})
}
}
/// Copies all data from a `Reader` to a `Writer`.
pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) {
pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) -> io::IoResult<()> {
let mut buf = [0, ..super::DEFAULT_BUF_SIZE];
loop {
match r.read(buf) {
Some(len) => w.write(buf.slice_to(len)),
None => break
}
let len = match r.read(buf) {
Ok(len) => len,
Err(ref e) if e.kind == io::EndOfFile => return Ok(()),
Err(e) => return Err(e),
};
if_ok!(w.write(buf.slice_to(len)));
}
}
#[cfg(test)]
mod test {
use io;
use io::{MemReader, MemWriter};
use super::*;
use prelude::*;
@@ -180,7 +193,7 @@ fn test_bounded_reader_unlimited() {
let mut r = MemReader::new(~[0, 1, 2]);
{
let mut r = LimitReader::new(&mut r, 4);
assert_eq!(~[0, 1, 2], r.read_to_end());
assert_eq!(~[0, 1, 2], r.read_to_end().unwrap());
}
}
@@ -189,24 +202,24 @@ fn test_bound_reader_limited() {
let mut r = MemReader::new(~[0, 1, 2]);
{
let mut r = LimitReader::new(&mut r, 2);
assert_eq!(~[0, 1], r.read_to_end());
assert_eq!(~[0, 1], r.read_to_end().unwrap());
}
assert_eq!(~[2], r.read_to_end());
assert_eq!(~[2], r.read_to_end().unwrap());
}
#[test]
fn test_null_writer() {
let mut s = NullWriter;
let buf = ~[0, 0, 0];
s.write(buf);
s.flush();
s.write(buf).unwrap();
s.flush().unwrap();
}
#[test]
fn test_zero_reader() {
let mut s = ZeroReader;
let mut buf = ~[1, 2, 3];
assert_eq!(s.read(buf), Some(3));
assert_eq!(s.read(buf), Ok(3));
assert_eq!(~[0, 0, 0], buf);
}
@@ -214,7 +227,7 @@ fn test_zero_reader() {
fn test_null_reader() {
let mut r = NullReader;
let mut buf = ~[0];
assert_eq!(r.read(buf), None);
assert!(r.read(buf).is_err());
}
#[test]
@@ -224,21 +237,23 @@ fn test_multi_writer() {
struct TestWriter;
impl Writer for TestWriter {
fn write(&mut self, _buf: &[u8]) {
fn write(&mut self, _buf: &[u8]) -> io::IoResult<()> {
unsafe { writes += 1 }
Ok(())
}
fn flush(&mut self) {
fn flush(&mut self) -> io::IoResult<()> {
unsafe { flushes += 1 }
Ok(())
}
}
let mut multi = MultiWriter::new(~[~TestWriter as ~Writer,
~TestWriter as ~Writer]);
multi.write([1, 2, 3]);
multi.write([1, 2, 3]).unwrap();
assert_eq!(2, unsafe { writes });
assert_eq!(0, unsafe { flushes });
multi.flush();
multi.flush().unwrap();
assert_eq!(2, unsafe { writes });
assert_eq!(2, unsafe { flushes });
}
@@ -248,14 +263,14 @@ fn test_chained_reader() {
let rs = ~[MemReader::new(~[0, 1]), MemReader::new(~[]),
MemReader::new(~[2, 3])];
let mut r = ChainedReader::new(rs.move_iter());
assert_eq!(~[0, 1, 2, 3], r.read_to_end());
assert_eq!(~[0, 1, 2, 3], r.read_to_end().unwrap());
}
#[test]
fn test_tee_reader() {
let mut r = TeeReader::new(MemReader::new(~[0, 1, 2]),
MemWriter::new());
assert_eq!(~[0, 1, 2], r.read_to_end());
assert_eq!(~[0, 1, 2], r.read_to_end().unwrap());
let (_, w) = r.unwrap();
assert_eq!(~[0, 1, 2], w.unwrap());
}
@@ -264,7 +279,7 @@ fn test_tee_reader() {
fn test_copy() {
let mut r = MemReader::new(~[0, 1, 2, 3, 4]);
let mut w = MemWriter::new();
copy(&mut r, &mut w);
copy(&mut r, &mut w).unwrap();
assert_eq!(~[0, 1, 2, 3, 4], w.unwrap());
}
}
+9 -2
View File
@@ -102,6 +102,7 @@
use ops::Drop;
use option::{Some, None, Option};
use prelude::drop;
use result::{Ok, Err};
use rt::local::Local;
use rt::task::Task;
use util;
@@ -131,13 +132,19 @@ struct DefaultLogger {
impl Logger for DefaultLogger {
// by default, just ignore the level
fn log(&mut self, _level: u32, args: &fmt::Arguments) {
fmt::writeln(&mut self.handle, args);
match fmt::writeln(&mut self.handle, args) {
Err(e) => fail!("failed to log: {}", e),
Ok(()) => {}
}
}
}
impl Drop for DefaultLogger {
fn drop(&mut self) {
self.handle.flush();
match self.handle.flush() {
Err(e) => fail!("failed to flush a logger: {}", e),
Ok(()) => {}
}
}
}
+5
View File
@@ -197,3 +197,8 @@ macro_rules! local_data_key (
pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
)
)
#[macro_export]
macro_rules! if_ok (
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
)
+1 -1
View File
@@ -382,7 +382,7 @@ pub fn unwrap_or_default(self) -> T {
impl<T: fmt::Show> fmt::Show for Option<T> {
#[inline]
fn fmt(s: &Option<T>, f: &mut fmt::Formatter) {
fn fmt(s: &Option<T>, f: &mut fmt::Formatter) -> fmt::Result {
match *s {
Some(ref t) => write!(f.buf, "Some({})", *t),
None => write!(f.buf, "None")
+11 -16
View File
@@ -372,9 +372,9 @@ fn load_self() -> Option<~[u8]> {
fn load_self() -> Option<~[u8]> {
use std::io;
match io::result(|| io::fs::readlink(&Path::new("/proc/self/exe"))) {
Ok(Some(path)) => Some(path.as_vec().to_owned()),
Ok(None) | Err(..) => None
match io::fs::readlink(&Path::new("/proc/self/exe")) {
Ok(path) => Some(path.as_vec().to_owned()),
Err(..) => None
}
}
@@ -929,7 +929,7 @@ pub enum MapError {
}
impl fmt::Show for MapError {
fn fmt(val: &MapError, out: &mut fmt::Formatter) {
fn fmt(val: &MapError, out: &mut fmt::Formatter) -> fmt::Result {
let str = match *val {
ErrFdNotAvail => "fd not available for reading or writing",
ErrInvalidFd => "Invalid fd",
@@ -944,23 +944,19 @@ fn fmt(val: &MapError, out: &mut fmt::Formatter) {
ErrAlreadyExists => "File mapping for specified file already exists",
ErrZeroLength => "Zero-length mapping not allowed",
ErrUnknown(code) => {
write!(out.buf, "Unknown error = {}", code);
return
return write!(out.buf, "Unknown error = {}", code)
},
ErrVirtualAlloc(code) => {
write!(out.buf, "VirtualAlloc failure = {}", code);
return
return write!(out.buf, "VirtualAlloc failure = {}", code)
},
ErrCreateFileMappingW(code) => {
format!("CreateFileMappingW failure = {}", code);
return
return write!(out.buf, "CreateFileMappingW failure = {}", code)
},
ErrMapViewOfFile(code) => {
write!(out.buf, "MapViewOfFile failure = {}", code);
return
return write!(out.buf, "MapViewOfFile failure = {}", code)
}
};
write!(out.buf, "{}", str);
write!(out.buf, "{}", str)
}
}
@@ -1496,7 +1492,6 @@ fn memory_map_file() {
use result::{Ok, Err};
use os::*;
use libc::*;
use io;
use io::fs;
#[cfg(unix)]
@@ -1540,9 +1535,9 @@ fn lseek_(fd: c_int, size: uint) {
assert!(*chunk.data == 0xbe);
close(fd);
}
drop(chunk);
let _guard = io::ignore_io_error();
fs::unlink(&path);
fs::unlink(&path).unwrap();
}
// More recursive_mkdir tests are in extra::tempfile
+1 -1
View File
@@ -533,7 +533,7 @@ pub struct Display<'a, P> {
}
impl<'a, P: GenericPath> fmt::Show for Display<'a, P> {
fn fmt(d: &Display<P>, f: &mut fmt::Formatter) {
fn fmt(d: &Display<P>, f: &mut fmt::Formatter) -> fmt::Result {
d.with_str(|s| f.pad(s))
}
}
+1 -1
View File
@@ -62,7 +62,7 @@ impl OSRng {
pub fn new() -> OSRng {
use path::Path;
let reader = File::open(&Path::new("/dev/urandom"));
let reader = reader.expect("Error opening /dev/urandom");
let reader = reader.ok().expect("Error opening /dev/urandom");
let reader_rng = ReaderRng::new(reader);
OSRng { inner: reader_rng }
+9 -9
View File
@@ -11,7 +11,7 @@
//! A wrapper around any Reader to treat it as an RNG.
use container::Container;
use option::{Some, None};
use result::{Ok, Err};
use io::Reader;
use rand::Rng;
@@ -49,26 +49,26 @@ fn next_u32(&mut self) -> u32 {
// platform just involves blitting the bytes into the memory
// of the u32, similarly for BE on BE; avoiding byteswapping.
if cfg!(target_endian="little") {
self.reader.read_le_u32()
self.reader.read_le_u32().unwrap()
} else {
self.reader.read_be_u32()
self.reader.read_be_u32().unwrap()
}
}
fn next_u64(&mut self) -> u64 {
// see above for explanation.
if cfg!(target_endian="little") {
self.reader.read_le_u64()
self.reader.read_le_u64().unwrap()
} else {
self.reader.read_be_u64()
self.reader.read_be_u64().unwrap()
}
}
fn fill_bytes(&mut self, v: &mut [u8]) {
if v.len() == 0 { return }
match self.reader.read(v) {
Some(n) if n == v.len() => return,
Some(n) => fail!("ReaderRng.fill_bytes could not fill buffer: \
read {} out of {} bytes.", n, v.len()),
None => fail!("ReaderRng.fill_bytes reached eof.")
Ok(n) if n == v.len() => return,
Ok(n) => fail!("ReaderRng.fill_bytes could not fill buffer: \
read {} out of {} bytes.", n, v.len()),
Err(e) => fail!("ReaderRng.fill_bytes error: {}", e)
}
}
}
+2
View File
@@ -66,6 +66,8 @@ pub fn align_to<T>(&mut self) {
pub fn bump_past<T>(&mut self) {
self.bump(mem::size_of::<T>());
}
pub fn unwrap(self) -> V { self.inner }
}
/// Abstract type-directed pointer-movement using the MovePtr trait
+118 -88
View File
@@ -21,48 +21,57 @@
use container::Container;
use io;
use iter::Iterator;
use option::{Some, None};
use option::{Some, None, Option};
use ptr;
use reflect;
use reflect::{MovePtr, align};
use result::{Ok, Err};
use str::StrSlice;
use to_str::ToStr;
use vec::OwnedVector;
use unstable::intrinsics::{Disr, Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
use unstable::raw;
macro_rules! if_ok( ($me:expr, $e:expr) => (
match $e {
Ok(()) => {},
Err(e) => { $me.last_err = Some(e); return false; }
}
) )
/// Representations
trait Repr {
fn write_repr(&self, writer: &mut io::Writer);
fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()>;
}
impl Repr for () {
fn write_repr(&self, writer: &mut io::Writer) {
writer.write("()".as_bytes());
fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> {
writer.write("()".as_bytes())
}
}
impl Repr for bool {
fn write_repr(&self, writer: &mut io::Writer) {
fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> {
let s = if *self { "true" } else { "false" };
writer.write(s.as_bytes())
}
}
impl Repr for int {
fn write_repr(&self, writer: &mut io::Writer) {
fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> {
::int::to_str_bytes(*self, 10u, |bits| {
writer.write(bits);
writer.write(bits)
})
}
}
macro_rules! int_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
fn write_repr(&self, writer: &mut io::Writer) {
fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> {
::$ty::to_str_bytes(*self, 10u, |bits| {
writer.write(bits);
writer.write(bytes!($suffix));
writer.write(bits).and_then(|()| {
writer.write(bytes!($suffix))
})
})
}
}))
@@ -78,10 +87,11 @@ fn write_repr(&self, writer: &mut io::Writer) {
int_repr!(u64, "u64")
macro_rules! num_repr(($ty:ident, $suffix:expr) => (impl Repr for $ty {
fn write_repr(&self, writer: &mut io::Writer) {
fn write_repr(&self, writer: &mut io::Writer) -> io::IoResult<()> {
let s = self.to_str();
writer.write(s.as_bytes());
writer.write(bytes!($suffix));
writer.write(s.as_bytes()).and_then(|()| {
writer.write(bytes!($suffix))
})
}
}))
@@ -100,7 +110,8 @@ pub struct ReprVisitor<'a> {
priv ptr: *u8,
priv ptr_stk: ~[*u8],
priv var_stk: ~[VariantState],
priv writer: &'a mut io::Writer
priv writer: &'a mut io::Writer,
priv last_err: Option<io::IoError>,
}
pub fn ReprVisitor<'a>(ptr: *u8,
@@ -110,6 +121,7 @@ pub fn ReprVisitor<'a>(ptr: *u8,
ptr_stk: ~[],
var_stk: ~[],
writer: writer,
last_err: None,
}
}
@@ -130,11 +142,10 @@ impl<'a> ReprVisitor<'a> {
// Various helpers for the TyVisitor impl
#[inline]
pub fn get<T>(&mut self, f: |&mut ReprVisitor, &T|) -> bool {
pub fn get<T>(&mut self, f: |&mut ReprVisitor, &T| -> bool) -> bool {
unsafe {
f(self, transmute::<*u8,&T>(self.ptr));
f(self, transmute::<*u8,&T>(self.ptr))
}
true
}
#[inline]
@@ -152,43 +163,53 @@ pub fn visit_ptr_inner(&mut self, ptr: *u8, inner: *TyDesc) -> bool {
ptr_stk: ~[],
var_stk: ~[],
writer: ::cast::transmute_copy(&self.writer),
last_err: None,
};
let mut v = reflect::MovePtrAdaptor(u);
// Obviously this should not be a thing, but blame #8401 for now
visit_tydesc(inner, &mut v as &mut TyVisitor);
true
match v.unwrap().last_err {
Some(e) => {
self.last_err = Some(e);
false
}
None => true,
}
}
}
#[inline]
pub fn write<T:Repr>(&mut self) -> bool {
self.get(|this, v:&T| {
v.write_repr(unsafe { ::cast::transmute_copy(&this.writer) });
if_ok!(this, v.write_repr(this.writer));
true
})
}
pub fn write_escaped_slice(&mut self, slice: &str) {
self.writer.write(['"' as u8]);
pub fn write_escaped_slice(&mut self, slice: &str) -> bool {
if_ok!(self, self.writer.write(['"' as u8]));
for ch in slice.chars() {
self.write_escaped_char(ch, true);
if !self.write_escaped_char(ch, true) { return false }
}
self.writer.write(['"' as u8]);
if_ok!(self, self.writer.write(['"' as u8]));
true
}
pub fn write_mut_qualifier(&mut self, mtbl: uint) {
pub fn write_mut_qualifier(&mut self, mtbl: uint) -> bool {
if mtbl == 0 {
self.writer.write("mut ".as_bytes());
if_ok!(self, self.writer.write("mut ".as_bytes()));
} else if mtbl == 1 {
// skip, this is ast::m_imm
} else {
fail!("invalid mutability value");
}
true
}
pub fn write_vec_range(&mut self, ptr: *(), len: uint, inner: *TyDesc) -> bool {
let mut p = ptr as *u8;
let (sz, al) = unsafe { ((*inner).size, (*inner).align) };
self.writer.write(['[' as u8]);
if_ok!(self, self.writer.write(['[' as u8]));
let mut first = true;
let mut left = len;
// unit structs have 0 size, and don't loop forever.
@@ -197,13 +218,13 @@ pub fn write_vec_range(&mut self, ptr: *(), len: uint, inner: *TyDesc) -> bool {
if first {
first = false;
} else {
self.writer.write(", ".as_bytes());
if_ok!(self, self.writer.write(", ".as_bytes()));
}
self.visit_ptr_inner(p as *u8, inner);
p = align(unsafe { ptr::offset(p, sz as int) as uint }, al) as *u8;
left -= dec;
}
self.writer.write([']' as u8]);
if_ok!(self, self.writer.write([']' as u8]));
true
}
@@ -211,8 +232,8 @@ pub fn write_unboxed_vec_repr(&mut self, _: uint, v: &raw::Vec<()>, inner: *TyDe
self.write_vec_range(ptr::to_unsafe_ptr(&v.data), v.fill, inner)
}
fn write_escaped_char(&mut self, ch: char, is_str: bool) {
match ch {
fn write_escaped_char(&mut self, ch: char, is_str: bool) -> bool {
if_ok!(self, match ch {
'\t' => self.writer.write("\\t".as_bytes()),
'\r' => self.writer.write("\\r".as_bytes()),
'\n' => self.writer.write("\\n".as_bytes()),
@@ -234,16 +255,18 @@ fn write_escaped_char(&mut self, ch: char, is_str: bool) {
'\x20'..'\x7e' => self.writer.write([ch as u8]),
_ => {
char::escape_unicode(ch, |c| {
self.writer.write([c as u8]);
})
let _ = self.writer.write([c as u8]);
});
Ok(())
}
}
});
return true;
}
}
impl<'a> TyVisitor for ReprVisitor<'a> {
fn visit_bot(&mut self) -> bool {
self.writer.write("!".as_bytes());
if_ok!(self, self.writer.write("!".as_bytes()));
true
}
fn visit_nil(&mut self) -> bool { self.write::<()>() }
@@ -265,9 +288,10 @@ fn visit_f64(&mut self) -> bool { self.write::<f64>() }
fn visit_char(&mut self) -> bool {
self.get::<char>(|this, &ch| {
this.writer.write(['\'' as u8]);
this.write_escaped_char(ch, false);
this.writer.write(['\'' as u8]);
if_ok!(this, this.writer.write(['\'' as u8]));
if !this.write_escaped_char(ch, false) { return false }
if_ok!(this, this.writer.write(['\'' as u8]));
true
})
}
@@ -277,8 +301,8 @@ fn visit_estr_box(&mut self) -> bool {
fn visit_estr_uniq(&mut self) -> bool {
self.get::<~str>(|this, s| {
this.writer.write(['~' as u8]);
this.write_escaped_slice(*s);
if_ok!(this, this.writer.write(['~' as u8]));
this.write_escaped_slice(*s)
})
}
@@ -291,34 +315,35 @@ fn visit_estr_fixed(&mut self, _n: uint, _sz: uint,
_align: uint) -> bool { fail!(); }
fn visit_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
self.writer.write(['@' as u8]);
if_ok!(self, self.writer.write(['@' as u8]));
self.write_mut_qualifier(mtbl);
self.get::<&raw::Box<()>>(|this, b| {
let p = ptr::to_unsafe_ptr(&b.data) as *u8;
this.visit_ptr_inner(p, inner);
this.visit_ptr_inner(p, inner)
})
}
fn visit_uniq(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
self.writer.write(['~' as u8]);
if_ok!(self, self.writer.write(['~' as u8]));
self.get::<*u8>(|this, b| {
this.visit_ptr_inner(*b, inner);
this.visit_ptr_inner(*b, inner)
})
}
fn visit_ptr(&mut self, mtbl: uint, _inner: *TyDesc) -> bool {
self.get::<*u8>(|this, p| {
write!(this.writer, "({} as *", *p);
if_ok!(this, write!(this.writer, "({} as *", *p));
this.write_mut_qualifier(mtbl);
this.writer.write("())".as_bytes());
if_ok!(this, this.writer.write("())".as_bytes()));
true
})
}
fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
self.writer.write(['&' as u8]);
if_ok!(self, self.writer.write(['&' as u8]));
self.write_mut_qualifier(mtbl);
self.get::<*u8>(|this, p| {
this.visit_ptr_inner(*p, inner);
this.visit_ptr_inner(*p, inner)
})
}
@@ -327,33 +352,33 @@ fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
fn visit_unboxed_vec(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
self.get::<raw::Vec<()>>(|this, b| {
this.write_unboxed_vec_repr(mtbl, b, inner);
this.write_unboxed_vec_repr(mtbl, b, inner)
})
}
fn visit_evec_box(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
self.get::<&raw::Box<raw::Vec<()>>>(|this, b| {
this.writer.write(['@' as u8]);
if_ok!(this, this.writer.write(['@' as u8]));
this.write_mut_qualifier(mtbl);
this.write_unboxed_vec_repr(mtbl, &b.data, inner);
this.write_unboxed_vec_repr(mtbl, &b.data, inner)
})
}
fn visit_evec_uniq(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
self.get::<&raw::Vec<()>>(|this, b| {
this.writer.write(['~' as u8]);
this.write_unboxed_vec_repr(mtbl, *b, inner);
if_ok!(this, this.writer.write(['~' as u8]));
this.write_unboxed_vec_repr(mtbl, *b, inner)
})
}
fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
self.get::<raw::Slice<()>>(|this, s| {
this.writer.write(['&' as u8]);
if_ok!(this, this.writer.write(['&' as u8]));
this.write_mut_qualifier(mtbl);
let size = unsafe {
if (*inner).size == 0 { 1 } else { (*inner).size }
};
this.write_vec_range(s.data, s.len * size, inner);
this.write_vec_range(s.data, s.len * size, inner)
})
}
@@ -361,42 +386,42 @@ fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint,
_: uint, inner: *TyDesc) -> bool {
let assumed_size = if sz == 0 { n } else { sz };
self.get::<()>(|this, b| {
this.write_vec_range(ptr::to_unsafe_ptr(b), assumed_size, inner);
this.write_vec_range(ptr::to_unsafe_ptr(b), assumed_size, inner)
})
}
fn visit_enter_rec(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
self.writer.write(['{' as u8]);
if_ok!(self, self.writer.write(['{' as u8]));
true
}
fn visit_rec_field(&mut self, i: uint, name: &str,
mtbl: uint, inner: *TyDesc) -> bool {
if i != 0 {
self.writer.write(", ".as_bytes());
if_ok!(self, self.writer.write(", ".as_bytes()));
}
self.write_mut_qualifier(mtbl);
self.writer.write(name.as_bytes());
self.writer.write(": ".as_bytes());
if_ok!(self, self.writer.write(name.as_bytes()));
if_ok!(self, self.writer.write(": ".as_bytes()));
self.visit_inner(inner);
true
}
fn visit_leave_rec(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
self.writer.write(['}' as u8]);
if_ok!(self, self.writer.write(['}' as u8]));
true
}
fn visit_enter_class(&mut self, name: &str, named_fields: bool, n_fields: uint,
_sz: uint, _align: uint) -> bool {
self.writer.write(name.as_bytes());
if_ok!(self, self.writer.write(name.as_bytes()));
if n_fields != 0 {
if named_fields {
self.writer.write(['{' as u8]);
if_ok!(self, self.writer.write(['{' as u8]));
} else {
self.writer.write(['(' as u8]);
if_ok!(self, self.writer.write(['(' as u8]));
}
}
true
@@ -405,11 +430,11 @@ fn visit_enter_class(&mut self, name: &str, named_fields: bool, n_fields: uint,
fn visit_class_field(&mut self, i: uint, name: &str, named: bool,
_mtbl: uint, inner: *TyDesc) -> bool {
if i != 0 {
self.writer.write(", ".as_bytes());
if_ok!(self, self.writer.write(", ".as_bytes()));
}
if named {
self.writer.write(name.as_bytes());
self.writer.write(": ".as_bytes());
if_ok!(self, self.writer.write(name.as_bytes()));
if_ok!(self, self.writer.write(": ".as_bytes()));
}
self.visit_inner(inner);
true
@@ -419,9 +444,9 @@ fn visit_leave_class(&mut self, _name: &str, named_fields: bool, n_fields: uint,
_sz: uint, _align: uint) -> bool {
if n_fields != 0 {
if named_fields {
self.writer.write(['}' as u8]);
if_ok!(self, self.writer.write(['}' as u8]));
} else {
self.writer.write([')' as u8]);
if_ok!(self, self.writer.write([')' as u8]));
}
}
true
@@ -429,13 +454,13 @@ fn visit_leave_class(&mut self, _name: &str, named_fields: bool, n_fields: uint,
fn visit_enter_tup(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
self.writer.write(['(' as u8]);
if_ok!(self, self.writer.write(['(' as u8]));
true
}
fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool {
if i != 0 {
self.writer.write(", ".as_bytes());
if_ok!(self, self.writer.write(", ".as_bytes()));
}
self.visit_inner(inner);
true
@@ -444,9 +469,9 @@ fn visit_tup_field(&mut self, i: uint, inner: *TyDesc) -> bool {
fn visit_leave_tup(&mut self, _n_fields: uint,
_sz: uint, _align: uint) -> bool {
if _n_fields == 1 {
self.writer.write([',' as u8]);
if_ok!(self, self.writer.write([',' as u8]));
}
self.writer.write([')' as u8]);
if_ok!(self, self.writer.write([')' as u8]));
true
}
@@ -482,9 +507,9 @@ fn visit_enter_enum_variant(&mut self, _variant: uint,
}
if write {
self.writer.write(name.as_bytes());
if_ok!(self, self.writer.write(name.as_bytes()));
if n_fields > 0 {
self.writer.write(['(' as u8]);
if_ok!(self, self.writer.write(['(' as u8]));
}
}
true
@@ -498,7 +523,7 @@ fn visit_enum_variant_field(&mut self,
match self.var_stk[self.var_stk.len() - 1] {
Matched => {
if i != 0 {
self.writer.write(", ".as_bytes());
if_ok!(self, self.writer.write(", ".as_bytes()));
}
if ! self.visit_inner(inner) {
return false;
@@ -516,7 +541,7 @@ fn visit_leave_enum_variant(&mut self, _variant: uint,
match self.var_stk[self.var_stk.len() - 1] {
Matched => {
if n_fields > 0 {
self.writer.write([')' as u8]);
if_ok!(self, self.writer.write([')' as u8]));
}
}
_ => ()
@@ -538,28 +563,29 @@ fn visit_leave_enum(&mut self,
fn visit_enter_fn(&mut self, _purity: uint, _proto: uint,
_n_inputs: uint, _retstyle: uint) -> bool {
self.writer.write("fn(".as_bytes());
if_ok!(self, self.writer.write("fn(".as_bytes()));
true
}
fn visit_fn_input(&mut self, i: uint, _mode: uint, inner: *TyDesc) -> bool {
if i != 0 {
self.writer.write(", ".as_bytes());
if_ok!(self, self.writer.write(", ".as_bytes()));
}
let name = unsafe { (*inner).name };
self.writer.write(name.as_bytes());
if_ok!(self, self.writer.write(name.as_bytes()));
true
}
fn visit_fn_output(&mut self, _retstyle: uint, variadic: bool, inner: *TyDesc) -> bool {
fn visit_fn_output(&mut self, _retstyle: uint, variadic: bool,
inner: *TyDesc) -> bool {
if variadic {
self.writer.write(", ...".as_bytes());
if_ok!(self, self.writer.write(", ...".as_bytes()));
}
self.writer.write(")".as_bytes());
if_ok!(self, self.writer.write(")".as_bytes()));
let name = unsafe { (*inner).name };
if name != "()" {
self.writer.write(" -> ".as_bytes());
self.writer.write(name.as_bytes());
if_ok!(self, self.writer.write(" -> ".as_bytes()));
if_ok!(self, self.writer.write(name.as_bytes()));
}
true
}
@@ -569,7 +595,7 @@ fn visit_leave_fn(&mut self, _purity: uint, _proto: uint,
fn visit_trait(&mut self, name: &str) -> bool {
self.writer.write(name.as_bytes());
if_ok!(self, self.writer.write(name.as_bytes()));
true
}
@@ -582,13 +608,17 @@ fn visit_type(&mut self) -> bool { true }
fn visit_closure_ptr(&mut self, _ck: uint) -> bool { true }
}
pub fn write_repr<T>(writer: &mut io::Writer, object: &T) {
pub fn write_repr<T>(writer: &mut io::Writer, object: &T) -> io::IoResult<()> {
unsafe {
let ptr = ptr::to_unsafe_ptr(object) as *u8;
let tydesc = get_tydesc::<T>();
let u = ReprVisitor(ptr, writer);
let mut v = reflect::MovePtrAdaptor(u);
visit_tydesc(tydesc, &mut v as &mut TyVisitor);
match v.unwrap().last_err {
Some(e) => Err(e),
None => Ok(()),
}
}
}
@@ -597,7 +627,7 @@ pub fn repr_to_str<T>(t: &T) -> ~str {
use io;
let mut result = io::MemWriter::new();
write_repr(&mut result as &mut io::Writer, t);
write_repr(&mut result as &mut io::Writer, t).unwrap();
str::from_utf8_owned(result.unwrap()).unwrap()
}
@@ -615,7 +645,7 @@ fn test_repr() {
fn exact_test<T>(t: &T, e:&str) {
let mut m = io::MemWriter::new();
write_repr(&mut m as &mut io::Writer, t);
write_repr(&mut m as &mut io::Writer, t).unwrap();
let s = str::from_utf8_owned(m.unwrap()).unwrap();
assert_eq!(s.as_slice(), e);
}
+1 -1
View File
@@ -208,7 +208,7 @@ pub fn unwrap_err(self) -> E {
impl<T: fmt::Show, E: fmt::Show> fmt::Show for Result<T, E> {
#[inline]
fn fmt(s: &Result<T, E>, f: &mut fmt::Formatter) {
fn fmt(s: &Result<T, E>, f: &mut fmt::Formatter) -> fmt::Result {
match *s {
Ok(ref t) => write!(f.buf, "Ok({})", *t),
Err(ref e) => write!(f.buf, "Err({})", *e)
+6 -17
View File
@@ -16,13 +16,13 @@
use ops::Drop;
use option::{Option, Some, None};
use path::Path;
use result::{Result, Ok, Err};
use result::{Result, Err};
use rt::task::Task;
use rt::local::Local;
use ai = io::net::addrinfo;
use io;
use io::IoError;
use io::{IoError, IoResult};
use io::net::ip::{IpAddr, SocketAddr};
use io::process::{ProcessConfig, ProcessExit};
use io::signal::Signum;
@@ -116,23 +116,12 @@ pub fn borrow() -> Option<LocalIo> {
return ret;
}
pub fn maybe_raise<T>(f: |io: &mut IoFactory| -> Result<T, IoError>)
-> Option<T>
pub fn maybe_raise<T>(f: |io: &mut IoFactory| -> IoResult<T>)
-> IoResult<T>
{
match LocalIo::borrow() {
None => {
io::io_error::cond.raise(io::standard_error(io::IoUnavailable));
None
}
Some(mut io) => {
match f(io.get()) {
Ok(t) => Some(t),
Err(ioerr) => {
io::io_error::cond.raise(ioerr);
None
}
}
}
None => Err(io::standard_error(io::IoUnavailable)),
Some(mut io) => f(io.get()),
}
}
+3 -2
View File
@@ -119,6 +119,7 @@ pub fn run(~self, f: ||) -> ~Task {
// Run the task main function, then do some cleanup.
f.finally(|| {
#[allow(unused_must_use)]
fn close_outputs() {
let mut task = Local::borrow(None::<Task>);
let logger = task.get().logger.take();
@@ -126,8 +127,8 @@ fn close_outputs() {
let stdout = task.get().stdout.take();
drop(task);
drop(logger); // loggers are responsible for flushing
match stdout { Some(mut w) => w.flush(), None => {} }
match stderr { Some(mut w) => w.flush(), None => {} }
match stdout { Some(mut w) => { w.flush(); }, None => {} }
match stderr { Some(mut w) => { w.flush(); }, None => {} }
}
// First, flush/destroy the user stdout/logger because these
+4 -3
View File
@@ -464,9 +464,10 @@ fn begin_unwind_inner(msg: ~Any, file: &'static str, line: uint) -> ! {
match task.stderr.take() {
Some(mut stderr) => {
Local::put(task);
format_args!(|args| ::fmt::writeln(stderr, args),
"task '{}' failed at '{}', {}:{}",
n, msg_s, file, line);
// FIXME: what to do when the task printing fails?
let _err = format_args!(|args| ::fmt::writeln(stderr, args),
"task '{}' failed at '{}', {}:{}",
n, msg_s, file, line);
task = Local::take();
match util::replace(&mut task.stderr, Some(stderr)) {
+5 -2
View File
@@ -11,10 +11,12 @@
use container::Container;
use fmt;
use from_str::FromStr;
use io::IoResult;
use iter::Iterator;
use libc;
use option::{Some, None, Option};
use os;
use result::Ok;
use str::StrSlice;
use unstable::running_on_valgrind;
use vec::ImmutableVector;
@@ -73,16 +75,17 @@ pub fn dumb_println(args: &fmt::Arguments) {
struct Stderr;
impl io::Writer for Stderr {
fn write(&mut self, data: &[u8]) {
fn write(&mut self, data: &[u8]) -> IoResult<()> {
unsafe {
libc::write(libc::STDERR_FILENO,
data.as_ptr() as *libc::c_void,
data.len() as libc::size_t);
}
Ok(()) // yes, we're lying
}
}
let mut w = Stderr;
fmt::writeln(&mut w as &mut io::Writer, args);
let _ = fmt::writeln(&mut w as &mut io::Writer, args);
}
pub fn abort(msg: &str) -> ! {
+49 -71
View File
@@ -11,6 +11,7 @@
//! Utilities for spawning and managing processes
#[allow(missing_doc)];
#[deny(unused_must_use)];
use comm::SharedChan;
use io::Reader;
@@ -119,7 +120,8 @@ impl Process {
* * options - Options to configure the environment of the process,
* the working directory and the standard IO streams.
*/
pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> Option<Process> {
pub fn new(prog: &str, args: &[~str],
options: ProcessOptions) -> io::IoResult<Process> {
let ProcessOptions { env, dir, in_fd, out_fd, err_fd } = options;
let env = env.as_ref().map(|a| a.as_slice());
let cwd = dir.as_ref().map(|a| a.as_str().unwrap());
@@ -138,10 +140,7 @@ fn rtify(fd: Option<c_int>, input: bool) -> process::StdioContainer {
cwd: cwd,
io: rtio,
};
match process::Process::new(rtconfig) {
Some(inner) => Some(Process { inner: inner }),
None => None
}
process::Process::new(rtconfig).map(|p| Process { inner: p })
}
/// Returns the unique id of the process
@@ -224,19 +223,17 @@ pub fn finish_with_output(&mut self) -> ProcessOutput {
let ch_clone = ch.clone();
spawn(proc() {
let _guard = io::ignore_io_error();
let mut error = error;
match error {
Some(ref mut e) => ch.send((2, e.read_to_end())),
None => ch.send((2, ~[]))
None => ch.send((2, Ok(~[])))
}
});
spawn(proc() {
let _guard = io::ignore_io_error();
let mut output = output;
match output {
Some(ref mut e) => ch_clone.send((1, e.read_to_end())),
None => ch_clone.send((1, ~[]))
None => ch_clone.send((1, Ok(~[])))
}
});
@@ -251,8 +248,8 @@ pub fn finish_with_output(&mut self) -> ProcessOutput {
};
return ProcessOutput {status: status,
output: outs,
error: errs};
output: outs.ok().unwrap_or(~[]),
error: errs.ok().unwrap_or(~[]) };
}
/**
@@ -262,9 +259,10 @@ pub fn finish_with_output(&mut self) -> ProcessOutput {
* On Posix OSs SIGTERM will be sent to the process. On Win32
* TerminateProcess(..) will be called.
*/
pub fn destroy(&mut self) {
self.inner.signal(io::process::PleaseExitSignal);
pub fn destroy(&mut self) -> io::IoResult<()> {
let ret = self.inner.signal(io::process::PleaseExitSignal);
self.finish();
return ret;
}
/**
@@ -274,9 +272,12 @@ pub fn destroy(&mut self) {
* On Posix OSs SIGKILL will be sent to the process. On Win32
* TerminateProcess(..) will be called.
*/
pub fn force_destroy(&mut self) {
self.inner.signal(io::process::MustDieSignal);
pub fn force_destroy(&mut self) -> io::IoResult<()> {
// This should never fail because we own the process
let ret = self.inner.signal(io::process::MustDieSignal);
self.finish();
return ret;
}
}
@@ -293,18 +294,14 @@ pub fn force_destroy(&mut self) {
*
* The process's exit code, or None if the child process could not be started
*/
pub fn process_status(prog: &str, args: &[~str]) -> Option<ProcessExit> {
let mut opt_prog = Process::new(prog, args, ProcessOptions {
pub fn process_status(prog: &str, args: &[~str]) -> io::IoResult<ProcessExit> {
Process::new(prog, args, ProcessOptions {
env: None,
dir: None,
in_fd: Some(unsafe { libc::dup(libc::STDIN_FILENO) }),
out_fd: Some(unsafe { libc::dup(libc::STDOUT_FILENO) }),
err_fd: Some(unsafe { libc::dup(libc::STDERR_FILENO) })
});
match opt_prog {
Some(ref mut prog) => Some(prog.finish()),
None => None
}
}).map(|mut p| p.finish())
}
/**
@@ -320,12 +317,10 @@ pub fn process_status(prog: &str, args: &[~str]) -> Option<ProcessExit> {
* The process's stdout/stderr output and exit code, or None if the child process could not be
* started.
*/
pub fn process_output(prog: &str, args: &[~str]) -> Option<ProcessOutput> {
let mut opt_prog = Process::new(prog, args, ProcessOptions::new());
match opt_prog {
Some(ref mut prog) => Some(prog.finish_with_output()),
None => None
}
pub fn process_output(prog: &str, args: &[~str]) -> io::IoResult<ProcessOutput> {
Process::new(prog, args, ProcessOptions::new()).map(|mut p| {
p.finish_with_output()
})
}
#[cfg(test)]
@@ -337,33 +332,25 @@ mod tests {
use task::spawn;
use unstable::running_on_valgrind;
use io::pipe::PipeStream;
use io::{io_error, FileNotFound};
use io::{FileNotFound};
use libc::c_int;
#[test]
#[cfg(not(target_os="android"))] // FIXME(#10380)
fn test_process_status() {
let mut status = run::process_status("false", []).expect("failed to exec `false`");
let mut status = run::process_status("false", []).unwrap();
assert!(status.matches_exit_status(1));
status = run::process_status("true", []).expect("failed to exec `true`");
status = run::process_status("true", []).unwrap();
assert!(status.success());
}
#[test]
fn test_process_output_fail_to_start() {
// If the executable does not exist, then the io_error condition should be raised with
// IoErrorKind FileNotFound.
let mut trapped_io_error = false;
let opt_outp = io_error::cond.trap(|e| {
trapped_io_error = true;
assert_eq!(e.kind, FileNotFound);
}).inside(|| -> Option<run::ProcessOutput> {
run::process_output("/no-binary-by-this-name-should-exist", [])
});
assert!(trapped_io_error);
assert!(opt_outp.is_none());
match run::process_output("/no-binary-by-this-name-should-exist", []) {
Err(e) => assert_eq!(e.kind, FileNotFound),
Ok(..) => fail!()
}
}
#[test]
@@ -371,7 +358,7 @@ fn test_process_output_fail_to_start() {
fn test_process_output_output() {
let run::ProcessOutput {status, output, error}
= run::process_output("echo", [~"hello"]).expect("failed to exec `echo`");
= run::process_output("echo", [~"hello"]).unwrap();
let output_str = str::from_utf8_owned(output).unwrap();
assert!(status.success());
@@ -387,7 +374,7 @@ fn test_process_output_output() {
fn test_process_output_error() {
let run::ProcessOutput {status, output, error}
= run::process_output("mkdir", [~"."]).expect("failed to exec `mkdir`");
= run::process_output("mkdir", [~"."]).unwrap();
assert!(status.matches_exit_status(1));
assert_eq!(output, ~[]);
@@ -408,7 +395,7 @@ fn test_pipes() {
in_fd: Some(pipe_in.input),
out_fd: Some(pipe_out.out),
err_fd: Some(pipe_err.out)
}).expect("failed to exec `cat`");
}).unwrap();
os::close(pipe_in.input as int);
os::close(pipe_out.out as int);
@@ -426,27 +413,18 @@ fn test_pipes() {
fn writeclose(fd: c_int, s: &str) {
let mut writer = PipeStream::open(fd);
writer.write(s.as_bytes());
writer.write(s.as_bytes()).unwrap();
}
fn readclose(fd: c_int) -> ~str {
let mut res = ~[];
let mut reader = PipeStream::open(fd);
let mut buf = [0, ..1024];
loop {
match reader.read(buf) {
Some(n) => { res.push_all(buf.slice_to(n)); }
None => break
}
}
str::from_utf8_owned(res).unwrap()
PipeStream::open(fd).read_to_str().unwrap()
}
#[test]
#[cfg(not(target_os="android"))] // FIXME(#10380)
fn test_finish_once() {
let mut prog = run::Process::new("false", [], run::ProcessOptions::new())
.expect("failed to exec `false`");
.unwrap();
assert!(prog.finish().matches_exit_status(1));
}
@@ -454,7 +432,7 @@ fn test_finish_once() {
#[cfg(not(target_os="android"))] // FIXME(#10380)
fn test_finish_twice() {
let mut prog = run::Process::new("false", [], run::ProcessOptions::new())
.expect("failed to exec `false`");
.unwrap();
assert!(prog.finish().matches_exit_status(1));
assert!(prog.finish().matches_exit_status(1));
}
@@ -464,7 +442,7 @@ fn test_finish_twice() {
fn test_finish_with_output_once() {
let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new())
.expect("failed to exec `echo`");
.unwrap();
let run::ProcessOutput {status, output, error}
= prog.finish_with_output();
let output_str = str::from_utf8_owned(output).unwrap();
@@ -482,7 +460,7 @@ fn test_finish_with_output_once() {
fn test_finish_with_output_twice() {
let mut prog = run::Process::new("echo", [~"hello"], run::ProcessOptions::new())
.expect("failed to exec `echo`");
.unwrap();
let run::ProcessOutput {status, output, error}
= prog.finish_with_output();
@@ -511,14 +489,14 @@ fn run_pwd(dir: Option<&Path>) -> run::Process {
run::Process::new("pwd", [], run::ProcessOptions {
dir: dir,
.. run::ProcessOptions::new()
}).expect("failed to exec `pwd`")
}).unwrap()
}
#[cfg(unix,target_os="android")]
fn run_pwd(dir: Option<&Path>) -> run::Process {
run::Process::new("/system/bin/sh", [~"-c",~"pwd"], run::ProcessOptions {
dir: dir,
.. run::ProcessOptions::new()
}).expect("failed to exec `/system/bin/sh`")
}).unwrap()
}
#[cfg(windows)]
@@ -526,7 +504,7 @@ fn run_pwd(dir: Option<&Path>) -> run::Process {
run::Process::new("cmd", [~"/c", ~"cd"], run::ProcessOptions {
dir: dir,
.. run::ProcessOptions::new()
}).expect("failed to run `cmd`")
}).unwrap()
}
#[test]
@@ -537,8 +515,8 @@ fn test_keep_current_working_dir() {
let parent_dir = os::getcwd();
let child_dir = Path::new(output.trim());
let parent_stat = parent_dir.stat();
let child_stat = child_dir.stat();
let parent_stat = parent_dir.stat().unwrap();
let child_stat = child_dir.stat().unwrap();
assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
@@ -554,8 +532,8 @@ fn test_change_working_directory() {
let output = str::from_utf8_owned(prog.finish_with_output().output).unwrap();
let child_dir = Path::new(output.trim());
let parent_stat = parent_dir.stat();
let child_stat = child_dir.stat();
let parent_stat = parent_dir.stat().unwrap();
let child_stat = child_dir.stat().unwrap();
assert_eq!(parent_stat.unstable.device, child_stat.unstable.device);
assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode);
@@ -566,14 +544,14 @@ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
run::Process::new("env", [], run::ProcessOptions {
env: env,
.. run::ProcessOptions::new()
}).expect("failed to exec `env`")
}).unwrap()
}
#[cfg(unix,target_os="android")]
fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
run::Process::new("/system/bin/sh", [~"-c",~"set"], run::ProcessOptions {
env: env,
.. run::ProcessOptions::new()
}).expect("failed to exec `/system/bin/sh`")
}).unwrap()
}
#[cfg(windows)]
@@ -581,7 +559,7 @@ fn run_env(env: Option<~[(~str, ~str)]>) -> run::Process {
run::Process::new("cmd", [~"/c", ~"set"], run::ProcessOptions {
env: env,
.. run::ProcessOptions::new()
}).expect("failed to run `cmd`")
}).unwrap()
}
#[test]
+1 -1
View File
@@ -541,7 +541,7 @@ fn test_avoid_copying_the_body_task_spawn() {
#[test]
fn test_avoid_copying_the_body_try() {
avoid_copying_the_body(|f| {
try(proc() {
let _ = try(proc() {
f()
});
})
+1 -1
View File
@@ -349,7 +349,7 @@ fn to_bytes(&self, lsb0: bool) -> ~[u8] {
let mut m = ::io::MemWriter::new();
self.iter_bytes(lsb0, |bytes| {
m.write(bytes);
m.write(bytes).unwrap();
true
});
m.unwrap()
+1 -1
View File
@@ -200,7 +200,7 @@ fn exclusive_new_poison() {
// accesses will also fail.
let x = Exclusive::new(1);
let x2 = x.clone();
task::try(proc() {
let _ = task::try(proc() {
x2.with(|one| assert_eq!(*one, 2))
});
x.with(|one| assert_eq!(*one, 1));
+64 -48
View File
@@ -189,58 +189,61 @@ fn color(self) -> term::color::Color {
}
}
fn print_maybe_styled(msg: &str, color: term::attr::Attr) {
local_data_key!(tls_terminal: ~Option<term::Terminal<StdWriter>>)
fn print_maybe_styled(msg: &str, color: term::attr::Attr) -> io::IoResult<()> {
local_data_key!(tls_terminal: Option<term::Terminal<StdWriter>>)
fn is_stderr_screen() -> bool {
use std::libc;
unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
}
fn write_pretty<T: Writer>(term: &mut term::Terminal<T>, s: &str, c: term::attr::Attr) {
term.attr(c);
term.write(s.as_bytes());
term.reset();
fn write_pretty<T: Writer>(term: &mut term::Terminal<T>, s: &str,
c: term::attr::Attr) -> io::IoResult<()> {
if_ok!(term.attr(c));
if_ok!(term.write(s.as_bytes()));
if_ok!(term.reset());
Ok(())
}
if is_stderr_screen() {
local_data::get_mut(tls_terminal, |term| {
match term {
Some(term) => {
match **term {
match *term {
Some(ref mut term) => write_pretty(term, msg, color),
None => io::stderr().write(msg.as_bytes())
}
}
None => {
let t = ~match term::Terminal::new(io::stderr()) {
let (t, ret) = match term::Terminal::new(io::stderr()) {
Ok(mut term) => {
write_pretty(&mut term, msg, color);
Some(term)
let r = write_pretty(&mut term, msg, color);
(Some(term), r)
}
Err(_) => {
io::stderr().write(msg.as_bytes());
None
(None, io::stderr().write(msg.as_bytes()))
}
};
local_data::set(tls_terminal, t);
ret
}
}
});
})
} else {
io::stderr().write(msg.as_bytes());
io::stderr().write(msg.as_bytes())
}
}
fn print_diagnostic(topic: &str, lvl: Level, msg: &str) {
let mut stderr = io::stderr();
fn print_diagnostic(topic: &str, lvl: Level, msg: &str) -> io::IoResult<()> {
if !topic.is_empty() {
write!(&mut stderr as &mut io::Writer, "{} ", topic);
let mut stderr = io::stderr();
if_ok!(write!(&mut stderr as &mut io::Writer, "{} ", topic));
}
print_maybe_styled(format!("{}: ", lvl.to_str()),
term::attr::ForegroundColor(lvl.color()));
print_maybe_styled(format!("{}\n", msg), term::attr::Bold);
if_ok!(print_maybe_styled(format!("{}: ", lvl.to_str()),
term::attr::ForegroundColor(lvl.color())));
if_ok!(print_maybe_styled(format!("{}\n", msg), term::attr::Bold));
Ok(())
}
pub struct DefaultEmitter;
@@ -250,20 +253,28 @@ fn emit(&self,
cmsp: Option<(&codemap::CodeMap, Span)>,
msg: &str,
lvl: Level) {
match cmsp {
let error = match cmsp {
Some((cm, sp)) => emit(cm, sp, msg, lvl, false),
None => print_diagnostic("", lvl, msg),
};
match error {
Ok(()) => {}
Err(e) => fail!("failed to print diagnostics: {}", e),
}
}
fn custom_emit(&self, cm: &codemap::CodeMap,
sp: Span, msg: &str, lvl: Level) {
emit(cm, sp, msg, lvl, true);
match emit(cm, sp, msg, lvl, true) {
Ok(()) => {}
Err(e) => fail!("failed to print diagnostics: {}", e),
}
}
}
fn emit(cm: &codemap::CodeMap, sp: Span,
msg: &str, lvl: Level, custom: bool) {
msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> {
let ss = cm.span_to_str(sp);
let lines = cm.span_to_lines(sp);
if custom {
@@ -272,19 +283,19 @@ fn emit(cm: &codemap::CodeMap, sp: Span,
// the span)
let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info};
let ses = cm.span_to_str(span_end);
print_diagnostic(ses, lvl, msg);
custom_highlight_lines(cm, sp, lvl, lines);
if_ok!(print_diagnostic(ses, lvl, msg));
if_ok!(custom_highlight_lines(cm, sp, lvl, lines));
} else {
print_diagnostic(ss, lvl, msg);
highlight_lines(cm, sp, lvl, lines);
if_ok!(print_diagnostic(ss, lvl, msg));
if_ok!(highlight_lines(cm, sp, lvl, lines));
}
print_macro_backtrace(cm, sp);
print_macro_backtrace(cm, sp)
}
fn highlight_lines(cm: &codemap::CodeMap,
sp: Span,
lvl: Level,
lines: &codemap::FileLines) {
lines: &codemap::FileLines) -> io::IoResult<()> {
let fm = lines.file;
let mut err = io::stderr();
let err = &mut err as &mut io::Writer;
@@ -297,12 +308,13 @@ fn highlight_lines(cm: &codemap::CodeMap,
}
// Print the offending lines
for line in display_lines.iter() {
write!(err, "{}:{} {}\n", fm.name, *line + 1, fm.get_line(*line as int));
if_ok!(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);
write!(err, "{0:1$}...\n", "", s.len());
if_ok!(write!(err, "{0:1$}...\n", "", s.len()));
}
// FIXME (#3260)
@@ -334,7 +346,7 @@ fn highlight_lines(cm: &codemap::CodeMap,
_ => s.push_char(' '),
};
}
write!(err, "{}", s);
if_ok!(write!(err, "{}", s));
let mut s = ~"^";
let hi = cm.lookup_char_pos(sp.hi);
if hi.col != lo.col {
@@ -342,8 +354,10 @@ fn highlight_lines(cm: &codemap::CodeMap,
let num_squigglies = hi.col.to_uint()-lo.col.to_uint()-1u;
for _ in range(0, num_squigglies) { s.push_char('~'); }
}
print_maybe_styled(s + "\n", term::attr::ForegroundColor(lvl.color()));
if_ok!(print_maybe_styled(s + "\n",
term::attr::ForegroundColor(lvl.color())));
}
Ok(())
}
// Here are the differences between this and the normal `highlight_lines`:
@@ -355,23 +369,23 @@ fn highlight_lines(cm: &codemap::CodeMap,
fn custom_highlight_lines(cm: &codemap::CodeMap,
sp: Span,
lvl: Level,
lines: &codemap::FileLines) {
lines: &codemap::FileLines) -> io::IoResult<()> {
let fm = lines.file;
let mut err = io::stderr();
let err = &mut err as &mut io::Writer;
let lines = lines.lines.as_slice();
if lines.len() > MAX_LINES {
write!(err, "{}:{} {}\n", fm.name,
lines[0] + 1, fm.get_line(lines[0] as int));
write!(err, "...\n");
if_ok!(write!(err, "{}:{} {}\n", fm.name,
lines[0] + 1, fm.get_line(lines[0] as int)));
if_ok!(write!(err, "...\n"));
let last_line = lines[lines.len()-1];
write!(err, "{}:{} {}\n", fm.name,
last_line + 1, fm.get_line(last_line as int));
if_ok!(write!(err, "{}:{} {}\n", fm.name,
last_line + 1, fm.get_line(last_line as int)));
} else {
for line in lines.iter() {
write!(err, "{}:{} {}\n", fm.name,
*line + 1, fm.get_line(*line as int));
if_ok!(write!(err, "{}:{} {}\n", fm.name,
*line + 1, fm.get_line(*line as int)));
}
}
let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1]+1);
@@ -381,22 +395,24 @@ fn custom_highlight_lines(cm: &codemap::CodeMap,
let mut s = ~"";
for _ in range(0, skip) { s.push_char(' '); }
s.push_char('^');
print_maybe_styled(s + "\n", term::attr::ForegroundColor(lvl.color()));
print_maybe_styled(s + "\n", term::attr::ForegroundColor(lvl.color()))
}
fn print_macro_backtrace(cm: &codemap::CodeMap, sp: Span) {
fn print_macro_backtrace(cm: &codemap::CodeMap, sp: Span) -> io::IoResult<()> {
for ei in sp.expn_info.iter() {
let ss = ei.callee.span.as_ref().map_or(~"", |span| cm.span_to_str(*span));
let (pre, post) = match ei.callee.format {
codemap::MacroAttribute => ("#[", "]"),
codemap::MacroBang => ("", "!")
};
print_diagnostic(ss, Note,
format!("in expansion of {}{}{}", pre, ei.callee.name, post));
if_ok!(print_diagnostic(ss, Note,
format!("in expansion of {}{}{}", pre,
ei.callee.name, post)));
let ss = cm.span_to_str(ei.call_site);
print_diagnostic(ss, Note, "expansion site");
print_macro_backtrace(cm, ei.call_site);
if_ok!(print_diagnostic(ss, Note, "expansion site"));
if_ok!(print_macro_backtrace(cm, ei.call_site));
}
Ok(())
}
pub fn expect<T:Clone>(diag: @SpanHandler, opt: Option<T>, msg: || -> ~str)

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