Browse Source

Add io module from libstd

Also includes CString and CStr modules
pull/10/head
Fenrir 8 years ago
parent
commit
b1779396be
  1. 20
      ctru-sys/src/sys/libc.rs
  2. 788
      src/ffi/c_str.rs
  3. 2
      src/ffi/mod.rs
  4. 1121
      src/io/buffered.rs
  5. 575
      src/io/cursor.rs
  6. 529
      src/io/error.rs
  7. 279
      src/io/impls.rs
  8. 1887
      src/io/mod.rs
  9. 22
      src/io/prelude.rs
  10. 204
      src/io/util.rs
  11. 4
      src/lib.rs
  12. 2
      src/memchr.rs
  13. 1
      src/sys/mod.rs
  14. 78
      src/sys/os.rs

20
ctru-sys/src/sys/libc.rs

@ -1,5 +1,24 @@ @@ -1,5 +1,24 @@
pub const STDOUT_FILENO: c_int = 1;
pub const EPERM: c_int = 1;
pub const ENOENT: c_int = 2;
pub const EINTR: c_int = 4;
pub const EAGAIN: c_int = 11;
pub const EACCES: c_int = 13;
pub const EEXIST: c_int = 17;
pub const EINVAL: c_int = 22;
pub const EPIPE: c_int = 32;
pub const EWOULDBLOCK: c_int = EAGAIN;
pub const EADDRINUSE: c_int = 98;
pub const EADDRNOTAVAIL: c_int = 99;
pub const ECONNABORTED: c_int = 103;
pub const ECONNRESET: c_int = 104;
pub const ENOTCONN: c_int = 107;
pub const ETIMEDOUT: c_int = 110;
pub const ECONNREFUSED: c_int = 111;
pub const EHOSTDOWN: c_int = 112;
#[repr(u8)]
pub enum c_void {
__variant1,
@ -25,5 +44,6 @@ extern "C" { @@ -25,5 +44,6 @@ extern "C" {
pub fn __errno() -> *const c_int;
pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void;
pub fn memrchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void;
pub fn strlen(cs: *const c_char) -> size_t;
pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t;
}

788
src/ffi/c_str.rs

@ -0,0 +1,788 @@ @@ -0,0 +1,788 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use ascii;
use collections::borrow::{Cow, Borrow, ToOwned};
use core::cmp::Ordering;
use error::Error;
use core::fmt::{self, Write};
use io;
use libctru::libc::{self, c_char};
use core::mem;
use memchr;
use core::ops;
use core::ptr;
use core::slice;
use core::str::{self, Utf8Error};
use alloc::boxed::Box;
use collections::Vec;
use collections::String;
/// A type representing an owned C-compatible string
///
/// This type serves the primary purpose of being able to safely generate a
/// C-compatible string from a Rust byte slice or vector. An instance of this
/// type is a static guarantee that the underlying bytes contain no interior 0
/// bytes and the final byte is 0.
///
/// A `CString` is created from either a byte slice or a byte vector. After
/// being created, a `CString` predominately inherits all of its methods from
/// the `Deref` implementation to `[c_char]`. Note that the underlying array
/// is represented as an array of `c_char` as opposed to `u8`. A `u8` slice
/// can be obtained with the `as_bytes` method. Slices produced from a `CString`
/// do *not* contain the trailing nul terminator unless otherwise specified.
///
/// # Examples
///
/// ```no_run
/// # fn main() {
/// use std::ffi::CString;
/// use std::os::raw::c_char;
///
/// extern {
/// fn my_printer(s: *const c_char);
/// }
///
/// let c_to_print = CString::new("Hello, world!").unwrap();
/// unsafe {
/// my_printer(c_to_print.as_ptr());
/// }
/// # }
/// ```
///
/// # Safety
///
/// `CString` is intended for working with traditional C-style strings
/// (a sequence of non-null bytes terminated by a single null byte); the
/// primary use case for these kinds of strings is interoperating with C-like
/// code. Often you will need to transfer ownership to/from that external
/// code. It is strongly recommended that you thoroughly read through the
/// documentation of `CString` before use, as improper ownership management
/// of `CString` instances can lead to invalid memory accesses, memory leaks,
/// and other memory errors.
#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
pub struct CString {
// Invariant 1: the slice ends with a zero byte and has a length of at least one.
// Invariant 2: the slice contains only one zero byte.
// Improper usage of unsafe function can break Invariant 2, but not Invariant 1.
inner: Box<[u8]>,
}
/// Representation of a borrowed C string.
///
/// This dynamically sized type is only safely constructed via a borrowed
/// version of an instance of `CString`. This type can be constructed from a raw
/// C string as well and represents a C string borrowed from another location.
///
/// Note that this structure is **not** `repr(C)` and is not recommended to be
/// placed in the signatures of FFI functions. Instead safe wrappers of FFI
/// functions may leverage the unsafe `from_ptr` constructor to provide a safe
/// interface to other consumers.
///
/// # Examples
///
/// Inspecting a foreign C string
///
/// ```no_run
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
///
/// extern { fn my_string() -> *const c_char; }
///
/// unsafe {
/// let slice = CStr::from_ptr(my_string());
/// println!("string length: {}", slice.to_bytes().len());
/// }
/// ```
///
/// Passing a Rust-originating C string
///
/// ```no_run
/// use std::ffi::{CString, CStr};
/// use std::os::raw::c_char;
///
/// fn work(data: &CStr) {
/// extern { fn work_with(data: *const c_char); }
///
/// unsafe { work_with(data.as_ptr()) }
/// }
///
/// let s = CString::new("data data data data").unwrap();
/// work(&s);
/// ```
///
/// Converting a foreign C string into a Rust `String`
///
/// ```no_run
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
///
/// extern { fn my_string() -> *const c_char; }
///
/// fn my_string_safe() -> String {
/// unsafe {
/// CStr::from_ptr(my_string()).to_string_lossy().into_owned()
/// }
/// }
///
/// println!("string: {}", my_string_safe());
/// ```
#[derive(Hash)]
pub struct CStr {
// FIXME: this should not be represented with a DST slice but rather with
// just a raw `c_char` along with some form of marker to make
// this an unsized type. Essentially `sizeof(&CStr)` should be the
// same as `sizeof(&c_char)` but `CStr` should be an unsized type.
inner: [c_char]
}
/// An error returned from `CString::new` to indicate that a nul byte was found
/// in the vector provided.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct NulError(usize, Vec<u8>);
/// An error returned from `CStr::from_bytes_with_nul` to indicate that a nul
/// byte was found too early in the slice provided or one wasn't found at all.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FromBytesWithNulError { _a: () }
/// An error returned from `CString::into_string` to indicate that a UTF-8 error
/// was encountered during the conversion.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct IntoStringError {
inner: CString,
error: Utf8Error,
}
impl CString {
/// Creates a new C-compatible string from a container of bytes.
///
/// This method will consume the provided data and use the underlying bytes
/// to construct a new string, ensuring that there is a trailing 0 byte.
///
/// # Examples
///
/// ```no_run
/// use std::ffi::CString;
/// use std::os::raw::c_char;
///
/// extern { fn puts(s: *const c_char); }
///
/// let to_print = CString::new("Hello!").unwrap();
/// unsafe {
/// puts(to_print.as_ptr());
/// }
/// ```
///
/// # Errors
///
/// This function will return an error if the bytes yielded contain an
/// internal 0 byte. The error returned will contain the bytes as well as
/// the position of the nul byte.
pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
Self::_new(t.into())
}
fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
match memchr::memchr(0, &bytes) {
Some(i) => Err(NulError(i, bytes)),
None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
}
}
/// Creates a C-compatible string from a byte vector without checking for
/// interior 0 bytes.
///
/// This method is equivalent to `new` except that no runtime assertion
/// is made that `v` contains no 0 bytes, and it requires an actual
/// byte vector, not anything that can be converted to one with Into.
///
/// # Examples
///
/// ```
/// use std::ffi::CString;
///
/// let raw = b"foo".to_vec();
/// unsafe {
/// let c_string = CString::from_vec_unchecked(raw);
/// }
/// ```
pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
v.reserve_exact(1);
v.push(0);
CString { inner: v.into_boxed_slice() }
}
/// Retakes ownership of a `CString` that was transferred to C.
///
/// Additionally, the length of the string will be recalculated from the pointer.
///
/// # Safety
///
/// This should only ever be called with a pointer that was earlier
/// obtained by calling `into_raw` on a `CString`. Other usage (e.g. trying to take
/// ownership of a string that was allocated by foreign code) is likely to lead
/// to undefined behavior or allocator corruption.
pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
let len = libc::strlen(ptr) + 1; // Including the NUL byte
let slice = slice::from_raw_parts(ptr, len as usize);
CString { inner: mem::transmute(slice) }
}
/// Transfers ownership of the string to a C caller.
///
/// The pointer must be returned to Rust and reconstituted using
/// `from_raw` to be properly deallocated. Specifically, one
/// should *not* use the standard C `free` function to deallocate
/// this string.
///
/// Failure to call `from_raw` will lead to a memory leak.
pub fn into_raw(self) -> *mut c_char {
Box::into_raw(self.into_inner()) as *mut c_char
}
/// Converts the `CString` into a `String` if it contains valid Unicode data.
///
/// On failure, ownership of the original `CString` is returned.
pub fn into_string(self) -> Result<String, IntoStringError> {
String::from_utf8(self.into_bytes())
.map_err(|e| IntoStringError {
error: e.utf8_error(),
inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) },
})
}
/// Returns the underlying byte buffer.
///
/// The returned buffer does **not** contain the trailing nul separator and
/// it is guaranteed to not have any interior nul bytes.
pub fn into_bytes(self) -> Vec<u8> {
let mut vec = self.into_inner().into_vec();
let _nul = vec.pop();
debug_assert_eq!(_nul, Some(0u8));
vec
}
/// Equivalent to the `into_bytes` function except that the returned vector
/// includes the trailing nul byte.
pub fn into_bytes_with_nul(self) -> Vec<u8> {
self.into_inner().into_vec()
}
/// Returns the contents of this `CString` as a slice of bytes.
///
/// The returned slice does **not** contain the trailing nul separator and
/// it is guaranteed to not have any interior nul bytes.
pub fn as_bytes(&self) -> &[u8] {
&self.inner[..self.inner.len() - 1]
}
/// Equivalent to the `as_bytes` function except that the returned slice
/// includes the trailing nul byte.
pub fn as_bytes_with_nul(&self) -> &[u8] {
&self.inner
}
// Bypass "move out of struct which implements `Drop` trait" restriction.
fn into_inner(self) -> Box<[u8]> {
unsafe {
let result = ptr::read(&self.inner);
mem::forget(self);
result
}
}
}
// Turns this `CString` into an empty string to prevent
// memory unsafe code from working by accident. Inline
// to prevent LLVM from optimizing it away in debug builds.
impl Drop for CString {
#[inline]
fn drop(&mut self) {
unsafe { *self.inner.get_unchecked_mut(0) = 0; }
}
}
impl ops::Deref for CString {
type Target = CStr;
fn deref(&self) -> &CStr {
unsafe { mem::transmute(self.as_bytes_with_nul()) }
}
}
impl fmt::Debug for CString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl From<CString> for Vec<u8> {
fn from(s: CString) -> Vec<u8> {
s.into_bytes()
}
}
impl fmt::Debug for CStr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\"")?;
for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
f.write_char(byte as char)?;
}
write!(f, "\"")
}
}
impl<'a> Default for &'a CStr {
fn default() -> &'a CStr {
static SLICE: &'static [c_char] = &[0];
unsafe { CStr::from_ptr(SLICE.as_ptr()) }
}
}
impl Default for CString {
/// Creates an empty `CString`.
fn default() -> CString {
let a: &CStr = Default::default();
a.to_owned()
}
}
impl Borrow<CStr> for CString {
fn borrow(&self) -> &CStr { self }
}
impl NulError {
/// Returns the position of the nul byte in the slice that was provided to
/// `CString::new`.
///
/// # Examples
///
/// ```
/// use std::ffi::CString;
///
/// let nul_error = CString::new("foo\0bar").unwrap_err();
/// assert_eq!(nul_error.nul_position(), 3);
///
/// let nul_error = CString::new("foo bar\0").unwrap_err();
/// assert_eq!(nul_error.nul_position(), 7);
/// ```
pub fn nul_position(&self) -> usize { self.0 }
/// Consumes this error, returning the underlying vector of bytes which
/// generated the error in the first place.
///
/// # Examples
///
/// ```
/// use std::ffi::CString;
///
/// let nul_error = CString::new("foo\0bar").unwrap_err();
/// assert_eq!(nul_error.into_vec(), b"foo\0bar");
/// ```
pub fn into_vec(self) -> Vec<u8> { self.1 }
}
impl Error for NulError {
fn description(&self) -> &str { "nul byte found in data" }
}
impl fmt::Display for NulError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "nul byte found in provided data at position: {}", self.0)
}
}
impl From<NulError> for io::Error {
fn from(_: NulError) -> io::Error {
io::Error::new(io::ErrorKind::InvalidInput,
"data provided contains a nul byte")
}
}
impl IntoStringError {
/// Consumes this error, returning original `CString` which generated the
/// error.
pub fn into_cstring(self) -> CString {
self.inner
}
/// Access the underlying UTF-8 error that was the cause of this error.
pub fn utf8_error(&self) -> Utf8Error {
self.error
}
}
impl Error for IntoStringError {
fn description(&self) -> &str {
"C string contained non-utf8 bytes"
}
fn cause(&self) -> Option<&Error> {
Some(&self.error)
}
}
impl fmt::Display for IntoStringError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
impl CStr {
/// Casts a raw C string to a safe C string wrapper.
///
/// This function will cast the provided `ptr` to the `CStr` wrapper which
/// allows inspection and interoperation of non-owned C strings. This method
/// is unsafe for a number of reasons:
///
/// * There is no guarantee to the validity of `ptr`
/// * The returned lifetime is not guaranteed to be the actual lifetime of
/// `ptr`
/// * There is no guarantee that the memory pointed to by `ptr` contains a
/// valid nul terminator byte at the end of the string.
///
/// > **Note**: This operation is intended to be a 0-cost cast but it is
/// > currently implemented with an up-front calculation of the length of
/// > the string. This is not guaranteed to always be the case.
///
/// # Examples
///
/// ```no_run
/// # fn main() {
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
///
/// extern {
/// fn my_string() -> *const c_char;
/// }
///
/// unsafe {
/// let slice = CStr::from_ptr(my_string());
/// println!("string returned: {}", slice.to_str().unwrap());
/// }
/// # }
/// ```
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
let len = libc::strlen(ptr);
mem::transmute(slice::from_raw_parts(ptr, len as usize + 1))
}
/// Creates a C string wrapper from a byte slice.
///
/// This function will cast the provided `bytes` to a `CStr` wrapper after
/// ensuring that it is null terminated and does not contain any interior
/// nul bytes.
///
/// # Examples
///
/// ```
/// use std::ffi::CStr;
///
/// let cstr = CStr::from_bytes_with_nul(b"hello\0");
/// assert!(cstr.is_ok());
/// ```
pub fn from_bytes_with_nul(bytes: &[u8])
-> Result<&CStr, FromBytesWithNulError> {
if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) {
Err(FromBytesWithNulError { _a: () })
} else {
Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
}
}
/// Unsafely creates a C string wrapper from a byte slice.
///
/// This function will cast the provided `bytes` to a `CStr` wrapper without
/// performing any sanity checks. The provided slice must be null terminated
/// and not contain any interior nul bytes.
///
/// # Examples
///
/// ```
/// use std::ffi::{CStr, CString};
///
/// unsafe {
/// let cstring = CString::new("hello").unwrap();
/// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
/// assert_eq!(cstr, &*cstring);
/// }
/// ```
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
mem::transmute(bytes)
}
/// Returns the inner pointer to this C string.
///
/// The returned pointer will be valid for as long as `self` is and points
/// to a contiguous region of memory terminated with a 0 byte to represent
/// the end of the string.
///
/// **WARNING**
///
/// It is your responsibility to make sure that the underlying memory is not
/// freed too early. For example, the following code will cause undefined
/// behaviour when `ptr` is used inside the `unsafe` block:
///
/// ```no_run
/// use std::ffi::{CString};
///
/// let ptr = CString::new("Hello").unwrap().as_ptr();
/// unsafe {
/// // `ptr` is dangling
/// *ptr;
/// }
/// ```
///
/// This happens because the pointer returned by `as_ptr` does not carry any
/// lifetime information and the string is deallocated immediately after
/// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated.
/// To fix the problem, bind the string to a local variable:
///
/// ```no_run
/// use std::ffi::{CString};
///
/// let hello = CString::new("Hello").unwrap();
/// let ptr = hello.as_ptr();
/// unsafe {
/// // `ptr` is valid because `hello` is in scope
/// *ptr;
/// }
/// ```
pub fn as_ptr(&self) -> *const c_char {
self.inner.as_ptr()
}
/// Converts this C string to a byte slice.
///
/// This function will calculate the length of this string (which normally
/// requires a linear amount of work to be done) and then return the
/// resulting slice of `u8` elements.
///
/// The returned slice will **not** contain the trailing nul that this C
/// string has.
///
/// > **Note**: This method is currently implemented as a 0-cost cast, but
/// > it is planned to alter its definition in the future to perform the
/// > length calculation whenever this method is called.
pub fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
&bytes[..bytes.len() - 1]
}
/// Converts this C string to a byte slice containing the trailing 0 byte.
///
/// This function is the equivalent of `to_bytes` except that it will retain
/// the trailing nul instead of chopping it off.
///
/// > **Note**: This method is currently implemented as a 0-cost cast, but
/// > it is planned to alter its definition in the future to perform the
/// > length calculation whenever this method is called.
pub fn to_bytes_with_nul(&self) -> &[u8] {
unsafe { mem::transmute(&self.inner) }
}
/// Yields a `&str` slice if the `CStr` contains valid UTF-8.
///
/// This function will calculate the length of this string and check for
/// UTF-8 validity, and then return the `&str` if it's valid.
///
/// > **Note**: This method is currently implemented to check for validity
/// > after a 0-cost cast, but it is planned to alter its definition in the
/// > future to perform the length calculation in addition to the UTF-8
/// > check whenever this method is called.
pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
// NB: When CStr is changed to perform the length check in .to_bytes()
// instead of in from_ptr(), it may be worth considering if this should
// be rewritten to do the UTF-8 check inline with the length calculation
// instead of doing it afterwards.
str::from_utf8(self.to_bytes())
}
/// Converts a `CStr` into a `Cow<str>`.
///
/// This function will calculate the length of this string (which normally
/// requires a linear amount of work to be done) and then return the
/// resulting slice as a `Cow<str>`, replacing any invalid UTF-8 sequences
/// with `U+FFFD REPLACEMENT CHARACTER`.
///
/// > **Note**: This method is currently implemented to check for validity
/// > after a 0-cost cast, but it is planned to alter its definition in the
/// > future to perform the length calculation in addition to the UTF-8
/// > check whenever this method is called.
pub fn to_string_lossy(&self) -> Cow<str> {
String::from_utf8_lossy(self.to_bytes())
}
}
impl PartialEq for CStr {
fn eq(&self, other: &CStr) -> bool {
self.to_bytes().eq(other.to_bytes())
}
}
impl Eq for CStr {}
impl PartialOrd for CStr {
fn partial_cmp(&self, other: &CStr) -> Option<Ordering> {
self.to_bytes().partial_cmp(&other.to_bytes())
}
}
impl Ord for CStr {
fn cmp(&self, other: &CStr) -> Ordering {
self.to_bytes().cmp(&other.to_bytes())
}
}
impl ToOwned for CStr {
type Owned = CString;
fn to_owned(&self) -> CString {
unsafe { CString::from_vec_unchecked(self.to_bytes().to_vec()) }
}
}
impl<'a> From<&'a CStr> for CString {
fn from(s: &'a CStr) -> CString {
s.to_owned()
}
}
impl ops::Index<ops::RangeFull> for CString {
type Output = CStr;
#[inline]
fn index(&self, _index: ops::RangeFull) -> &CStr {
self
}
}
impl AsRef<CStr> for CStr {
fn as_ref(&self) -> &CStr {
self
}
}
impl AsRef<CStr> for CString {
fn as_ref(&self) -> &CStr {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use libc::c_char;
use collections::borrow::Cow::{Borrowed, Owned};
use collections::borrow::ToOwned;
use core::hash::{Hash, Hasher};
#[test]
fn c_to_rust() {
let data = b"123\0";
let ptr = data.as_ptr() as *const c_char;
unsafe {
assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123");
assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0");
}
}
#[test]
fn simple() {
let s = CString::new("1234").unwrap();
assert_eq!(s.as_bytes(), b"1234");
assert_eq!(s.as_bytes_with_nul(), b"1234\0");
}
#[test]
fn build_with_zero1() {
assert!(CString::new(&b"\0"[..]).is_err());
}
#[test]
fn build_with_zero2() {
assert!(CString::new(vec![0]).is_err());
}
#[test]
fn build_with_zero3() {
unsafe {
let s = CString::from_vec_unchecked(vec![0]);
assert_eq!(s.as_bytes(), b"\0");
}
}
#[test]
fn formatted() {
let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
}
#[test]
fn borrowed() {
unsafe {
let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
assert_eq!(s.to_bytes(), b"12");
assert_eq!(s.to_bytes_with_nul(), b"12\0");
}
}
#[test]
fn to_str() {
let data = b"123\xE2\x80\xA6\0";
let ptr = data.as_ptr() as *const c_char;
unsafe {
assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
}
let data = b"123\xE2\0";
let ptr = data.as_ptr() as *const c_char;
unsafe {
assert!(CStr::from_ptr(ptr).to_str().is_err());
assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
}
}
#[test]
fn to_owned() {
let data = b"123\0";
let ptr = data.as_ptr() as *const c_char;
let owned = unsafe { CStr::from_ptr(ptr).to_owned() };
assert_eq!(owned.as_bytes_with_nul(), data);
}
#[test]
fn from_bytes_with_nul() {
let data = b"123\0";
let cstr = CStr::from_bytes_with_nul(data);
assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..]));
let cstr = CStr::from_bytes_with_nul(data);
assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..]));
unsafe {
let cstr = CStr::from_bytes_with_nul(data);
let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data);
assert_eq!(cstr, Ok(cstr_unchecked));
}
}
#[test]
fn from_bytes_with_nul_unterminated() {
let data = b"123";
let cstr = CStr::from_bytes_with_nul(data);
assert!(cstr.is_err());
}
#[test]
fn from_bytes_with_nul_interior() {
let data = b"1\023\0";
let cstr = CStr::from_bytes_with_nul(data);
assert!(cstr.is_err());
}
}

