// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. // // ignore-lexer-test FIXME #15883 // FIXME: cover these topics: // path, reader, writer, stream, raii (close not needed), // stdio, print!, println!, file access, process spawning, // error handling //! I/O, including files, networking, timers, and processes //! //! `std::io` provides Rust's basic I/O types, //! for reading and writing to files, TCP, UDP, //! and other types of sockets and pipes, //! manipulating the file system, spawning processes. //! //! # Examples //! //! Some examples of obvious things you might want to do //! //! * Read lines from stdin //! //! ```rust //! use std::io; //! //! for line in io::stdin().lock().lines() { //! print!("{}", line.unwrap()); //! } //! ``` //! //! * Read a complete file //! //! ```rust //! use std::io::File; //! //! 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 mut file = File::create(&Path::new("message.txt")); //! file.write(b"hello, file!\n"); //! # drop(file); //! # ::std::io::fs::unlink(&Path::new("message.txt")); //! ``` //! //! * Iterate over the lines of a file //! //! ```rust,no_run //! use std::io::BufferedReader; //! use std::io::File; //! //! let path = Path::new("message.txt"); //! let mut file = BufferedReader::new(File::open(&path)); //! for line in file.lines() { //! print!("{}", line.unwrap()); //! } //! ``` //! //! * Pull the lines of a file into a vector of strings //! //! ```rust,no_run //! use std::io::BufferedReader; //! use std::io::File; //! //! let path = Path::new("message.txt"); //! let mut file = BufferedReader::new(File::open(&path)); //! let lines: Vec = file.lines().map(|x| x.unwrap()).collect(); //! ``` //! //! * Make a simple TCP client connection and request //! //! ```rust //! # #![allow(unused_must_use)] //! use std::io::TcpStream; //! //! # // connection doesn't fail if a server is running on 8080 //! # // locally, we still want to be type checking this code, so lets //! # // just stop it running (#11576) //! # if false { //! let mut socket = TcpStream::connect("127.0.0.1:8080").unwrap(); //! socket.write(b"GET / HTTP/1.0\n\n"); //! let response = socket.read_to_end(); //! # } //! ``` //! //! * Make a simple TCP server //! //! ```rust //! # fn main() { } //! # fn foo() { //! # #![allow(dead_code)] //! use std::io::{TcpListener, TcpStream}; //! use std::io::{Acceptor, Listener}; //! use std::thread::Thread; //! //! let listener = TcpListener::bind("127.0.0.1:80"); //! //! // bind the listener to the specified address //! let mut acceptor = listener.listen(); //! //! fn handle_client(mut stream: TcpStream) { //! // ... //! # &mut stream; // silence unused mutability/variable warning //! } //! // accept connections and process them, spawning a new tasks for each one //! for stream in acceptor.incoming() { //! match stream { //! Err(e) => { /* connection failed */ } //! Ok(stream) => Thread::spawn(move|| { //! // connection succeeded //! handle_client(stream) //! }).detach() //! } //! } //! //! // close the socket server //! drop(acceptor); //! # } //! ``` //! //! //! # Error Handling //! //! I/O is an area where nearly every operation can result in unexpected //! 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: //! //! * All I/O operations return `IoResult` which is equivalent to //! `Result`. The `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. This is because `Result` has the //! `#[must_use]` attribute. //! * Common traits are implemented for `IoResult`, e.g. //! `impl Reader for IoResult`, 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(b"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 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; //! //! match File::create(&Path::new("diary.txt")).write(b"Met a girl.\n") { //! Ok(()) => (), // succeeded //! Err(e) => println!("failed to write to my diary: {}", e), //! } //! //! # ::std::io::fs::unlink(&Path::new("diary.txt")); //! ``` //! //! 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`. 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` 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. //! //! ## `try!` //! //! Explicit pattern matching on `IoResult`s can get quite verbose, especially //! when performing many I/O operations. Some examples (like those above) are //! alleviated with extra methods implemented on `IoResult`, but others have more //! complex interdependencies among each I/O operation. //! //! The `try!` macro from `std::macros` is provided as a method of early-return //! inside `Result`-returning functions. It expands to an early-return on `Err` //! and otherwise unwraps the contained `Ok` value. //! //! If you wanted to read several `u32`s from a file and return their product: //! //! ```rust //! use std::io::{File, IoResult}; //! //! fn file_product(p: &Path) -> IoResult { //! let mut f = File::open(p); //! let x1 = try!(f.read_le_u32()); //! let x2 = try!(f.read_le_u32()); //! //! Ok(x1 * x2) //! } //! //! match file_product(&Path::new("numbers.bin")) { //! Ok(x) => println!("{}", x), //! Err(e) => println!("Failed to read numbers!") //! } //! ``` //! //! With `try!` in `file_product`, each `read_le_u32` need not be directly //! concerned with error handling; instead its caller is responsible for //! responding to errors that may occur while attempting to read the numbers. #![experimental] #![deny(unused_must_use)] pub use self::SeekStyle::*; pub use self::FileMode::*; pub use self::FileAccess::*; pub use self::IoErrorKind::*; use char::Char; use clone::Clone; use default::Default; use error::{FromError, Error}; use fmt; use int; use iter::{Iterator, IteratorExt}; use mem::transmute; use ops::{BitOr, BitXor, BitAnd, Sub, Not, FnOnce}; use option::Option; use option::Option::{Some, None}; use os; use boxed::Box; use result::Result; use result::Result::{Ok, Err}; use sys; use slice::SliceExt; use str::StrExt; use str; use string::String; use uint; use unicode; use unicode::char::UnicodeChar; use vec::Vec; // Reexports pub use self::stdio::stdin; pub use self::stdio::stdout; pub use self::stdio::stderr; pub use self::stdio::print; pub use self::stdio::println; pub use self::fs::File; pub use self::timer::Timer; pub use self::net::ip::IpAddr; pub use self::net::tcp::TcpListener; pub use self::net::tcp::TcpStream; pub use self::net::udp::UdpStream; pub use self::pipe::PipeStream; pub use self::process::{Process, Command}; pub use self::tempfile::TempDir; pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter}; pub use self::buffered::{BufferedReader, BufferedWriter, BufferedStream, LineBufferedWriter}; pub use self::comm_adapters::{ChanReader, ChanWriter}; mod buffered; mod comm_adapters; mod mem; mod result; mod tempfile; pub mod extensions; pub mod fs; pub mod net; pub mod pipe; pub mod process; pub mod stdio; pub mod test; pub mod timer; pub mod util; /// The default buffer size for various I/O operations // libuv recommends 64k buffers to maximize throughput // https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA const DEFAULT_BUF_SIZE: uint = 1024 * 64; /// A convenient typedef of the return value of any I/O action. pub type IoResult = Result; /// The type passed to I/O condition handlers to indicate error /// /// # FIXME /// /// Is something like this sufficient? It's kind of archaic #[deriving(PartialEq, Eq, Clone)] pub struct IoError { /// An enumeration which can be matched against for determining the flavor /// of error. pub kind: IoErrorKind, /// A human-readable description about the error pub desc: &'static str, /// Detailed information about this error, not always available pub detail: Option } impl IoError { /// Convert an `errno` value into an `IoError`. /// /// If `detail` is `true`, the `detail` field of the `IoError` /// struct is filled with an allocated string describing the error /// in more detail, retrieved from the operating system. pub fn from_errno(errno: uint, detail: bool) -> IoError { let mut err = sys::decode_error(errno as i32); if detail && err.kind == OtherIoError { err.detail = Some(os::error_string(errno).chars() .map(|c| c.to_lowercase()).collect()) } err } /// Retrieve the last error to occur as a (detailed) IoError. /// /// This uses the OS `errno`, and so there should not be any task /// descheduling or migration (other than that performed by the /// operating system) between the call(s) for which errors are /// being checked and the call of this function. pub fn last_error() -> IoError { IoError::from_errno(os::errno() as uint, true) } } impl fmt::Show for IoError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { IoError { kind: OtherIoError, desc: "unknown error", detail: Some(ref detail) } => write!(fmt, "{}", detail), IoError { detail: None, desc, .. } => write!(fmt, "{}", desc), IoError { detail: Some(ref detail), desc, .. } => write!(fmt, "{} ({})", desc, detail) } } } impl Error for IoError { fn description(&self) -> &str { self.desc } fn detail(&self) -> Option { self.detail.clone() } } impl FromError for Box { fn from_error(err: IoError) -> Box { box err } } /// A list specifying general categories of I/O error. #[deriving(Copy, PartialEq, Eq, Clone, Show)] pub enum IoErrorKind { /// Any I/O error not part of this list. OtherIoError, /// The operation could not complete because end of file was reached. EndOfFile, /// The file was not found. FileNotFound, /// The file permissions disallowed access to this file. PermissionDenied, /// A network connection failed for some reason not specified in this list. ConnectionFailed, /// The network operation failed because the network connection was closed. Closed, /// The connection was refused by the remote server. ConnectionRefused, /// The connection was reset by the remote server. ConnectionReset, /// The connection was aborted (terminated) by the remote server. ConnectionAborted, /// The network operation failed because it was not connected yet. NotConnected, /// The operation failed because a pipe was closed. BrokenPipe, /// A file already existed with that name. PathAlreadyExists, /// No file exists at that location. PathDoesntExist, /// The path did not specify the type of file that this operation required. For example, /// attempting to copy a directory with the `fs::copy()` operation will fail with this error. MismatchedFileTypeForOperation, /// The operation temporarily failed (for example, because a signal was received), and retrying /// may succeed. ResourceUnavailable, /// No I/O functionality is available for this task. IoUnavailable, /// A parameter was incorrect in a way that caused an I/O error not part of this list. InvalidInput, /// The I/O operation's timeout expired, causing it to be canceled. TimedOut, /// This write operation failed to write all of its data. /// /// Normally the write() method on a Writer guarantees that all of its data /// has been written, but some operations may be terminated after only /// partially writing some data. An example of this is a timed out write /// which successfully wrote a known number of bytes, but bailed out after /// doing so. /// /// The payload contained as part of this variant is the number of bytes /// which are known to have been successfully written. ShortWrite(uint), /// The Reader returned 0 bytes from `read()` too many times. NoProgress, } /// A trait that lets you add a `detail` to an IoError easily trait UpdateIoError { /// Returns an IoError with updated description and detail fn update_err(self, desc: &'static str, detail: D) -> Self where D: FnOnce(&IoError) -> String; /// Returns an IoError with updated detail fn update_detail(self, detail: D) -> Self where D: FnOnce(&IoError) -> String; /// Returns an IoError with update description fn update_desc(self, desc: &'static str) -> Self; } impl UpdateIoError for IoResult { fn update_err(self, desc: &'static str, detail: D) -> IoResult where D: FnOnce(&IoError) -> String, { self.map_err(move |mut e| { let detail = detail(&e); e.desc = desc; e.detail = Some(detail); e }) } fn update_detail(self, detail: D) -> IoResult where D: FnOnce(&IoError) -> String, { self.map_err(move |mut e| { e.detail = Some(detail(&e)); e }) } fn update_desc(self, desc: &'static str) -> IoResult { self.map_err(|mut e| { e.desc = desc; e }) } } static NO_PROGRESS_LIMIT: uint = 1000; /// A trait for objects which are byte-oriented streams. Readers are defined by /// one method, `read`. This function will block until data is available, /// filling in the provided buffer with any data read. /// /// Readers are intended to be composable with one another. Many objects /// throughout the I/O and related libraries take and provide types which /// implement the `Reader` trait. pub trait Reader { // 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 may /// be less than the number requested, even 0. Returns `Err` on EOF. /// /// # Error /// /// 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 /// /// # Implementation Note /// /// When implementing this method on a new Reader, you are strongly encouraged /// not to return 0 if you can avoid it. fn read(&mut self, buf: &mut [u8]) -> IoResult; // Convenient helper methods based on the above methods /// Reads at least `min` bytes and places them in `buf`. /// Returns the number of bytes read. /// /// This will continue to call `read` until at least `min` bytes have been /// read. If `read` returns 0 too many times, `NoProgress` will be /// returned. /// /// # Error /// /// If an error occurs at any point, that error is returned, and no further /// bytes are read. fn read_at_least(&mut self, min: uint, buf: &mut [u8]) -> IoResult { if min > buf.len() { return Err(IoError { detail: Some(String::from_str("the buffer is too short")), ..standard_error(InvalidInput) }); } let mut read = 0; while read < min { let mut zeroes = 0; loop { match self.read(buf.slice_from_mut(read)) { Ok(0) => { zeroes += 1; if zeroes >= NO_PROGRESS_LIMIT { return Err(standard_error(NoProgress)); } } Ok(n) => { read += n; break; } err@Err(_) => return err } } } Ok(read) } /// Reads a single byte. Returns `Err` on EOF. fn read_byte(&mut self) -> IoResult { let mut buf = [0]; try!(self.read_at_least(1, &mut buf)); Ok(buf[0]) } /// Reads up to `len` bytes and appends them to a vector. /// Returns the number of bytes read. The number of bytes read may be /// less than the number requested, even 0. Returns Err on EOF. /// /// # Error /// /// If an error occurs during this I/O operation, then it is returned /// as `Err(IoError)`. See `read()` for more details. fn push(&mut self, len: uint, buf: &mut Vec) -> IoResult { let start_len = buf.len(); buf.reserve(len); let n = { let s = unsafe { slice_vec_capacity(buf, start_len, start_len + len) }; try!(self.read(s)) }; unsafe { buf.set_len(start_len + n) }; Ok(n) } /// Reads at least `min` bytes, but no more than `len`, and appends them to /// a vector. /// Returns the number of bytes read. /// /// This will continue to call `read` until at least `min` bytes have been /// read. If `read` returns 0 too many times, `NoProgress` will be /// returned. /// /// # Error /// /// If an error occurs at any point, that error is returned, and no further /// bytes are read. fn push_at_least(&mut self, min: uint, len: uint, buf: &mut Vec) -> IoResult { if min > len { return Err(IoError { detail: Some(String::from_str("the buffer is too short")), ..standard_error(InvalidInput) }); } let start_len = buf.len(); buf.reserve(len); // we can't just use self.read_at_least(min, slice) because we need to push // successful reads onto the vector before any returned errors. let mut read = 0; while read < min { read += { let s = unsafe { slice_vec_capacity(buf, start_len + read, start_len + len) }; try!(self.read_at_least(1, s)) }; unsafe { buf.set_len(start_len + read) }; } Ok(read) } /// Reads exactly `len` bytes and gives you back a new vector of length /// `len` /// /// # Error /// /// Fails with the same conditions as `read`. Additionally returns error /// 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_at_least` or `read` methods. fn read_exact(&mut self, len: uint) -> IoResult> { let mut buf = Vec::with_capacity(len); match self.push_at_least(len, len, &mut buf) { Ok(_) => Ok(buf), Err(e) => Err(e), } } /// Reads all remaining bytes from the stream. /// /// # Error /// /// 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> { let mut buf = Vec::with_capacity(DEFAULT_BUF_SIZE); loop { match self.push_at_least(1, DEFAULT_BUF_SIZE, &mut buf) { Ok(_) => {} Err(ref e) if e.kind == EndOfFile => break, Err(e) => return Err(e) } } 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. /// /// # Error /// /// 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_string(&mut self) -> IoResult { self.read_to_end().and_then(|s| { match String::from_utf8(s) { Ok(s) => Ok(s), Err(_) => Err(standard_error(InvalidInput)), } }) } // Byte conversion helpers /// Reads `n` little-endian unsigned integer bytes. /// /// `n` must be between 1 and 8, inclusive. fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult { assert!(nbytes > 0 && nbytes <= 8); let mut val = 0u64; let mut pos = 0; let mut i = nbytes; while i > 0 { val += (try!(self.read_u8()) as u64) << pos; pos += 8; i -= 1; } 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) -> IoResult { 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) -> IoResult { assert!(nbytes > 0 && nbytes <= 8); let mut val = 0u64; let mut i = nbytes; while i > 0 { i -= 1; val += (try!(self.read_u8()) as u64) << i * 8; } 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) -> IoResult { 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-dependent. fn read_le_uint(&mut self) -> IoResult { self.read_le_uint_n(uint::BYTES).map(|i| i as uint) } /// Reads a little-endian integer. /// /// The number of bytes returned is system-dependent. fn read_le_int(&mut self) -> IoResult { 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-dependent. fn read_be_uint(&mut self) -> IoResult { self.read_be_uint_n(uint::BYTES).map(|i| i as uint) } /// Reads a big-endian integer. /// /// The number of bytes returned is system-dependent. fn read_be_int(&mut self) -> IoResult { 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) -> IoResult { self.read_be_uint_n(8) } /// Reads a big-endian `u32`. /// /// `u32`s are 4 bytes long. fn read_be_u32(&mut self) -> IoResult { 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) -> IoResult { 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) -> IoResult { self.read_be_int_n(8) } /// Reads a big-endian `i32`. /// /// `i32`s are 4 bytes long. fn read_be_i32(&mut self) -> IoResult { 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) -> IoResult { 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) -> IoResult { self.read_be_u64().map(|i| unsafe { transmute::(i) }) } /// Reads a big-endian `f32`. /// /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. fn read_be_f32(&mut self) -> IoResult { self.read_be_u32().map(|i| unsafe { transmute::(i) }) } /// Reads a little-endian `u64`. /// /// `u64`s are 8 bytes long. fn read_le_u64(&mut self) -> IoResult { self.read_le_uint_n(8) } /// Reads a little-endian `u32`. /// /// `u32`s are 4 bytes long. fn read_le_u32(&mut self) -> IoResult { 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) -> IoResult { 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) -> IoResult { self.read_le_int_n(8) } /// Reads a little-endian `i32`. /// /// `i32`s are 4 bytes long. fn read_le_i32(&mut self) -> IoResult { 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) -> IoResult { 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) -> IoResult { self.read_le_u64().map(|i| unsafe { transmute::(i) }) } /// Reads a little-endian `f32`. /// /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. fn read_le_f32(&mut self) -> IoResult { self.read_le_u32().map(|i| unsafe { transmute::(i) }) } /// Read a u8. /// /// `u8`s are 1 byte. fn read_u8(&mut self) -> IoResult { self.read_byte() } /// Read an i8. /// /// `i8`s are 1 byte. fn read_i8(&mut self) -> IoResult { self.read_byte().map(|i| i as i8) } } /// A reader which can be converted to a RefReader. #[deprecated = "use ByRefReader instead"] pub trait AsRefReader { /// Creates a wrapper around a mutable reference to the reader. /// /// This is useful to allow applying adaptors while still /// retaining ownership of the original value. fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self>; } #[allow(deprecated)] impl AsRefReader for T { fn by_ref<'a>(&'a mut self) -> RefReader<'a, T> { RefReader { inner: self } } } /// A reader which can be converted to a RefReader. pub trait ByRefReader { /// Creates a wrapper around a mutable reference to the reader. /// /// This is useful to allow applying adaptors while still /// retaining ownership of the original value. fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self>; } impl ByRefReader for T { fn by_ref<'a>(&'a mut self) -> RefReader<'a, T> { RefReader { inner: self } } } /// A reader which can be converted to bytes. pub trait BytesReader { /// Create an iterator that reads a single byte on /// each iteration, until EOF. /// /// # Error /// /// Any error other than `EndOfFile` that is produced by the underlying Reader /// is returned by the iterator and should be handled by the caller. fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self>; } impl BytesReader for T { fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, T> { extensions::Bytes::new(self) } } impl<'a> Reader for Box { fn read(&mut self, buf: &mut [u8]) -> IoResult { let reader: &mut Reader = &mut **self; reader.read(buf) } } impl<'a> Reader for &'a mut (Reader+'a) { fn read(&mut self, buf: &mut [u8]) -> IoResult { (*self).read(buf) } } /// Returns a slice of `v` between `start` and `end`. /// /// Similar to `slice()` except this function only bounds the slice on the /// capacity of `v`, not the length. /// /// # Panics /// /// Panics when `start` or `end` point outside the capacity of `v`, or when /// `start` > `end`. // Private function here because we aren't sure if we want to expose this as // API yet. If so, it should be a method on Vec. unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec, start: uint, end: uint) -> &'a mut [T] { use raw::Slice; use ptr::PtrExt; assert!(start <= end); assert!(end <= v.capacity()); transmute(Slice { data: v.as_ptr().offset(start as int), len: end - start }) } /// A `RefReader` is a struct implementing `Reader` which contains a reference /// to another reader. This is often useful when composing streams. /// /// # Example /// /// ``` /// # fn main() {} /// # fn process_input(r: R) {} /// # fn foo() { /// use std::io; /// use std::io::ByRefReader; /// use std::io::util::LimitReader; /// /// let mut stream = io::stdin(); /// /// // Only allow the function to process at most one kilobyte of input /// { /// let stream = LimitReader::new(stream.by_ref(), 1024); /// process_input(stream); /// } /// /// // 'stream' is still available for use here /// /// # } /// ``` pub struct RefReader<'a, R:'a> { /// The underlying reader which this is referencing inner: &'a mut R } impl<'a, R: Reader> Reader for RefReader<'a, R> { fn read(&mut self, buf: &mut [u8]) -> IoResult { self.inner.read(buf) } } impl<'a, R: Buffer> Buffer for RefReader<'a, R> { fn fill_buf(&mut self) -> IoResult<&[u8]> { self.inner.fill_buf() } fn consume(&mut self, amt: uint) { self.inner.consume(amt) } } fn extend_sign(val: u64, nbytes: uint) -> i64 { let shift = (8 - nbytes) * 8; (val << shift) as i64 >> shift } /// A trait for objects which are byte-oriented streams. Writers are defined by /// one method, `write`. This function will block until the provided buffer of /// bytes has been entirely written, and it will return any failures which occur. /// /// Another commonly overridden method is the `flush` method for writers such as /// buffered writers. /// /// Writers are intended to be composable with one another. Many objects /// throughout the I/O and related libraries take and provide types which /// implement the `Writer` trait. pub trait Writer { /// Write the entirety of a given buffer /// /// # Errors /// /// 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) -> IoResult<()> { Ok(()) } /// Writes a formatted string into this writer, returning any error /// encountered. /// /// This method is primarily used to interface with the `format_args!` /// macro, but it is rare that this should explicitly be called. The /// `write!` macro should be favored to invoke this method instead. /// /// # Errors /// /// This function will return any I/O error reported while formatting. fn write_fmt(&mut self, fmt: fmt::Arguments) -> IoResult<()> { // Create a shim which translates a Writer to a FormatWriter and saves // off I/O errors. instead of discarding them struct Adaptor<'a, T:'a> { inner: &'a mut T, error: IoResult<()>, } impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> { fn write(&mut self, bytes: &[u8]) -> fmt::Result { match self.inner.write(bytes) { Ok(()) => Ok(()), Err(e) => { self.error = Err(e); Err(fmt::Error) } } } } let mut output = Adaptor { inner: self, error: Ok(()) }; match fmt::write(&mut output, fmt) { Ok(()) => Ok(()), Err(..) => output.error } } /// Write a rust string into this sink. /// /// The bytes written will be the UTF-8 encoded version of the input string. /// 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. #[inline] 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`) /// byte afterwards. Note that the writing of the newline is *not* atomic in /// the sense that the call to `write` is invoked twice (once with the /// string and once with a newline character). /// /// If other encodings or line ending flavors are desired, it is recommended /// that the `write` method is used specifically instead. #[inline] fn write_line(&mut self, s: &str) -> IoResult<()> { self.write_str(s).and_then(|()| self.write(&[b'\n'])) } /// Write a single char, encoded as UTF-8. #[inline] fn write_char(&mut self, c: char) -> IoResult<()> { let mut buf = [0u8; 4]; let n = c.encode_utf8(buf.as_mut_slice()).unwrap_or(0); self.write(buf[..n]) } /// Write the result of passing n through `int::to_str_bytes`. #[inline] fn write_int(&mut self, n: int) -> IoResult<()> { write!(self, "{}", n) } /// Write the result of passing n through `uint::to_str_bytes`. #[inline] fn write_uint(&mut self, n: uint) -> IoResult<()> { write!(self, "{}", n) } /// Write a little-endian uint (number of bytes depends on system). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] fn write_be_f64(&mut self, f: f64) -> IoResult<()> { unsafe { self.write_be_u64(transmute(f)) } } /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). #[inline] fn write_be_f32(&mut self, f: f32) -> IoResult<()> { unsafe { self.write_be_u32(transmute(f)) } } /// Write a little-endian u64 (8 bytes). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] 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). #[inline] fn write_le_f64(&mut self, f: f64) -> IoResult<()> { unsafe { self.write_le_u64(transmute(f)) } } /// Write a little-endian IEEE754 single-precision floating-point /// (4 bytes). #[inline] fn write_le_f32(&mut self, f: f32) -> IoResult<()> { unsafe { self.write_le_u32(transmute(f)) } } /// Write a u8 (1 byte). #[inline] fn write_u8(&mut self, n: u8) -> IoResult<()> { self.write(&[n]) } /// Write an i8 (1 byte). #[inline] fn write_i8(&mut self, n: i8) -> IoResult<()> { self.write(&[n as u8]) } } /// A writer which can be converted to a RefWriter. #[deprecated = "use ByRefWriter instead"] pub trait AsRefWriter { /// Creates a wrapper around a mutable reference to the writer. /// /// This is useful to allow applying wrappers while still /// retaining ownership of the original value. #[inline] fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self>; } #[allow(deprecated)] impl AsRefWriter for T { fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { RefWriter { inner: self } } } /// A writer which can be converted to a RefWriter. pub trait ByRefWriter { /// Creates a wrapper around a mutable reference to the writer. /// /// This is useful to allow applying wrappers while still /// retaining ownership of the original value. #[inline] fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self>; } impl ByRefWriter for T { fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { RefWriter { inner: self } } } impl<'a> Writer for Box { #[inline] fn write(&mut self, buf: &[u8]) -> IoResult<()> { (&mut **self).write(buf) } #[inline] fn flush(&mut self) -> IoResult<()> { (&mut **self).flush() } } impl<'a> Writer for &'a mut (Writer+'a) { #[inline] fn write(&mut self, buf: &[u8]) -> IoResult<()> { (**self).write(buf) } #[inline] fn flush(&mut self) -> IoResult<()> { (**self).flush() } } /// A `RefWriter` is a struct implementing `Writer` which contains a reference /// to another writer. This is often useful when composing streams. /// /// # Example /// /// ``` /// # fn main() {} /// # fn process_input(r: R) {} /// # fn foo () { /// use std::io::util::TeeReader; /// use std::io::{stdin, ByRefWriter}; /// /// let mut output = Vec::new(); /// /// { /// // Don't give ownership of 'output' to the 'tee'. Instead we keep a /// // handle to it in the outer scope /// let mut tee = TeeReader::new(stdin(), output.by_ref()); /// process_input(tee); /// } /// /// println!("input processed: {}", output); /// # } /// ``` pub struct RefWriter<'a, W:'a> { /// The underlying writer which this is referencing inner: &'a mut W } impl<'a, W: Writer> Writer for RefWriter<'a, W> { #[inline] fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write(buf) } #[inline] fn flush(&mut self) -> IoResult<()> { self.inner.flush() } } /// A Stream is a readable and a writable object. Data written is typically /// received by the object which reads receive data from. pub trait Stream: Reader + Writer { } impl Stream for T {} /// An iterator that reads a line on each iteration, /// until `.read_line()` encounters `EndOfFile`. /// /// # Notes about the Iteration Protocol /// /// The `Lines` may yield `None` and thus terminate /// an iteration, but continue to yield elements if iteration /// is attempted again. /// /// # Error /// /// Any error other than `EndOfFile` that is produced by the underlying Reader /// is returned by the iterator and should be handled by the caller. pub struct Lines<'r, T:'r> { buffer: &'r mut T, } impl<'r, T: Buffer> Iterator> for Lines<'r, T> { fn next(&mut self) -> Option> { match self.buffer.read_line() { Ok(x) => Some(Ok(x)), Err(IoError { kind: EndOfFile, ..}) => None, Err(y) => Some(Err(y)) } } } /// An iterator that reads a utf8-encoded character on each iteration, /// until `.read_char()` encounters `EndOfFile`. /// /// # Notes about the Iteration Protocol /// /// The `Chars` may yield `None` and thus terminate /// an iteration, but continue to yield elements if iteration /// is attempted again. /// /// # Error /// /// Any error other than `EndOfFile` that is produced by the underlying Reader /// is returned by the iterator and should be handled by the caller. pub struct Chars<'r, T:'r> { buffer: &'r mut T } impl<'r, T: Buffer> Iterator> for Chars<'r, T> { fn next(&mut self) -> Option> { match self.buffer.read_char() { Ok(x) => Some(Ok(x)), Err(IoError { kind: EndOfFile, ..}) => None, Err(y) => Some(Err(y)) } } } /// A Buffer is a type of reader which has some form of internal buffering to /// allow certain kinds of reading operations to be more optimized than others. /// This type extends the `Reader` trait with a few methods that are not /// possible to reasonably implement with purely a read interface. pub trait Buffer: Reader { /// Fills the internal buffer of this object, returning the buffer contents. /// Note that none of the contents will be "read" in the sense that later /// calling `read` may return the same contents. /// /// The `consume` function must be called with the number of bytes that are /// consumed from this buffer returned to ensure that the bytes are never /// returned twice. /// /// # Error /// /// 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_buf<'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 `read`. fn consume(&mut self, amt: uint); /// Reads the next line of input, interpreted as a sequence of UTF-8 /// encoded Unicode codepoints. If a newline is encountered, then the /// newline is contained in the returned string. /// /// # Example /// /// ```rust /// use std::io::BufReader; /// /// let mut reader = BufReader::new(b"hello\nworld"); /// assert_eq!("hello\n", &*reader.read_line().unwrap()); /// ``` /// /// # Error /// /// 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 { self.read_until(b'\n').and_then(|line| match String::from_utf8(line) { Ok(s) => Ok(s), Err(_) => Err(standard_error(InvalidInput)), } ) } /// 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. /// /// # Error /// /// 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> { let mut res = Vec::new(); let mut used; loop { { let available = match self.fill_buf() { 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[..i + 1]); used = i + 1; break } None => { res.push_all(available); used = available.len(); } } } self.consume(used); } self.consume(used); Ok(res) } /// Reads the next utf8-encoded character from the underlying stream. /// /// # Error /// /// 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 { let first_byte = try!(self.read_byte()); let width = unicode::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 = 1; while start < width { match try!(self.read(buf.slice_mut(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[..width]).ok() { Some(s) => Ok(s.char_at(0)), None => Err(standard_error(InvalidInput)) } } } /// Extension methods for the Buffer trait which are included in the prelude. pub trait BufferPrelude { /// Create an iterator that reads a utf8-encoded character on each iteration /// until EOF. /// /// # Error /// /// Any error other than `EndOfFile` that is produced by the underlying Reader /// is returned by the iterator and should be handled by the caller. fn chars<'r>(&'r mut self) -> Chars<'r, Self>; /// Create an iterator that reads a line on each iteration until EOF. /// /// # Error /// /// Any error other than `EndOfFile` that is produced by the underlying Reader /// is returned by the iterator and should be handled by the caller. fn lines<'r>(&'r mut self) -> Lines<'r, Self>; } impl BufferPrelude for T { fn chars<'r>(&'r mut self) -> Chars<'r, T> { Chars { buffer: self } } fn lines<'r>(&'r mut self) -> Lines<'r, T> { Lines { buffer: self } } } /// When seeking, the resulting cursor is offset from a base by the offset given /// to the `seek` function. The base used is specified by this enumeration. #[deriving(Copy)] pub enum SeekStyle { /// Seek from the beginning of the stream SeekSet, /// Seek from the end of the stream SeekEnd, /// Seek from the current position SeekCur, } /// An object implementing `Seek` internally has some form of cursor which can /// be moved within a stream of bytes. The stream typically has a fixed size, /// allowing seeking relative to either end. pub trait Seek { /// Return position of file cursor in the stream fn tell(&self) -> IoResult; /// Seek to an offset in a stream /// /// A successful seek clears the EOF indicator. Seeking beyond EOF is /// allowed, but seeking before position 0 is not allowed. /// /// # Errors /// /// * Seeking to a negative offset is considered an error /// * Seeking past the end of the stream does not modify the underlying /// stream, but the next write may cause the previous data to be filled in /// with a bit pattern. fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>; } /// A listener is a value that can consume itself to start listening for /// connections. /// /// Doing so produces some sort of Acceptor. pub trait Listener> { /// Spin up the listener and start queuing incoming connections /// /// # Error /// /// Returns `Err` if this listener could not be bound to listen for /// connections. In all cases, this listener is consumed. fn listen(self) -> IoResult; } /// An acceptor is a value that presents incoming connections pub trait Acceptor { /// Wait for and accept an incoming connection /// /// # Error /// /// Returns `Err` if an I/O error is encountered. fn accept(&mut self) -> IoResult; /// 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 } } } /// 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 the `IoResult` representing whether the /// connection attempt was successful. A successful connection will be wrapped /// in `Ok`. A failed connection is represented as an `Err`. pub struct IncomingConnections<'a, A:'a> { inc: &'a mut A, } impl<'a, T, A: Acceptor> Iterator> for IncomingConnections<'a, A> { fn next(&mut self) -> Option> { Some(self.inc.accept()) } } /// Creates a standard error for a commonly used flavor of error. The `detail` /// field of the returned error will always be `None`. /// /// # Example /// /// ``` /// use std::io; /// /// let eof = io::standard_error(io::EndOfFile); /// let einval = io::standard_error(io::InvalidInput); /// ``` pub fn standard_error(kind: IoErrorKind) -> IoError { let desc = match kind { EndOfFile => "end of file", IoUnavailable => "I/O is unavailable", InvalidInput => "invalid input", OtherIoError => "unknown I/O error", FileNotFound => "file not found", PermissionDenied => "permission denied", ConnectionFailed => "connection failed", Closed => "stream is closed", ConnectionRefused => "connection refused", ConnectionReset => "connection reset", ConnectionAborted => "connection aborted", NotConnected => "not connected", BrokenPipe => "broken pipe", PathAlreadyExists => "file already exists", PathDoesntExist => "no such file", MismatchedFileTypeForOperation => "mismatched file type", ResourceUnavailable => "resource unavailable", TimedOut => "operation timed out", ShortWrite(..) => "short write", NoProgress => "no progress", }; IoError { kind: kind, desc: desc, detail: None, } } /// A mode specifies how a file should be opened or created. These modes are /// passed to `File::open_mode` and are used to control where the file is /// positioned when it is initially opened. #[deriving(Copy, Clone, PartialEq, Eq)] pub enum FileMode { /// Opens a file positioned at the beginning. Open, /// Opens a file positioned at EOF. Append, /// Opens a file, truncating it if it already exists. Truncate, } /// Access permissions with which the file should be opened. `File`s /// opened with `Read` will return an error if written to. #[deriving(Copy, Clone, PartialEq, Eq)] pub enum FileAccess { /// Read-only access, requests to write will result in an error Read, /// Write-only access, requests to read will result in an error Write, /// Read-write access, no requests are denied by default ReadWrite, } /// Different kinds of files which can be identified by a call to stat #[deriving(Copy, PartialEq, Show, Hash, Clone)] pub enum FileType { /// This is a normal file, corresponding to `S_IFREG` RegularFile, /// This file is a directory, corresponding to `S_IFDIR` Directory, /// This file is a named pipe, corresponding to `S_IFIFO` NamedPipe, /// This file is a block device, corresponding to `S_IFBLK` BlockSpecial, /// This file is a symbolic link to another file, corresponding to `S_IFLNK` Symlink, /// The type of this file is not recognized as one of the other categories Unknown, } /// A structure used to describe metadata information about a file. This /// structure is created through the `stat` method on a `Path`. /// /// # Example /// /// ``` /// # use std::io::fs::PathExtensions; /// # fn main() {} /// # fn foo() { /// let info = match Path::new("foo.txt").stat() { /// Ok(stat) => stat, /// Err(e) => panic!("couldn't read foo.txt: {}", e), /// }; /// /// println!("byte size: {}", info.size); /// # } /// ``` #[deriving(Copy, Hash)] pub struct FileStat { /// The size of the file, in bytes pub size: u64, /// The kind of file this path points to (directory, file, pipe, etc.) pub kind: FileType, /// The file permissions currently on the file pub perm: FilePermission, // FIXME(#10301): These time fields are pretty useless without an actual // time representation, what are the milliseconds relative // to? /// The time that the file was created at, in platform-dependent /// milliseconds pub created: u64, /// The time that this file was last modified, in platform-dependent /// milliseconds pub modified: u64, /// The time that this file was last accessed, in platform-dependent /// milliseconds pub accessed: u64, /// Information returned by stat() which is not guaranteed to be /// platform-independent. This information may be useful on some platforms, /// but it may have different meanings or no meaning at all on other /// platforms. /// /// Usage of this field is discouraged, but if access is desired then the /// fields are located here. #[unstable] pub unstable: UnstableFileStat, } /// This structure represents all of the possible information which can be /// returned from a `stat` syscall which is not contained in the `FileStat` /// structure. This information is not necessarily platform independent, and may /// have different meanings or no meaning at all on some platforms. #[unstable] #[deriving(Copy, Hash)] pub struct UnstableFileStat { /// The ID of the device containing the file. pub device: u64, /// The file serial number. pub inode: u64, /// The device ID. pub rdev: u64, /// The number of hard links to this file. pub nlink: u64, /// The user ID of the file. pub uid: u64, /// The group ID of the file. pub gid: u64, /// The optimal block size for I/O. pub blksize: u64, /// The blocks allocated for this file. pub blocks: u64, /// User-defined flags for the file. pub flags: u64, /// The file generation number. pub gen: u64, } bitflags! { #[doc = "A set of permissions for a file or directory is represented"] #[doc = "by a set of flags which are or'd together."] flags FilePermission: u32 { const USER_READ = 0o400, const USER_WRITE = 0o200, const USER_EXECUTE = 0o100, const GROUP_READ = 0o040, const GROUP_WRITE = 0o020, const GROUP_EXECUTE = 0o010, const OTHER_READ = 0o004, const OTHER_WRITE = 0o002, const OTHER_EXECUTE = 0o001, const USER_RWX = USER_READ.bits | USER_WRITE.bits | USER_EXECUTE.bits, const GROUP_RWX = GROUP_READ.bits | GROUP_WRITE.bits | GROUP_EXECUTE.bits, const OTHER_RWX = OTHER_READ.bits | OTHER_WRITE.bits | OTHER_EXECUTE.bits, #[doc = "Permissions for user owned files, equivalent to 0644 on"] #[doc = "unix-like systems."] const USER_FILE = USER_READ.bits | USER_WRITE.bits | GROUP_READ.bits | OTHER_READ.bits, #[doc = "Permissions for user owned directories, equivalent to 0755 on"] #[doc = "unix-like systems."] const USER_DIR = USER_RWX.bits | GROUP_READ.bits | GROUP_EXECUTE.bits | OTHER_READ.bits | OTHER_EXECUTE.bits, #[doc = "Permissions for user owned executables, equivalent to 0755"] #[doc = "on unix-like systems."] const USER_EXEC = USER_DIR.bits, #[doc = "All possible permissions enabled."] const ALL_PERMISSIONS = USER_RWX.bits | GROUP_RWX.bits | OTHER_RWX.bits, // Deprecated names #[allow(non_upper_case_globals)] #[deprecated = "use USER_READ instead"] const UserRead = USER_READ.bits, #[allow(non_upper_case_globals)] #[deprecated = "use USER_WRITE instead"] const UserWrite = USER_WRITE.bits, #[allow(non_upper_case_globals)] #[deprecated = "use USER_EXECUTE instead"] const UserExecute = USER_EXECUTE.bits, #[allow(non_upper_case_globals)] #[deprecated = "use GROUP_READ instead"] const GroupRead = GROUP_READ.bits, #[allow(non_upper_case_globals)] #[deprecated = "use GROUP_WRITE instead"] const GroupWrite = GROUP_WRITE.bits, #[allow(non_upper_case_globals)] #[deprecated = "use GROUP_EXECUTE instead"] const GroupExecute = GROUP_EXECUTE.bits, #[allow(non_upper_case_globals)] #[deprecated = "use OTHER_READ instead"] const OtherRead = OTHER_READ.bits, #[allow(non_upper_case_globals)] #[deprecated = "use OTHER_WRITE instead"] const OtherWrite = OTHER_WRITE.bits, #[allow(non_upper_case_globals)] #[deprecated = "use OTHER_EXECUTE instead"] const OtherExecute = OTHER_EXECUTE.bits, #[allow(non_upper_case_globals)] #[deprecated = "use USER_RWX instead"] const UserRWX = USER_RWX.bits, #[allow(non_upper_case_globals)] #[deprecated = "use GROUP_RWX instead"] const GroupRWX = GROUP_RWX.bits, #[allow(non_upper_case_globals)] #[deprecated = "use OTHER_RWX instead"] const OtherRWX = OTHER_RWX.bits, #[doc = "Deprecated: use `USER_FILE` instead."] #[allow(non_upper_case_globals)] #[deprecated = "use USER_FILE instead"] const UserFile = USER_FILE.bits, #[doc = "Deprecated: use `USER_DIR` instead."] #[allow(non_upper_case_globals)] #[deprecated = "use USER_DIR instead"] const UserDir = USER_DIR.bits, #[doc = "Deprecated: use `USER_EXEC` instead."] #[allow(non_upper_case_globals)] #[deprecated = "use USER_EXEC instead"] const UserExec = USER_EXEC.bits, #[doc = "Deprecated: use `ALL_PERMISSIONS` instead"] #[allow(non_upper_case_globals)] #[deprecated = "use ALL_PERMISSIONS instead"] const AllPermissions = ALL_PERMISSIONS.bits, } } #[stable] impl Default for FilePermission { #[stable] #[inline] fn default() -> FilePermission { FilePermission::empty() } } impl fmt::Show for FilePermission { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:04o}", self.bits) } } #[cfg(test)] mod tests { use self::BadReaderBehavior::*; use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput, Writer}; use prelude::{Ok, Vec, Buffer, SliceExt}; use uint; #[deriving(Clone, PartialEq, Show)] enum BadReaderBehavior { GoodBehavior(uint), BadBehavior(uint) } struct BadReader { r: T, behavior: Vec, } impl BadReader { fn new(r: T, behavior: Vec) -> BadReader { BadReader { behavior: behavior, r: r } } } impl Reader for BadReader { fn read(&mut self, buf: &mut [u8]) -> IoResult { let BadReader { ref mut behavior, ref mut r } = *self; loop { if behavior.is_empty() { // fall back on good return r.read(buf); } match behavior.as_mut_slice()[0] { GoodBehavior(0) => (), GoodBehavior(ref mut x) => { *x -= 1; return r.read(buf); } BadBehavior(0) => (), BadBehavior(ref mut x) => { *x -= 1; return Ok(0); } }; behavior.remove(0); } } } #[test] fn test_read_at_least() { let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), vec![GoodBehavior(uint::MAX)]); let buf = &mut [0u8; 5]; assert!(r.read_at_least(1, buf).unwrap() >= 1); assert!(r.read_exact(5).unwrap().len() == 5); // read_exact uses read_at_least assert!(r.read_at_least(0, buf).is_ok()); let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), vec![BadBehavior(50), GoodBehavior(uint::MAX)]); assert!(r.read_at_least(1, buf).unwrap() >= 1); let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), vec![BadBehavior(1), GoodBehavior(1), BadBehavior(50), GoodBehavior(uint::MAX)]); assert!(r.read_at_least(1, buf).unwrap() >= 1); assert!(r.read_at_least(1, buf).unwrap() >= 1); let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), vec![BadBehavior(uint::MAX)]); assert_eq!(r.read_at_least(1, buf).unwrap_err().kind, NoProgress); let mut r = MemReader::new(b"hello, world!".to_vec()); assert_eq!(r.read_at_least(5, buf).unwrap(), 5); assert_eq!(r.read_at_least(6, buf).unwrap_err().kind, InvalidInput); } #[test] fn test_push_at_least() { let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), vec![GoodBehavior(uint::MAX)]); let mut buf = Vec::new(); assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); assert!(r.push_at_least(0, 5, &mut buf).is_ok()); let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), vec![BadBehavior(50), GoodBehavior(uint::MAX)]); assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), vec![BadBehavior(1), GoodBehavior(1), BadBehavior(50), GoodBehavior(uint::MAX)]); assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), vec![BadBehavior(uint::MAX)]); assert_eq!(r.push_at_least(1, 5, &mut buf).unwrap_err().kind, NoProgress); let mut r = MemReader::new(b"hello, world!".to_vec()); assert_eq!(r.push_at_least(5, 1, &mut buf).unwrap_err().kind, InvalidInput); } #[test] fn test_show() { use super::*; assert_eq!(format!("{}", USER_READ), "0400"); assert_eq!(format!("{}", USER_FILE), "0644"); assert_eq!(format!("{}", USER_EXEC), "0755"); assert_eq!(format!("{}", USER_RWX), "0700"); assert_eq!(format!("{}", GROUP_RWX), "0070"); assert_eq!(format!("{}", OTHER_RWX), "0007"); assert_eq!(format!("{}", ALL_PERMISSIONS), "0777"); assert_eq!(format!("{}", USER_READ | USER_WRITE | OTHER_WRITE), "0602"); } fn _ensure_buffer_is_object_safe(x: &T) -> &Buffer { x as &Buffer } }