diff options
Diffstat (limited to 'src/libstd/old_io/mod.rs')
| -rw-r--r-- | src/libstd/old_io/mod.rs | 1961 |
1 files changed, 1961 insertions, 0 deletions
diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs new file mode 100644 index 00000000000..3d1c8a0b86c --- /dev/null +++ b/src/libstd/old_io/mod.rs @@ -0,0 +1,1961 @@ +// 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 <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. +// +// 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 +//! +//! > **Warning**: This module is currently called `old_io` for a reason! The +//! > module is currently being redesigned in a number of RFCs. For more details +//! > follow the RFC repository in connection with [RFC 517][base] or follow +//! > some of these sub-RFCs +//! > +//! > * [String handling][osstr] +//! > * [Core I/O support][core] +//! > * [Deadlines][deadlines] +//! > * [std::env][env] +//! > * [std::process][process] +//! +//! [base]: https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md +//! [osstr]: https://github.com/rust-lang/rfcs/pull/575 +//! [core]: https://github.com/rust-lang/rfcs/pull/576 +//! [deadlines]: https://github.com/rust-lang/rfcs/pull/577 +//! [env]: https://github.com/rust-lang/rfcs/pull/578 +//! [process]: https://github.com/rust-lang/rfcs/pull/579 +//! +//! `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::old_io as io; +//! +//! for line in io::stdin().lock().lines() { +//! print!("{}", line.unwrap()); +//! } +//! ``` +//! +//! * Read a complete file +//! +//! ```rust +//! use std::old_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::old_io::File; +//! +//! let mut file = File::create(&Path::new("message.txt")); +//! file.write_all(b"hello, file!\n"); +//! # drop(file); +//! # ::std::old_io::fs::unlink(&Path::new("message.txt")); +//! ``` +//! +//! * Iterate over the lines of a file +//! +//! ```rust,no_run +//! use std::old_io::BufferedReader; +//! use std::old_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::old_io::BufferedReader; +//! use std::old_io::File; +//! +//! let path = Path::new("message.txt"); +//! let mut file = BufferedReader::new(File::open(&path)); +//! let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect(); +//! ``` +//! +//! * Make a simple TCP client connection and request +//! +//! ```rust +//! # #![allow(unused_must_use)] +//! use std::old_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_all(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::old_io::{TcpListener, TcpStream}; +//! use std::old_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) +//! }); +//! } +//! } +//! } +//! +//! // 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<T>` which is equivalent to +//! `Result<T, IoError>`. 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<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_all(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::old_io::File; +//! +//! match File::create(&Path::new("diary.txt")).write_all(b"Met a girl.\n") { +//! Ok(()) => (), // succeeded +//! Err(e) => println!("failed to write to my diary: {}", e), +//! } +//! +//! # ::std::old_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<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. +//! +//! ## `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::old_io::{File, IoResult}; +//! +//! fn file_product(p: &Path) -> IoResult<u32> { +//! 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. + +#![unstable] +#![deny(unused_must_use)] + +pub use self::SeekStyle::*; +pub use self::FileMode::*; +pub use self::FileAccess::*; +pub use self::IoErrorKind::*; + +use char::CharExt; +use default::Default; +use error::Error; +use fmt; +use int; +use iter::{Iterator, IteratorExt}; +use marker::Sized; +use mem::transmute; +use ops::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 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::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 timer; +pub mod util; + +#[macro_use] +pub mod test; + +/// 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<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 +#[derive(PartialEq, Eq, Clone, Show)] +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<String> +} + +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) + } +} + +#[stable] +impl fmt::Display 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 } +} + +/// A list specifying general categories of I/O error. +#[derive(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<T> { + /// Returns an IoError with updated description and detail + fn update_err<D>(self, desc: &'static str, detail: D) -> Self where + D: FnOnce(&IoError) -> String; + + /// Returns an IoError with updated detail + fn update_detail<D>(self, detail: D) -> Self where + D: FnOnce(&IoError) -> String; + + /// Returns an IoError with update description + fn update_desc(self, desc: &'static str) -> Self; +} + +impl<T> UpdateIoError<T> for IoResult<T> { + fn update_err<D>(self, desc: &'static str, detail: D) -> IoResult<T> 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<D>(self, detail: D) -> IoResult<T> 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<T> { + 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<uint>; + + // 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<uint> { + 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(&mut buf[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<u8> { + 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<u8>) -> IoResult<uint> { + 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<u8>) -> IoResult<uint> { + 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<Vec<u8>> { + 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<Vec<u8>> { + 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<String> { + 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<u64> { + 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<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) -> IoResult<u64> { + 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<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-dependent. + 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-dependent. + 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-dependent. + 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-dependent. + 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> IoResult<f64> { + self.read_be_u64().map(|i| unsafe { + 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) -> IoResult<f32> { + self.read_be_u32().map(|i| unsafe { + transmute::<u32, f32>(i) + }) + } + + /// Reads a little-endian `u64`. + /// + /// `u64`s are 8 bytes long. + 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> IoResult<f64> { + self.read_le_u64().map(|i| unsafe { + 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) -> IoResult<f32> { + self.read_le_u32().map(|i| unsafe { + transmute::<u32, f32>(i) + }) + } + + /// Read a u8. + /// + /// `u8`s are 1 byte. + fn read_u8(&mut self) -> IoResult<u8> { + self.read_byte() + } + + /// Read an i8. + /// + /// `i8`s are 1 byte. + fn read_i8(&mut self) -> IoResult<i8> { + self.read_byte().map(|i| i as i8) + } +} + +/// 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<T: Reader> 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<T: Reader> BytesReader for T { + fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, T> { + extensions::Bytes::new(self) + } +} + +impl<'a> Reader for Box<Reader+'a> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + 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<uint> { (*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<T>, 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. +/// +/// # Examples +/// +/// ``` +/// use std::old_io as io; +/// use std::old_io::ByRefReader; +/// use std::old_io::util::LimitReader; +/// +/// fn process_input<R: Reader>(r: R) {} +/// +/// 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<uint> { 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_all(&mut self, buf: &[u8]) -> IoResult<()>; + + /// Deprecated, this method was renamed to `write_all` + #[deprecated = "renamed to `write_all`"] + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write_all(buf) } + + /// 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 fmt::Writer and saves + // off I/O errors. instead of discarding them + struct Adaptor<'a, T: ?Sized +'a> { + inner: &'a mut T, + error: IoResult<()>, + } + + impl<'a, T: ?Sized + Writer> fmt::Writer for Adaptor<'a, T> { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.inner.write_all(s.as_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_all(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_all(&[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_all(&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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(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_all(&[n]) + } + + /// Write an i8 (1 byte). + #[inline] + fn write_i8(&mut self, n: i8) -> IoResult<()> { + self.write_all(&[n as u8]) + } +} + +/// 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<T: Writer> ByRefWriter for T { + fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { + RefWriter { inner: self } + } +} + +impl<'a> Writer for Box<Writer+'a> { + #[inline] + fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { + (&mut **self).write_all(buf) + } + + #[inline] + fn flush(&mut self) -> IoResult<()> { + (&mut **self).flush() + } +} + +impl<'a> Writer for &'a mut (Writer+'a) { + #[inline] + fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { (**self).write_all(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 +/// +/// ``` +/// use std::old_io::util::TeeReader; +/// use std::old_io::{stdin, ByRefWriter}; +/// +/// fn process_input<R: Reader>(r: R) {} +/// +/// 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_all(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write_all(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<T: Reader + Writer> 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> { + type Item = IoResult<String>; + + fn next(&mut self) -> Option<IoResult<String>> { + 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> { + type Item = IoResult<char>; + + fn next(&mut self) -> Option<IoResult<char>> { + 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::old_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<String> { + 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<Vec<u8>> { + let mut res = Vec::new(); + + loop { + let (done, used) = { + let available = match self.fill_buf() { + Ok(n) => n, + Err(ref e) if res.len() > 0 && e.kind == EndOfFile => { + return Ok(res); + } + Err(e) => return Err(e) + }; + match available.iter().position(|&b| b == byte) { + Some(i) => { + res.push_all(&available[..i + 1]); + (true, i + 1) + } + None => { + res.push_all(available); + (false, available.len()) + } + } + }; + self.consume(used); + if done { + return 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<char> { + 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(&mut buf[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<T: Buffer> 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. +#[derive(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<u64>; + + /// 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<T, A: Acceptor<T>> { + /// 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<A>; +} + +/// An acceptor is a value that presents incoming connections +pub trait Acceptor<T> { + /// Wait for and accept an incoming connection + /// + /// # Error + /// + /// Returns `Err` if an I/O error is encountered. + fn accept(&mut self) -> IoResult<T>; + + /// 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: ?Sized +'a> { + inc: &'a mut A, +} + +#[old_impl_check] +impl<'a, T, A: ?Sized + Acceptor<T>> Iterator for IncomingConnections<'a, A> { + type Item = IoResult<T>; + + fn next(&mut self) -> Option<IoResult<T>> { + 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::old_io as 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. +#[derive(Copy, Clone, PartialEq, Eq, Show)] +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. +#[derive(Copy, Clone, PartialEq, Eq, Show)] +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 +#[derive(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`. +/// +/// # Examples +/// +/// ```no_run +/// # #![allow(unstable)] +/// +/// use std::old_io::fs::PathExtensions; +/// +/// 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); +/// ``` +#[derive(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] +#[derive(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! { + /// A set of permissions for a file or directory is represented by a set of + /// flags which are or'd together. + #[derive(Show)] + 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, + + /// Permissions for user owned files, equivalent to 0644 on unix-like + /// systems. + const USER_FILE = USER_READ.bits | USER_WRITE.bits | GROUP_READ.bits | OTHER_READ.bits, + + /// Permissions for user owned directories, equivalent to 0755 on + /// unix-like systems. + const USER_DIR = USER_RWX.bits | GROUP_READ.bits | GROUP_EXECUTE.bits | + OTHER_READ.bits | OTHER_EXECUTE.bits, + + /// Permissions for user owned executables, equivalent to 0755 + /// on unix-like systems. + const USER_EXEC = USER_DIR.bits, + + /// All possible permissions enabled. + const ALL_PERMISSIONS = USER_RWX.bits | GROUP_RWX.bits | OTHER_RWX.bits, + } +} + + +#[stable] +impl Default for FilePermission { + #[stable] + #[inline] + fn default() -> FilePermission { FilePermission::empty() } +} + +#[stable] +impl fmt::Display 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::v1::{Ok, Vec, Buffer, SliceExt}; + use uint; + + #[derive(Clone, PartialEq, Show)] + enum BadReaderBehavior { + GoodBehavior(uint), + BadBehavior(uint) + } + + struct BadReader<T> { + r: T, + behavior: Vec<BadReaderBehavior>, + } + + impl<T: Reader> BadReader<T> { + fn new(r: T, behavior: Vec<BadReaderBehavior>) -> BadReader<T> { + BadReader { behavior: behavior, r: r } + } + } + + impl<T: Reader> Reader for BadReader<T> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + 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<T: Buffer>(x: &T) -> &Buffer { + x as &Buffer + } +} |