2
src/ffi/mod.rs

@ -1,3 +1,5 @@ @@ -1,3 +1,5 @@
pub use self::c_str::{CString, CStr};
pub use self::os_str::{OsString, OsStr};
mod c_str;
mod os_str;

1121
src/io/buffered.rs

File diff suppressed because it is too large Load Diff

575
src/io/cursor.rs

@ -0,0 +1,575 @@ @@ -0,0 +1,575 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use io::prelude::*;
use core::cmp;
use io::{self, SeekFrom, Error, ErrorKind};
use collections::boxed::Box;
use collections::Vec;
/// A `Cursor` wraps another type and provides it with a
/// [`Seek`](trait.Seek.html) implementation.
///
/// Cursors are typically used with in-memory buffers to allow them to
/// implement `Read` and/or `Write`, allowing these buffers to be used
/// anywhere you might use a reader or writer that does actual I/O.
///
/// The standard library implements some I/O traits on various types which
/// are commonly used as a buffer, like `Cursor<Vec<u8>>` and `Cursor<&[u8]>`.
///
/// # Examples
///
/// We may want to write bytes to a [`File`][file] in our production
/// code, but use an in-memory buffer in our tests. We can do this with
/// `Cursor`:
///
/// [file]: ../fs/struct.File.html
///
/// ```no_run
/// use std::io::prelude::*;
/// use std::io::{self, SeekFrom};
/// use std::fs::File;
///
/// // a library function we've written
/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
/// try!(writer.seek(SeekFrom::End(-10)));
///
/// for i in 0..10 {
/// try!(writer.write(&[i]));
/// }
///
/// // all went well
/// Ok(())
/// }
///
/// # fn foo() -> io::Result<()> {
/// // Here's some code that uses this library function.
/// //
/// // We might want to use a BufReader here for efficiency, but let's
/// // keep this example focused.
/// let mut file = try!(File::create("foo.txt"));
///
/// try!(write_ten_bytes_at_end(&mut file));
/// # Ok(())
/// # }
///
/// // now let's write a test
/// #[test]
/// fn test_writes_bytes() {
/// // setting up a real File is much more slow than an in-memory buffer,
/// // let's use a cursor instead
/// use std::io::Cursor;
/// let mut buff = Cursor::new(vec![0; 15]);
///
/// write_ten_bytes_at_end(&mut buff).unwrap();
///
/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
/// }
/// ```
#[derive(Clone, Debug)]
pub struct Cursor<T> {
inner: T,
pos: u64,
}
impl<T> Cursor<T> {
/// Creates a new cursor wrapping the provided underlying I/O object.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
/// ```
pub fn new(inner: T) -> Cursor<T> {
Cursor { pos: 0, inner: inner }
}
/// Consumes this cursor, returning the underlying value.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let vec = buff.into_inner();
/// ```
pub fn into_inner(self) -> T { self.inner }
/// Gets a reference to the underlying value in this cursor.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let reference = buff.get_ref();
/// ```
pub fn get_ref(&self) -> &T { &self.inner }
/// Gets a mutable reference to the underlying value in this cursor.
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying value as it may corrupt this cursor's position.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let mut buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let reference = buff.get_mut();
/// ```
pub fn get_mut(&mut self) -> &mut T { &mut self.inner }
/// Returns the current position of this cursor.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
/// use std::io::prelude::*;
/// use std::io::SeekFrom;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.position(), 0);
///
/// buff.seek(SeekFrom::Current(2)).unwrap();
/// assert_eq!(buff.position(), 2);
///
/// buff.seek(SeekFrom::Current(-1)).unwrap();
/// assert_eq!(buff.position(), 1);
/// ```
pub fn position(&self) -> u64 { self.pos }
/// Sets the position of this cursor.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.position(), 0);
///
/// buff.set_position(2);
/// assert_eq!(buff.position(), 2);
///
/// buff.set_position(4);
/// assert_eq!(buff.position(), 4);
/// ```
pub fn set_position(&mut self, pos: u64) { self.pos = pos; }
}
impl<T> io::Seek for Cursor<T> where T: AsRef<[u8]> {
fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
let pos = match style {
SeekFrom::Start(n) => { self.pos = n; return Ok(n) }
SeekFrom::End(n) => self.inner.as_ref().len() as i64 + n,
SeekFrom::Current(n) => self.pos as i64 + n,
};
if pos < 0 {
Err(Error::new(ErrorKind::InvalidInput,
"invalid seek to a negative position"))
} else {
self.pos = pos as u64;
Ok(self.pos)
}
}
}
impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = Read::read(&mut self.fill_buf()?, buf)?;
self.pos += n as u64;
Ok(n)
}
}
impl<T> BufRead for Cursor<T> where T: AsRef<[u8]> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
Ok(&self.inner.as_ref()[(amt as usize)..])
}
fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
}
impl<'a> Write for Cursor<&'a mut [u8]> {
#[inline]
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
let pos = cmp::min(self.pos, self.inner.len() as u64);
let amt = (&mut self.inner[(pos as usize)..]).write(data)?;
self.pos += amt as u64;
Ok(amt)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
impl Write for Cursor<Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// Make sure the internal buffer is as least as big as where we
// currently are
let pos = self.position();
let amt = pos.saturating_sub(self.inner.len() as u64);
// use `resize` so that the zero filling is as efficient as possible
let len = self.inner.len();
self.inner.resize(len + amt as usize, 0);
// Figure out what bytes will be used to overwrite what's currently
// there (left), and what will be appended on the end (right)
{
let pos = pos as usize;
let space = self.inner.len() - pos;
let (left, right) = buf.split_at(cmp::min(space, buf.len()));
self.inner[pos..pos + left.len()].copy_from_slice(left);
self.inner.extend_from_slice(right);
}
// Bump us forward
self.set_position(pos + buf.len() as u64);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
impl Write for Cursor<Box<[u8]>> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let pos = cmp::min(self.pos, self.inner.len() as u64);
let amt = (&mut self.inner[(pos as usize)..]).write(buf)?;
self.pos += amt as u64;
Ok(amt)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#[cfg(test)]
mod tests {
use io::prelude::*;
use io::{Cursor, SeekFrom};
use collections::Vec;
#[test]
fn test_vec_writer() {
let mut writer = Vec::new();
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(writer, b);
}
#[test]
fn test_mem_writer() {
let mut writer = Cursor::new(Vec::new());
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
}
#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_seek() {
let mut buf = [0 as u8; 8];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[1]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2);
assert_eq!(writer.position(), 2);
assert_eq!(writer.write(&[2]).unwrap(), 1);
assert_eq!(writer.position(), 3);
assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[3]).unwrap(), 1);
assert_eq!(writer.position(), 2);
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.position(), 7);
assert_eq!(writer.write(&[4]).unwrap(), 1);
assert_eq!(writer.position(), 8);
}
let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
assert_eq!(buf, b);
}
#[test]
fn test_buf_writer_error() {
let mut buf = [0 as u8; 2];
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[0, 0]).unwrap(), 1);
assert_eq!(writer.write(&[0, 0]).unwrap(), 0);
}
#[test]
fn test_mem_reader() {
let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_boxed_slice_reader() {
let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7).into_boxed_slice());
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn read_to_end() {
let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
let mut v = Vec::new();
reader.read_to_end(&mut v).unwrap();
assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
}
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.len(), 7);
let b: &[_] = &[0];
assert_eq!(&buf[..], b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.len(), 3);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(&buf[..], b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_buf_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = Cursor::new(&in_buf[..]);
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
assert_eq!(reader.position(), 0);
let mut buf = [0];
assert_eq!(reader.read(&mut buf).unwrap(), 1);
assert_eq!(reader.position(), 1);
let b: &[_] = &[0];
assert_eq!(buf, b);
let mut buf = [0; 4];
assert_eq!(reader.read(&mut buf).unwrap(), 4);
assert_eq!(reader.position(), 5);
let b: &[_] = &[1, 2, 3, 4];
assert_eq!(buf, b);
assert_eq!(reader.read(&mut buf).unwrap(), 3);
let b: &[_] = &[5, 6, 7];
assert_eq!(&buf[..3], b);
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
#[test]
fn test_read_char() {
let b = &b"Vi\xE1\xBB\x87t"[..];
let mut c = Cursor::new(b).chars();
assert_eq!(c.next().unwrap().unwrap(), 'V');
assert_eq!(c.next().unwrap().unwrap(), 'i');
assert_eq!(c.next().unwrap().unwrap(), 'ệ');
assert_eq!(c.next().unwrap().unwrap(), 't');
assert!(c.next().is_none());
}
#[test]
fn test_read_bad_char() {
let b = &b"\x80"[..];
let mut c = Cursor::new(b).chars();
assert!(c.next().unwrap().is_err());
}
#[test]
fn seek_past_end() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut r = Cursor::new(vec!(10));
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.read(&mut [0]).unwrap(), 0);
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 0);
let mut r = Cursor::new(vec![10].into_boxed_slice());
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 0);
}
#[test]
fn seek_before_0() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut r = Cursor::new(vec!(10));
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
let mut r = Cursor::new(vec!(10).into_boxed_slice());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
fn test_seekable_mem_writer() {
let mut writer = Cursor::new(Vec::<u8>::new());
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[3, 4]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3);
assert_eq!(writer.write(&[0, 1]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7);
assert_eq!(writer.write(&[1, 2]).unwrap(), 2);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
assert_eq!(&writer.get_ref()[..], b);
assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10);
assert_eq!(writer.write(&[1]).unwrap(), 1);
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn vec_seek_past_end() {
let mut r = Cursor::new(Vec::new());
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 1);
}
#[test]
fn vec_seek_before_0() {
let mut r = Cursor::new(Vec::new());
assert!(r.seek(SeekFrom::End(-2)).is_err());
}
}

529
src/io/error.rs

@ -0,0 +1,529 @@ @@ -0,0 +1,529 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use error;
use core::fmt;
use core::result;
use sys;
use collections::boxed::Box;
/// A specialized [`Result`](../result/enum.Result.html) type for I/O
/// operations.
///
/// This type is broadly used across `std::io` for any operation which may
/// produce an error.
///
/// This typedef is generally used to avoid writing out `io::Error` directly and
/// is otherwise a direct mapping to `Result`.
///
/// While usual Rust style is to import types directly, aliases of `Result`
/// often are not, to make it easier to distinguish between them. `Result` is
/// generally assumed to be `std::result::Result`, and so users of this alias
/// will generally use `io::Result` instead of shadowing the prelude's import
/// of `std::result::Result`.
///
/// # Examples
///
/// A convenience function that bubbles an `io::Result` to its caller:
///
/// ```
/// use std::io;
///
/// fn get_string() -> io::Result<String> {
/// let mut buffer = String::new();
///
/// try!(io::stdin().read_line(&mut buffer));
///
/// Ok(buffer)
/// }
/// ```
pub type Result<T> = result::Result<T, Error>;
/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// [`ErrorKind`].
///
/// [`ErrorKind`]: enum.ErrorKind.html
#[derive(Debug)]
pub struct Error {
repr: Repr,
}
enum Repr {
Os(i32),
Custom(Box<Custom>),
}
#[derive(Debug)]
struct Custom {
kind: ErrorKind,
error: Box<error::Error+Send+Sync>,
}
/// A list specifying general categories of I/O error.
///
/// This list is intended to grow over time and it is not recommended to
/// exhaustively match against it.
///
/// It is used with the [`io::Error`] type.
///
/// [`io::Error`]: struct.Error.html
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[allow(deprecated)]
pub enum ErrorKind {
/// An entity was not found, often a file.
NotFound,
/// The operation lacked the necessary privileges to complete.
PermissionDenied,
/// 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,
/// A socket address could not be bound because the address is already in
/// use elsewhere.
AddrInUse,
/// A nonexistent interface was requested or the requested address was not
/// local.
AddrNotAvailable,
/// The operation failed because a pipe was closed.
BrokenPipe,
/// An entity already exists, often a file.
AlreadyExists,
/// The operation needs to block to complete, but the blocking operation was
/// requested to not occur.
WouldBlock,
/// A parameter was incorrect.
InvalidInput,
/// Data not valid for the operation were encountered.
///
/// Unlike `InvalidInput`, this typically means that the operation
/// parameters were valid, however the error was caused by malformed
/// input data.
///
/// For example, a function that reads a file into a string will error with
/// `InvalidData` if the file's contents are not valid UTF-8.
InvalidData,
/// The I/O operation's timeout expired, causing it to be canceled.
TimedOut,
/// An error returned when an operation could not be completed because a
/// call to `write` returned `Ok(0)`.
///
/// This typically means that an operation could only succeed if it wrote a
/// particular number of bytes but only a smaller number of bytes could be
/// written.
WriteZero,
/// This operation was interrupted.
///
/// Interrupted operations can typically be retried.
Interrupted,
/// Any I/O error not part of this list.
Other,
/// An error returned when an operation could not be completed because an
/// "end of file" was reached prematurely.
///
/// This typically means that an operation could only succeed if it read a
/// particular number of bytes but only a smaller number of bytes could be
/// read.
UnexpectedEof,
/// A marker variant that tells the compiler that users of this enum cannot
/// match it exhaustively.
#[doc(hidden)]
__Nonexhaustive,
}
impl Error {
/// Creates a new I/O error from a known kind of error as well as an
/// arbitrary error payload.
///
/// This function is used to generically create I/O errors which do not
/// originate from the OS itself. The `error` argument is an arbitrary
/// payload which will be contained in this `Error`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// // errors can be created from strings
/// let custom_error = Error::new(ErrorKind::Other, "oh no!");
///
/// // errors can also be created from other errors
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
/// ```
pub fn new<E>(kind: ErrorKind, error: E) -> Error
where E: Into<Box<error::Error+Send+Sync>>
{
Self::_new(kind, error.into())
}
fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
Error {
repr: Repr::Custom(Box::new(Custom {
kind: kind,
error: error,
}))
}
}
/// Returns an error representing the last OS error which occurred.
///
/// This function reads the value of `errno` for the target platform (e.g.
/// `GetLastError` on Windows) and will return a corresponding instance of
/// `Error` for the error code.
///
/// # Examples
///
/// ```
/// use std::io::Error;
///
/// println!("last OS error: {:?}", Error::last_os_error());
/// ```
pub fn last_os_error() -> Error {
Error::from_raw_os_error(sys::os::errno() as i32)
}
/// Creates a new instance of an `Error` from a particular OS error code.
///
/// # Examples
///
/// On Linux:
///
/// ```
/// # if cfg!(target_os = "linux") {
/// use std::io;
///
/// let error = io::Error::from_raw_os_error(98);
/// assert_eq!(error.kind(), io::ErrorKind::AddrInUse);
/// # }
/// ```
///
/// On Windows:
///
/// ```
/// # if cfg!(windows) {
/// use std::io;
///
/// let error = io::Error::from_raw_os_error(10048);
/// assert_eq!(error.kind(), io::ErrorKind::AddrInUse);
/// # }
/// ```
pub fn from_raw_os_error(code: i32) -> Error {
Error { repr: Repr::Os(code) }
}
/// Returns the OS error that this error represents (if any).
///
/// If this `Error` was constructed via `last_os_error` or
/// `from_raw_os_error`, then this function will return `Some`, otherwise
/// it will return `None`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// fn print_os_error(err: &Error) {
/// if let Some(raw_os_err) = err.raw_os_error() {
/// println!("raw OS error: {:?}", raw_os_err);
/// } else {
/// println!("Not an OS error");
/// }
/// }
///
/// fn main() {
/// // Will print "raw OS error: ...".
/// print_os_error(&Error::last_os_error());
/// // Will print "Not an OS error".
/// print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
/// }
/// ```
pub fn raw_os_error(&self) -> Option<i32> {
match self.repr {
Repr::Os(i) => Some(i),
Repr::Custom(..) => None,
}
}
/// Returns a reference to the inner error wrapped by this error (if any).
///
/// If this `Error` was constructed via `new` then this function will
/// return `Some`, otherwise it will return `None`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// fn print_error(err: &Error) {
/// if let Some(inner_err) = err.get_ref() {
/// println!("Inner error: {:?}", inner_err);
/// } else {
/// println!("No inner error");
/// }
/// }
///
/// fn main() {
/// // Will print "No inner error".
/// print_error(&Error::last_os_error());
/// // Will print "Inner error: ...".
/// print_error(&Error::new(ErrorKind::Other, "oh no!"));
/// }
/// ```
pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Custom(ref c) => Some(&*c.error),
}
}
/// Returns a mutable reference to the inner error wrapped by this error
/// (if any).
///
/// If this `Error` was constructed via `new` then this function will
/// return `Some`, otherwise it will return `None`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
/// use std::{error, fmt};
/// use std::fmt::Display;
///
/// #[derive(Debug)]
/// struct MyError {
/// v: String,
/// }
///
/// impl MyError {
/// fn new() -> MyError {
/// MyError {
/// v: "oh no!".to_owned()
/// }
/// }
///
/// fn change_message(&mut self, new_message: &str) {
/// self.v = new_message.to_owned();
/// }
/// }
///
/// impl error::Error for MyError {
/// fn description(&self) -> &str { &self.v }
/// }
///
/// impl Display for MyError {
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// write!(f, "MyError: {}", &self.v)
/// }
/// }
///
/// fn change_error(mut err: Error) -> Error {
/// if let Some(inner_err) = err.get_mut() {
/// inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!");
/// }
/// err
/// }
///
/// fn print_error(err: &Error) {
/// if let Some(inner_err) = err.get_ref() {
/// println!("Inner error: {}", inner_err);
/// } else {
/// println!("No inner error");
/// }
/// }
///
/// fn main() {
/// // Will print "No inner error".
/// print_error(&change_error(Error::last_os_error()));
/// // Will print "Inner error: ...".
/// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new())));
/// }
/// ```
pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Custom(ref mut c) => Some(&mut *c.error),
}
}
/// Consumes the `Error`, returning its inner error (if any).
///
/// If this `Error` was constructed via `new` then this function will
/// return `Some`, otherwise it will return `None`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// fn print_error(err: Error) {
/// if let Some(inner_err) = err.into_inner() {
/// println!("Inner error: {}", inner_err);
/// } else {
/// println!("No inner error");
/// }
/// }
///
/// fn main() {
/// // Will print "No inner error".
/// print_error(Error::last_os_error());
/// // Will print "Inner error: ...".
/// print_error(Error::new(ErrorKind::Other, "oh no!"));
/// }
/// ```
pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
match self.repr {
Repr::Os(..) => None,
Repr::Custom(c) => Some(c.error)
}
}
/// Returns the corresponding `ErrorKind` for this error.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// fn print_error(err: Error) {
/// println!("{:?}", err.kind());
/// }
///
/// fn main() {
/// // Will print "No inner error".
/// print_error(Error::last_os_error());
/// // Will print "Inner error: ...".
/// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
/// }
/// ```
pub fn kind(&self) -> ErrorKind {
match self.repr {
Repr::Os(code) => sys::os::decode_error_kind(code),
Repr::Custom(ref c) => c.kind,
}
}
}
impl fmt::Debug for Repr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
Repr::Os(ref code) =>
fmt.debug_struct("Os").field("code", code)
.field("message", &sys::os::error_string(*code)).finish(),
Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self.repr {
Repr::Os(code) => {
let detail = sys::os::error_string(code);
write!(fmt, "{} (os error {})", detail, code)
}
Repr::Custom(ref c) => c.error.fmt(fmt),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match self.repr {
Repr::Os(..) => match self.kind() {
ErrorKind::NotFound => "entity not found",
ErrorKind::PermissionDenied => "permission denied",
ErrorKind::ConnectionRefused => "connection refused",
ErrorKind::ConnectionReset => "connection reset",
ErrorKind::ConnectionAborted => "connection aborted",
ErrorKind::NotConnected => "not connected",
ErrorKind::AddrInUse => "address in use",
ErrorKind::AddrNotAvailable => "address not available",
ErrorKind::BrokenPipe => "broken pipe",
ErrorKind::AlreadyExists => "entity already exists",
ErrorKind::WouldBlock => "operation would block",
ErrorKind::InvalidInput => "invalid input parameter",
ErrorKind::InvalidData => "invalid data",
ErrorKind::TimedOut => "timed out",
ErrorKind::WriteZero => "write zero",
ErrorKind::Interrupted => "operation interrupted",
ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file",
ErrorKind::__Nonexhaustive => unreachable!()
},
Repr::Custom(ref c) => c.error.description(),
}
}
fn cause(&self) -> Option<&error::Error> {
match self.repr {
Repr::Os(..) => None,
Repr::Custom(ref c) => c.error.cause(),
}
}
}
fn _assert_error_is_sync_send() {
fn _is_sync_send<T: Sync+Send>() {}
_is_sync_send::<Error>();
}
#[cfg(test)]
mod test {
use super::{Error, ErrorKind};
use error;
use core::fmt;
use sys::os::error_string;
#[test]
fn test_debug_error() {
let code = 6;
let msg = error_string(code);
let err = Error { repr: super::Repr::Os(code) };
let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg);
assert_eq!(format!("{:?}", err), expected);
}
#[test]
fn test_downcasting() {
#[derive(Debug)]
struct TestError;
impl fmt::Display for TestError {
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
impl error::Error for TestError {
fn description(&self) -> &str {
"asdf"
}
}
// we have to call all of these UFCS style right now since method
// resolution won't implicitly drop the Send+Sync bounds
let mut err = Error::new(ErrorKind::Other, TestError);
assert!(err.get_ref().unwrap().is::<TestError>());
assert_eq!("asdf", err.get_ref().unwrap().description());
assert!(err.get_mut().unwrap().is::<TestError>());
let extracted = err.into_inner().unwrap();
extracted.downcast::<TestError>().unwrap();
}
}

279
src/io/impls.rs

@ -0,0 +1,279 @@ @@ -0,0 +1,279 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use core::cmp;
use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
use core::fmt;
use core::mem;
use collections::boxed::Box;
use collections::Vec;
use collections::String;
// =============================================================================
// Forwarding implementations
impl<'a, R: Read + ?Sized> Read for &'a mut R {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
#[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
#[inline]
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
(**self).read_to_string(buf)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
(**self).read_exact(buf)
}
}
impl<'a, W: Write + ?Sized> Write for &'a mut W {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
#[inline]
fn flush(&mut self) -> io::Result<()> { (**self).flush() }
#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
(**self).write_all(buf)
}
#[inline]
fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
(**self).write_fmt(fmt)
}
}
impl<'a, S: Seek + ?Sized> Seek for &'a mut S {
#[inline]
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B {
#[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
#[inline]
fn consume(&mut self, amt: usize) { (**self).consume(amt) }
#[inline]
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_until(byte, buf)
}
#[inline]
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
(**self).read_line(buf)
}
}
impl<R: Read + ?Sized> Read for Box<R> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
#[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
#[inline]
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
(**self).read_to_string(buf)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
(**self).read_exact(buf)
}
}
impl<W: Write + ?Sized> Write for Box<W> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
#[inline]
fn flush(&mut self) -> io::Result<()> { (**self).flush() }
#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
(**self).write_all(buf)
}
#[inline]
fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
(**self).write_fmt(fmt)
}
}
impl<S: Seek + ?Sized> Seek for Box<S> {
#[inline]
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
impl<B: BufRead + ?Sized> BufRead for Box<B> {
#[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
#[inline]
fn consume(&mut self, amt: usize) { (**self).consume(amt) }
#[inline]
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_until(byte, buf)
}
#[inline]
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
(**self).read_line(buf)
}
}
// =============================================================================
// In-memory buffer implementations
impl<'a> Read for &'a [u8] {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let amt = cmp::min(buf.len(), self.len());
let (a, b) = self.split_at(amt);
buf[..amt].copy_from_slice(a);
*self = b;
Ok(amt)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.len() {
return Err(Error::new(ErrorKind::UnexpectedEof,
"failed to fill whole buffer"));
}
let (a, b) = self.split_at(buf.len());
buf.copy_from_slice(a);
*self = b;
Ok(())
}
}
impl<'a> BufRead for &'a [u8] {
#[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }
#[inline]
fn consume(&mut self, amt: usize) { *self = &self[amt..]; }
}
impl<'a> Write for &'a mut [u8] {
#[inline]
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
let amt = cmp::min(data.len(), self.len());
let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
a.copy_from_slice(&data[..amt]);
*self = b;
Ok(amt)
}
#[inline]
fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
if self.write(data)? == data.len() {
Ok(())
} else {
Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
}
}
#[inline]
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
impl Write for Vec<u8> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.extend_from_slice(buf);
Ok(buf.len())
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.extend_from_slice(buf);
Ok(())
}
#[inline]
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#[cfg(test)]
mod tests {
use io::prelude::*;
use test;
use collections::Vec;
#[bench]
fn bench_read_slice(b: &mut test::Bencher) {
let buf = [5; 1024];
let mut dst = [0; 128];
b.iter(|| {
let mut rd = &buf[..];
for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
})
}
#[bench]
fn bench_write_slice(b: &mut test::Bencher) {
let mut buf = [0; 1024];
let src = [5; 128];
b.iter(|| {
let mut wr = &mut buf[..];
for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
})
}
#[bench]
fn bench_read_vec(b: &mut test::Bencher) {
let buf = vec![5; 1024];
let mut dst = [0; 128];
b.iter(|| {
let mut rd = &buf[..];
for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
})
}
#[bench]
fn bench_write_vec(b: &mut test::Bencher) {
let mut buf = Vec::with_capacity(1024);
let src = [5; 128];
b.iter(|| {
let mut wr = &mut buf[..];
for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
})
}
}

1887
src/io/mod.rs

File diff suppressed because it is too large Load Diff

22
src/io/prelude.rs

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The I/O Prelude
//!
//! The purpose of this module is to alleviate imports of many common I/O traits
//! by adding a glob import to the top of I/O heavy modules:
//!
//! ```
//! # #![allow(unused_imports)]
//! use std::io::prelude::*;
//! ```
pub use super::{Read, Write, BufRead, Seek};

204
src/io/util.rs

@ -0,0 +1,204 @@ @@ -0,0 +1,204 @@
// Copyright 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.
#![allow(missing_copy_implementations)]
use io::{self, Read, Write, ErrorKind, BufRead};
/// Copies the entire contents of a reader into a writer.
///
/// This function will continuously read data from `reader` and then
/// write it into `writer` in a streaming fashion until `reader`
/// returns EOF.
///
/// On success, the total number of bytes that were copied from
/// `reader` to `writer` is returned.
///
/// # Errors
///
/// This function will return an error immediately if any call to `read` or
/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
/// handled by this function and the underlying operation is retried.
///
/// # Examples
///
/// ```
/// use std::io;
///
/// # fn foo() -> io::Result<()> {
/// let mut reader: &[u8] = b"hello";
/// let mut writer: Vec<u8> = vec![];
///
/// try!(io::copy(&mut reader, &mut writer));
///
/// assert_eq!(reader, &writer[..]);
/// # Ok(())
/// # }
/// ```
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
where R: Read, W: Write
{
let mut buf = [0; super::DEFAULT_BUF_SIZE];
let mut written = 0;
loop {
let len = match reader.read(&mut buf) {
Ok(0) => return Ok(written),
Ok(len) => len,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
};
writer.write_all(&buf[..len])?;
written += len as u64;
}
}
/// A reader which is always at EOF.
///
/// This struct is generally created by calling [`empty()`][empty]. Please see
/// the documentation of `empty()` for more details.
///
/// [empty]: fn.empty.html
pub struct Empty { _priv: () }
/// Constructs a new handle to an empty reader.
///
/// All reads from the returned reader will return `Ok(0)`.
///
/// # Examples
///
/// A slightly sad example of not reading anything into a buffer:
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
pub fn empty() -> Empty { Empty { _priv: () } }
impl Read for Empty {
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
}
impl BufRead for Empty {
fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
fn consume(&mut self, _n: usize) {}
}
/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat()`][repeat]. Please
/// see the documentation of `repeat()` for more details.
///
/// [repeat]: fn.repeat.html
pub struct Repeat { byte: u8 }
/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }
impl Read for Repeat {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
for slot in &mut *buf {
*slot = self.byte;
}
Ok(buf.len())
}
}
/// A writer which will move data into the void.
///
/// This struct is generally created by calling [`sink()`][sink]. Please
/// see the documentation of `sink()` for more details.
///
/// [sink]: fn.sink.html
pub struct Sink { _priv: () }
/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to `write` on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
///
/// # Examples
///
/// ```rust
/// use std::io::{self, Write};
///
/// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
pub fn sink() -> Sink { Sink { _priv: () } }
impl Write for Sink {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#[cfg(test)]
mod tests {
use io::prelude::*;
use io::{copy, sink, empty, repeat};
#[test]
fn copy_copies() {
let mut r = repeat(0).take(4);
let mut w = sink();
assert_eq!(copy(&mut r, &mut w).unwrap(), 4);
let mut r = repeat(0).take(1 << 17);
assert_eq!(copy(&mut r as &mut Read, &mut w as &mut Write).unwrap(), 1 << 17);
}
#[test]
fn sink_sinks() {
let mut s = sink();
assert_eq!(s.write(&[]).unwrap(), 0);
assert_eq!(s.write(&[0]).unwrap(), 1);
assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
}
#[test]
fn empty_reads() {
let mut e = empty();
assert_eq!(e.read(&mut []).unwrap(), 0);
assert_eq!(e.read(&mut [0]).unwrap(), 0);
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0);
}
#[test]
fn repeat_repeats() {
let mut r = repeat(4);
let mut b = [0; 1024];
assert_eq!(r.read(&mut b).unwrap(), 1024);
assert!(b.iter().all(|b| *b == 4));
}
#[test]
fn take_some_bytes() {
assert_eq!(repeat(4).take(100).bytes().count(), 100);
assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
}
}

4
src/lib.rs

@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
extern crate alloc;
extern crate alloc_system;
extern crate collections;
#[macro_use] extern crate collections;
extern crate rustc_unicode;
extern crate ctru_sys as libctru;
@ -31,6 +31,8 @@ pub mod sdmc; @@ -31,6 +31,8 @@ pub mod sdmc;
pub mod ascii;
pub mod error;
pub mod ffi;
pub mod io;
pub mod memchr;
pub mod panic;
pub mod path;

2
src/memchr.rs

@ -67,7 +67,7 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { @@ -67,7 +67,7 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
/// ```
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
use libc;
use libctru::libc;
// GNU's memrchr() will - unlike memchr() - error if haystack is empty.
if haystack.is_empty() {

1
src/sys/mod.rs

@ -22,4 +22,5 @@ pub trait FromInner<Inner> { @@ -22,4 +22,5 @@ pub trait FromInner<Inner> {
fn from_inner(inner: Inner) -> Self;
}
pub mod os;
pub mod wtf8;

78
src/sys/os.rs

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
use libctru::libc;
use io::ErrorKind;
use collections::{str, String};
use collections::borrow::ToOwned;
use ffi::CStr;
const TMPBUF_SZ: usize = 128;
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as libc::c_int {
libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
libc::ECONNRESET => ErrorKind::ConnectionReset,
libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
libc::EPIPE => ErrorKind::BrokenPipe,
libc::ENOTCONN => ErrorKind::NotConnected,
libc::ECONNABORTED => ErrorKind::ConnectionAborted,
libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
libc::EADDRINUSE => ErrorKind::AddrInUse,
libc::ENOENT => ErrorKind::NotFound,
libc::EINTR => ErrorKind::Interrupted,
libc::EINVAL => ErrorKind::InvalidInput,
libc::ETIMEDOUT => ErrorKind::TimedOut,
libc::EEXIST => ErrorKind::AlreadyExists,
// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
// clause
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => ErrorKind::WouldBlock,
_ => ErrorKind::Other,
}
}
extern "C" {
#[cfg(not(target_os = "dragonfly"))]
#[cfg_attr(any(target_os = "linux", target_os = "emscripten"),
link_name = "__errno_location")]
#[cfg_attr(any(target_os = "bitrig",
target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
target_env = "newlib"),
link_name = "__errno")]
#[cfg_attr(target_os = "solaris", link_name = "___errno")]
#[cfg_attr(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd"),
link_name = "__error")]
fn errno_location() -> *mut libc::c_int;
}
pub fn errno() -> i32 {
unsafe { (*errno_location()) as i32 }
}
/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
extern "C" {
#[cfg_attr(any(target_os = "linux", target_env = "newlib"),
link_name = "__xpg_strerror_r")]
fn strerror_r(errnum: libc::c_int,
buf: *mut libc::c_char,
buflen: libc::size_t)
-> libc::c_int;
}
let mut buf = [0 as libc::c_char; TMPBUF_SZ];
let p = buf.as_mut_ptr();
unsafe {
if strerror_r(errno as libc::c_int, p, buf.len() as libc::size_t) < 0 {
panic!("strerror_r failure");
}
let p = p as *const _;
str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
}
}
Loading…
Cancel
Save