Browse Source

implement buffered stdio

pull/10/head
Fenrir 8 years ago
parent
commit
3f2366df13
  1. 68
      ctr-std/src/io/lazy.rs
  2. 183
      ctr-std/src/io/mod.rs
  3. 33
      ctr-std/src/io/print.rs
  4. 722
      ctr-std/src/io/stdio.rs
  5. 1
      ctr-std/src/lib.rs
  6. 9
      ctr-std/src/panicking.rs
  7. 137
      ctr-std/src/sys/unix/fd.rs
  8. 81
      ctr-std/src/sys/unix/io.rs
  9. 2
      ctr-std/src/sys/unix/mod.rs
  10. 81
      ctr-std/src/sys/unix/stdio.rs
  11. 80
      ctr-std/src/sys_common/at_exit_imp.rs
  12. 15
      ctr-std/src/sys_common/mod.rs

68
ctr-std/src/io/lazy.rs

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
// 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 cell::Cell;
use ptr;
use sync::Arc;
use sys_common;
use sys_common::mutex::Mutex;
pub struct Lazy<T> {
lock: Mutex,
ptr: Cell<*mut Arc<T>>,
init: fn() -> Arc<T>,
}
unsafe impl<T> Sync for Lazy<T> {}
impl<T: Send + Sync + 'static> Lazy<T> {
pub const fn new(init: fn() -> Arc<T>) -> Lazy<T> {
Lazy {
lock: Mutex::new(),
ptr: Cell::new(ptr::null_mut()),
init: init
}
}
pub fn get(&'static self) -> Option<Arc<T>> {
unsafe {
self.lock.lock();
let ptr = self.ptr.get();
let ret = if ptr.is_null() {
Some(self.init())
} else if ptr as usize == 1 {
None
} else {
Some((*ptr).clone())
};
self.lock.unlock();
return ret
}
}
unsafe fn init(&'static self) -> Arc<T> {
// If we successfully register an at exit handler, then we cache the
// `Arc` allocation in our own internal box (it will get deallocated by
// the at exit handler). Otherwise we just return the freshly allocated
// `Arc`.
let registered = sys_common::at_exit(move || {
self.lock.lock();
let ptr = self.ptr.get();
self.ptr.set(1 as *mut _);
self.lock.unlock();
drop(Box::from_raw(ptr))
});
let ret = (self.init)();
if registered.is_ok() {
self.ptr.set(Box::into_raw(Box::new(ret.clone())));
}
ret
}
}

183
ctr-std/src/io/mod.rs

@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
//! of other types, and you can implement them for your types too. As such,
//! you'll see a few different types of I/O throughout the documentation in
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
//! example, `Read` adds a `read()` method, which we can use on `File`s:
//! example, [`Read`] adds a [`read()`] method, which we can use on `File`s:
//!
//! ```
//! use std::io;
@ -29,11 +29,11 @@ @@ -29,11 +29,11 @@
//! use std::fs::File;
//!
//! # fn foo() -> io::Result<()> {
//! let mut f = try!(File::open("foo.txt"));
//! let mut f = File::open("foo.txt")?;
//! let mut buffer = [0; 10];
//!
//! // read up to 10 bytes
//! try!(f.read(&mut buffer));
//! f.read(&mut buffer)?;
//!
//! println!("The bytes: {:?}", buffer);
//! # Ok(())
@ -58,14 +58,14 @@ @@ -58,14 +58,14 @@
//! use std::fs::File;
//!
//! # fn foo() -> io::Result<()> {
//! let mut f = try!(File::open("foo.txt"));
//! let mut f = File::open("foo.txt")?;
//! let mut buffer = [0; 10];
//!
//! // skip to the last 10 bytes of the file
//! try!(f.seek(SeekFrom::End(-10)));
//! f.seek(SeekFrom::End(-10))?;
//!
//! // read up to 10 bytes
//! try!(f.read(&mut buffer));
//! f.read(&mut buffer)?;
//!
//! println!("The bytes: {:?}", buffer);
//! # Ok(())
@ -93,12 +93,12 @@ @@ -93,12 +93,12 @@
//! use std::fs::File;
//!
//! # fn foo() -> io::Result<()> {
//! let f = try!(File::open("foo.txt"));
//! let f = File::open("foo.txt")?;
//! let mut reader = BufReader::new(f);
//! let mut buffer = String::new();
//!
//! // read a line into buffer
//! try!(reader.read_line(&mut buffer));
//! reader.read_line(&mut buffer)?;
//!
//! println!("{}", buffer);
//! # Ok(())
@ -115,12 +115,12 @@ @@ -115,12 +115,12 @@
//! use std::fs::File;
//!
//! # fn foo() -> io::Result<()> {
//! let f = try!(File::create("foo.txt"));
//! let f = File::create("foo.txt")?;
//! {
//! let mut writer = BufWriter::new(f);
//!
//! // write a byte to the buffer
//! try!(writer.write(&[42]));
//! writer.write(&[42])?;
//!
//! } // the buffer is flushed once writer goes out of scope
//!
@ -138,7 +138,7 @@ @@ -138,7 +138,7 @@
//! # fn foo() -> io::Result<()> {
//! let mut input = String::new();
//!
//! try!(io::stdin().read_line(&mut input));
//! io::stdin().read_line(&mut input)?;
//!
//! println!("You typed: {}", input.trim());
//! # Ok(())
@ -152,7 +152,7 @@ @@ -152,7 +152,7 @@
//! use std::io::prelude::*;
//!
//! # fn foo() -> io::Result<()> {
//! try!(io::stdout().write(&[42]));
//! io::stdout().write(&[42])?;
//! # Ok(())
//! # }
//! ```
@ -173,11 +173,11 @@ @@ -173,11 +173,11 @@
//! use std::fs::File;
//!
//! # fn foo() -> io::Result<()> {
//! let f = try!(File::open("foo.txt"));
//! let f = File::open("foo.txt")?;
//! let reader = BufReader::new(f);
//!
//! for line in reader.lines() {
//! println!("{}", try!(line));
//! println!("{}", line?);
//! }
//!
//! # Ok(())
@ -194,7 +194,7 @@ @@ -194,7 +194,7 @@
//! use std::io;
//!
//! # fn foo() -> io::Result<()> {
//! try!(io::copy(&mut io::stdin(), &mut io::stdout()));
//! io::copy(&mut io::stdin(), &mut io::stdout())?;
//! # Ok(())
//! # }
//! ```
@ -206,7 +206,7 @@ @@ -206,7 +206,7 @@
//! Last, but certainly not least, is [`io::Result`]. This type is used
//! as the return type of many `std::io` functions that can cause an error, and
//! can be returned from your own functions as well. Many of the examples in this
//! module use the [`try!`] macro:
//! module use the [`?` operator]:
//!
//! ```
//! use std::io;
@ -214,7 +214,7 @@ @@ -214,7 +214,7 @@
//! fn read_input() -> io::Result<()> {
//! let mut input = String::new();
//!
//! try!(io::stdin().read_line(&mut input));
//! io::stdin().read_line(&mut input)?;
//!
//! println!("You typed: {}", input.trim());
//!
@ -250,7 +250,8 @@ @@ -250,7 +250,8 @@
//! [`println!`]: ../macro.println.html
//! [`Lines`]: struct.Lines.html
//! [`io::Result`]: type.Result.html
//! [`try!`]: ../macro.try.html
//! [`?` operator]: ../../book/syntax-index.html
//! [`read()`]: trait.Read.html#tymethod.read
#![stable(feature = "rust1", since = "1.0.0")]
@ -273,16 +274,21 @@ pub use self::error::{Result, Error, ErrorKind}; @@ -273,16 +274,21 @@ pub use self::error::{Result, Error, ErrorKind};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::print::{STDOUT, _print};
pub use self::stdio::{stdin, stdout, stderr, _print, Stdin, Stdout, Stderr};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::stdio::{StdoutLock, StderrLock, StdinLock};
#[unstable(feature = "libstd_io_internals", issue = "0")]
#[doc(no_inline, hidden)]
pub use self::stdio::{set_panic, set_print};
pub mod prelude;
mod buffered;
mod cursor;
mod error;
mod impls;
mod lazy;
mod util;
mod print;
mod stdio;
const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
@ -399,19 +405,19 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> @@ -399,19 +405,19 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
/// let mut buffer = [0; 10];
///
/// // read up to 10 bytes
/// try!(f.read(&mut buffer));
/// f.read(&mut buffer)?;
///
/// let mut buffer = vec![0; 10];
/// // read the whole file
/// try!(f.read_to_end(&mut buffer));
/// f.read_to_end(&mut buffer)?;
///
/// // read into a String, so that you don't need to do the conversion.
/// let mut buffer = String::new();
/// try!(f.read_to_string(&mut buffer));
/// f.read_to_string(&mut buffer)?;
///
/// // and more! See the other methods for more details.
/// # Ok(())
@ -459,11 +465,11 @@ pub trait Read { @@ -459,11 +465,11 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
/// let mut buffer = [0; 10];
///
/// // read 10 bytes
/// try!(f.read(&mut buffer[..]));
/// f.read(&mut buffer[..])?;
/// # Ok(())
/// # }
/// ```
@ -501,11 +507,11 @@ pub trait Read { @@ -501,11 +507,11 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
/// let mut buffer = Vec::new();
///
/// // read the whole file
/// try!(f.read_to_end(&mut buffer));
/// f.read_to_end(&mut buffer)?;
/// # Ok(())
/// # }
/// ```
@ -540,10 +546,10 @@ pub trait Read { @@ -540,10 +546,10 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
/// let mut buffer = String::new();
///
/// try!(f.read_to_string(&mut buffer));
/// f.read_to_string(&mut buffer)?;
/// # Ok(())
/// # }
/// ```
@ -600,11 +606,11 @@ pub trait Read { @@ -600,11 +606,11 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
/// let mut buffer = [0; 10];
///
/// // read exactly 10 bytes
/// try!(f.read_exact(&mut buffer));
/// f.read_exact(&mut buffer)?;
/// # Ok(())
/// # }
/// ```
@ -643,7 +649,7 @@ pub trait Read { @@ -643,7 +649,7 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
/// let mut buffer = Vec::new();
/// let mut other_buffer = Vec::new();
///
@ -651,12 +657,12 @@ pub trait Read { @@ -651,12 +657,12 @@ pub trait Read {
/// let reference = f.by_ref();
///
/// // read at most 5 bytes
/// try!(reference.take(5).read_to_end(&mut buffer));
/// reference.take(5).read_to_end(&mut buffer)?;
///
/// } // drop our &mut reference so we can use f again
///
/// // original file still usable, read the rest
/// try!(f.read_to_end(&mut other_buffer));
/// f.read_to_end(&mut other_buffer)?;
/// # Ok(())
/// # }
/// ```
@ -682,7 +688,7 @@ pub trait Read { @@ -682,7 +688,7 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
///
/// for byte in f.bytes() {
/// println!("{}", byte.unwrap());
@ -719,7 +725,7 @@ pub trait Read { @@ -719,7 +725,7 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
///
/// for c in f.chars() {
/// println!("{}", c.unwrap());
@ -753,15 +759,15 @@ pub trait Read { @@ -753,15 +759,15 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f1 = try!(File::open("foo.txt"));
/// let mut f2 = try!(File::open("bar.txt"));
/// let mut f1 = File::open("foo.txt")?;
/// let mut f2 = File::open("bar.txt")?;
///
/// let mut handle = f1.chain(f2);
/// let mut buffer = String::new();
///
/// // read the value into a String. We could use any Read method here,
/// // this is just one example.
/// try!(handle.read_to_string(&mut buffer));
/// handle.read_to_string(&mut buffer)?;
/// # Ok(())
/// # }
/// ```
@ -789,13 +795,13 @@ pub trait Read { @@ -789,13 +795,13 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
/// let mut buffer = [0; 5];
///
/// // read at most five bytes
/// let mut handle = f.take(5);
///
/// try!(handle.read(&mut buffer));
/// handle.read(&mut buffer)?;
/// # Ok(())
/// # }
/// ```
@ -809,19 +815,23 @@ pub trait Read { @@ -809,19 +815,23 @@ pub trait Read {
///
/// Implementors of the `Write` trait are sometimes called 'writers'.
///
/// Writers are defined by two required methods, `write()` and `flush()`:
/// Writers are defined by two required methods, [`write()`] and [`flush()`]:
///
/// * The `write()` method will attempt to write some data into the object,
/// * The [`write()`] method will attempt to write some data into the object,
/// returning how many bytes were successfully written.
///
/// * The `flush()` method is useful for adaptors and explicit buffers
/// * The [`flush()`] method is useful for adaptors and explicit buffers
/// themselves for ensuring that all buffered data has been pushed out to the
/// 'true sink'.
///
/// Writers are intended to be composable with one another. Many implementors
/// throughout `std::io` take and provide types which implement the `Write`
/// throughout [`std::io`] take and provide types which implement the `Write`
/// trait.
///
/// [`write()`]: #tymethod.write
/// [`flush()`]: #tymethod.flush
/// [`std::io`]: index.html
///
/// # Examples
///
/// ```
@ -829,9 +839,9 @@ pub trait Read { @@ -829,9 +839,9 @@ pub trait Read {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
/// let mut buffer = try!(File::create("foo.txt"));
/// let mut buffer = File::create("foo.txt")?;
///
/// try!(buffer.write(b"some bytes"));
/// buffer.write(b"some bytes")?;
/// # Ok(())
/// # }
/// ```
@ -869,9 +879,9 @@ pub trait Write { @@ -869,9 +879,9 @@ pub trait Write {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
/// let mut buffer = try!(File::create("foo.txt"));
/// let mut buffer = File::create("foo.txt")?;
///
/// try!(buffer.write(b"some bytes"));
/// buffer.write(b"some bytes")?;
/// # Ok(())
/// # }
/// ```
@ -894,10 +904,10 @@ pub trait Write { @@ -894,10 +904,10 @@ pub trait Write {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
/// let mut buffer = BufWriter::new(try!(File::create("foo.txt")));
/// let mut buffer = BufWriter::new(File::create("foo.txt")?);
///
/// try!(buffer.write(b"some bytes"));
/// try!(buffer.flush());
/// buffer.write(b"some bytes")?;
/// buffer.flush()?;
/// # Ok(())
/// # }
/// ```
@ -922,9 +932,9 @@ pub trait Write { @@ -922,9 +932,9 @@ pub trait Write {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
/// let mut buffer = try!(File::create("foo.txt"));
/// let mut buffer = File::create("foo.txt")?;
///
/// try!(buffer.write_all(b"some bytes"));
/// buffer.write_all(b"some bytes")?;
/// # Ok(())
/// # }
/// ```
@ -971,12 +981,12 @@ pub trait Write { @@ -971,12 +981,12 @@ pub trait Write {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
/// let mut buffer = try!(File::create("foo.txt"));
/// let mut buffer = File::create("foo.txt")?;
///
/// // this call
/// try!(write!(buffer, "{:.*}", 2, 1.234567));
/// write!(buffer, "{:.*}", 2, 1.234567)?;
/// // turns into this:
/// try!(buffer.write_fmt(format_args!("{:.*}", 2, 1.234567)));
/// buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))?;
/// # Ok(())
/// # }
/// ```
@ -1027,12 +1037,12 @@ pub trait Write { @@ -1027,12 +1037,12 @@ pub trait Write {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
/// let mut buffer = try!(File::create("foo.txt"));
/// let mut buffer = File::create("foo.txt")?;
///
/// let reference = buffer.by_ref();
///
/// // we can use reference just like our original buffer
/// try!(reference.write_all(b"some bytes"));
/// reference.write_all(b"some bytes")?;
/// # Ok(())
/// # }
/// ```
@ -1059,10 +1069,10 @@ pub trait Write { @@ -1059,10 +1069,10 @@ pub trait Write {
/// use std::io::SeekFrom;
///
/// # fn foo() -> io::Result<()> {
/// let mut f = try!(File::open("foo.txt"));
/// let mut f = File::open("foo.txt")?;
///
/// // move the cursor 42 bytes from the start of the file
/// try!(f.seek(SeekFrom::Start(42)));
/// f.seek(SeekFrom::Start(42))?;
/// # Ok(())
/// # }
/// ```
@ -1183,7 +1193,7 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) @@ -1183,7 +1193,7 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let f = try!(File::open("foo.txt"));
/// let f = File::open("foo.txt")?;
/// let f = BufReader::new(f);
///
/// for line in f.lines() {
@ -1297,7 +1307,7 @@ pub trait BufRead: Read { @@ -1297,7 +1307,7 @@ pub trait BufRead: Read {
/// let mut stdin = stdin.lock();
/// let mut buffer = Vec::new();
///
/// try!(stdin.read_until(b'a', &mut buffer));
/// stdin.read_until(b'a', &mut buffer)?;
///
/// println!("{:?}", buffer);
/// # Ok(())
@ -1415,6 +1425,12 @@ pub trait BufRead: Read { @@ -1415,6 +1425,12 @@ pub trait BufRead: Read {
/// println!("{}", line.unwrap());
/// }
/// ```
///
/// # Errors
///
/// Each line of the iterator has the same error semantics as [`BufRead::read_line()`].
///
/// [`BufRead::read_line()`]: trait.BufRead.html#method.read_line
#[stable(feature = "rust1", since = "1.0.0")]
fn lines(self) -> Lines<Self> where Self: Sized {
Lines { buf: self }
@ -1434,6 +1450,16 @@ pub struct Chain<T, U> { @@ -1434,6 +1450,16 @@ pub struct Chain<T, U> {
done_first: bool,
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Chain")
.field("t", &self.first)
.field("u", &self.second)
.finish()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Read, U: Read> Read for Chain<T, U> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
@ -1470,11 +1496,12 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> { @@ -1470,11 +1496,12 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
/// Reader adaptor which limits the bytes read from an underlying reader.
///
/// This struct is generally created by calling [`take()`][take] on a reader.
/// Please see the documentation of `take()` for more details.
/// This struct is generally created by calling [`take()`] on a reader.
/// Please see the documentation of [`take()`] for more details.
///
/// [take]: trait.Read.html#method.take
/// [`take()`]: trait.Read.html#method.take
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Take<T> {
inner: T,
limit: u64,
@ -1486,8 +1513,10 @@ impl<T> Take<T> { @@ -1486,8 +1513,10 @@ impl<T> Take<T> {
///
/// # Note
///
/// This instance may reach EOF after reading fewer bytes than indicated by
/// this method if the underlying `Read` instance reaches EOF.
/// This instance may reach `EOF` after reading fewer bytes than indicated by
/// this method if the underlying [`Read`] instance reaches EOF.
///
/// [`Read`]: ../../std/io/trait.Read.html
///
/// # Examples
///
@ -1497,7 +1526,7 @@ impl<T> Take<T> { @@ -1497,7 +1526,7 @@ impl<T> Take<T> {
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let f = try!(File::open("foo.txt"));
/// let f = File::open("foo.txt")?;
///
/// // read at most five bytes
/// let handle = f.take(5);
@ -1514,24 +1543,22 @@ impl<T> Take<T> { @@ -1514,24 +1543,22 @@ impl<T> Take<T> {
/// # Examples
///
/// ```
/// #![feature(io_take_into_inner)]
///
/// use std::io;
/// use std::io::prelude::*;
/// use std::fs::File;
///
/// # fn foo() -> io::Result<()> {
/// let mut file = try!(File::open("foo.txt"));
/// let mut file = File::open("foo.txt")?;
///
/// let mut buffer = [0; 5];
/// let mut handle = file.take(5);
/// try!(handle.read(&mut buffer));
/// handle.read(&mut buffer)?;
///
/// let file = handle.into_inner();
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "io_take_into_inner", issue = "23755")]
#[stable(feature = "io_take_into_inner", since = "1.15.0")]
pub fn into_inner(self) -> T {
self.inner
}
@ -1592,6 +1619,7 @@ fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> { @@ -1592,6 +1619,7 @@ fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> {
///
/// [`bytes()`]: trait.Read.html#method.bytes
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Bytes<R> {
inner: R,
}
@ -1613,6 +1641,7 @@ impl<R: Read> Iterator for Bytes<R> { @@ -1613,6 +1641,7 @@ impl<R: Read> Iterator for Bytes<R> {
/// [chars]: trait.Read.html#method.chars
#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
issue = "27802")]
#[derive(Debug)]
pub struct Chars<R> {
inner: R,
}
@ -1702,6 +1731,7 @@ impl fmt::Display for CharsError { @@ -1702,6 +1731,7 @@ impl fmt::Display for CharsError {
///
/// [split]: trait.BufRead.html#method.split
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Split<B> {
buf: B,
delim: u8,
@ -1733,6 +1763,7 @@ impl<B: BufRead> Iterator for Split<B> { @@ -1733,6 +1763,7 @@ impl<B: BufRead> Iterator for Split<B> {
///
/// [lines]: trait.BufRead.html#method.lines
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Lines<B> {
buf: B,
}

33
ctr-std/src/io/print.rs

@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
use fmt;
use io::{self, Write};
// NOTE: We're just gonna use the spin mutex until we figure out how to properly
// implement mutexes with ctrulib functions
use spin::Mutex;
use libc;
pub static STDOUT: Mutex<StdoutRaw> = Mutex::new(StdoutRaw(()));
pub struct StdoutRaw(());
#[stable(feature = "3ds", since = "1.0.0")]
impl Write for StdoutRaw {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
unsafe {
// devkitPro's version of write(2) fails if zero bytes are written,
// so let's just exit if the buffer size is zero
if buf.is_empty() {
return Ok(buf.len())
}
libc::write(libc::STDOUT_FILENO, buf.as_ptr() as *const _, buf.len());
Ok(buf.len())
}
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
STDOUT.lock().write_fmt(args).unwrap();
}

722
ctr-std/src/io/stdio.rs

@ -0,0 +1,722 @@ @@ -0,0 +1,722 @@
// 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 cell::RefCell;
use fmt;
use io::lazy::Lazy;
use io::{self, BufReader, LineWriter};
use sync::{Arc, Mutex, MutexGuard};
use sys::stdio;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
use thread::LocalKeyState;
/// Stdout used by print! and println! macros
thread_local! {
static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = {
RefCell::new(None)
}
}
/// A handle to a raw instance of the standard input stream of this process.
///
/// This handle is not synchronized or buffered in any fashion. Constructed via
/// the `std::io::stdio::stdin_raw` function.
struct StdinRaw(stdio::Stdin);
/// A handle to a raw instance of the standard output stream of this process.
///
/// This handle is not synchronized or buffered in any fashion. Constructed via
/// the `std::io::stdio::stdout_raw` function.
struct StdoutRaw(stdio::Stdout);
/// A handle to a raw instance of the standard output stream of this process.
///
/// This handle is not synchronized or buffered in any fashion. Constructed via
/// the `std::io::stdio::stderr_raw` function.
struct StderrRaw(stdio::Stderr);
/// Constructs a new raw handle to the standard input of this process.
///
/// The returned handle does not interact with any other handles created nor
/// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin`
/// handles is **not** available to raw handles returned from this function.
///
/// The returned handle has no external synchronization or buffering.
fn stdin_raw() -> io::Result<StdinRaw> { stdio::Stdin::new().map(StdinRaw) }
/// Constructs a new raw handle to the standard output stream of this process.
///
/// The returned handle does not interact with any other handles created nor
/// handles returned by `std::io::stdout`. Note that data is buffered by the
/// `std::io::stdout` handles so writes which happen via this raw handle may
/// appear before previous writes.
///
/// The returned handle has no external synchronization or buffering layered on
/// top.
fn stdout_raw() -> io::Result<StdoutRaw> { stdio::Stdout::new().map(StdoutRaw) }
/// Constructs a new raw handle to the standard error stream of this process.
///
/// The returned handle does not interact with any other handles created nor
/// handles returned by `std::io::stderr`.
///
/// The returned handle has no external synchronization or buffering layered on
/// top.
fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
impl Read for StdinRaw {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.0.read_to_end(buf)
}
}
impl Write for StdoutRaw {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
fn flush(&mut self) -> io::Result<()> { self.0.flush() }
}
impl Write for StderrRaw {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
fn flush(&mut self) -> io::Result<()> { self.0.flush() }
}
enum Maybe<T> {
Real(T),
Fake,
}
impl<W: io::Write> io::Write for Maybe<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match *self {
Maybe::Real(ref mut w) => handle_ebadf(w.write(buf), buf.len()),
Maybe::Fake => Ok(buf.len())
}
}
fn flush(&mut self) -> io::Result<()> {
match *self {
Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()),
Maybe::Fake => Ok(())
}
}
}
impl<R: io::Read> io::Read for Maybe<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match *self {
Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), 0),
Maybe::Fake => Ok(0)
}
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
match *self {
Maybe::Real(ref mut r) => handle_ebadf(r.read_to_end(buf), 0),
Maybe::Fake => Ok(0)
}
}
}
fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
use sys::stdio::EBADF_ERR;
match r {
Err(ref e) if e.raw_os_error() == Some(EBADF_ERR) => Ok(default),
r => r
}
}
/// A handle to the standard input stream of a process.
///
/// Each handle is a shared reference to a global buffer of input data to this
/// process. A handle can be `lock`'d to gain full access to [`BufRead`] methods
/// (e.g. `.lines()`). Reads to this handle are otherwise locked with respect
/// to other reads.
///
/// This handle implements the `Read` trait, but beware that concurrent reads
/// of `Stdin` must be executed with care.
///
/// Created by the [`io::stdin`] method.
///
/// [`io::stdin`]: fn.stdin.html
/// [`BufRead`]: trait.BufRead.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stdin {
inner: Arc<Mutex<BufReader<Maybe<StdinRaw>>>>,
}
/// A locked reference to the `Stdin` handle.
///
/// This handle implements both the [`Read`] and [`BufRead`] traits, and
/// is constructed via the [`Stdin::lock`] method.
///
/// [`Read`]: trait.Read.html
/// [`BufRead`]: trait.BufRead.html
/// [`Stdin::lock`]: struct.Stdin.html#method.lock
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StdinLock<'a> {
inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>,
}
/// Constructs a new handle to the standard input of the current process.
///
/// Each handle returned is a reference to a shared global buffer whose access
/// is synchronized via a mutex. If you need more explicit control over
/// locking, see the [`lock() method`][lock].
///
/// [lock]: struct.Stdin.html#method.lock
///
/// # Examples
///
/// Using implicit synchronization:
///
/// ```
/// use std::io::{self, Read};
///
/// # fn foo() -> io::Result<String> {
/// let mut buffer = String::new();
/// io::stdin().read_to_string(&mut buffer)?;
/// # Ok(buffer)
/// # }
/// ```
///
/// Using explicit synchronization:
///
/// ```
/// use std::io::{self, Read};
///
/// # fn foo() -> io::Result<String> {
/// let mut buffer = String::new();
/// let stdin = io::stdin();
/// let mut handle = stdin.lock();
///
/// handle.read_to_string(&mut buffer)?;
/// # Ok(buffer)
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin {
static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init);
return Stdin {
inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
};
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
let stdin = match stdin_raw() {
Ok(stdin) => Maybe::Real(stdin),
_ => Maybe::Fake
};
Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin)))
}
}
impl Stdin {
/// Locks this handle to the standard input stream, returning a readable
/// guard.
///
/// The lock is released when the returned lock goes out of scope. The
/// returned guard also implements the [`Read`] and [`BufRead`] traits for
/// accessing the underlying data.
///
/// [`Read`]: trait.Read.html
/// [`BufRead`]: trait.BufRead.html
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// # fn foo() -> io::Result<String> {
/// let mut buffer = String::new();
/// let stdin = io::stdin();
/// let mut handle = stdin.lock();
///
/// handle.read_to_string(&mut buffer)?;
/// # Ok(buffer)
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn lock(&self) -> StdinLock {
StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
}
/// Locks this handle and reads a line of input into the specified buffer.
///
/// For detailed semantics of this method, see the documentation on
/// [`BufRead::read_line`].
///
/// [`BufRead::read_line`]: trait.BufRead.html#method.read_line
///
/// # Examples
///
/// ```no_run
/// use std::io;
///
/// let mut input = String::new();
/// match io::stdin().read_line(&mut input) {
/// Ok(n) => {
/// println!("{} bytes read", n);
/// println!("{}", input);
/// }
/// Err(error) => println!("error: {}", error),
/// }
/// ```
///
/// You can run the example one of two ways:
///
/// - Pipe some text to it, e.g. `printf foo | path/to/executable`
/// - Give it text interactively by running the executable directly,
/// in which case it will wait for the Enter key to be pressed before
/// continuing
#[stable(feature = "rust1", since = "1.0.0")]
pub fn read_line(&self, buf: &mut String) -> io::Result<usize> {
self.lock().read_line(buf)
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Stdin {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Stdin { .. }")
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.lock().read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.lock().read_to_end(buf)
}
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.lock().read_to_string(buf)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.lock().read_exact(buf)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Read for StdinLock<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.inner.read_to_end(buf)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> BufRead for StdinLock<'a> {
fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
fn consume(&mut self, n: usize) { self.inner.consume(n) }
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a> fmt::Debug for StdinLock<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("StdinLock { .. }")
}
}
/// A handle to the global standard output stream of the current process.
///
/// Each handle shares a global buffer of data to be written to the standard
/// output stream. Access is also synchronized via a lock and explicit control
/// over locking is available via the [`lock()`] method.
///
/// Created by the [`io::stdout`] method.
///
/// [`lock()`]: #method.lock
/// [`io::stdout`]: fn.stdout.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stdout {
// FIXME: this should be LineWriter or BufWriter depending on the state of
// stdout (tty or not). Note that if this is not line buffered it
// should also flush-on-panic or some form of flush-on-abort.
inner: Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>,
}
/// A locked reference to the `Stdout` handle.
///
/// This handle implements the [`Write`] trait, and is constructed via
/// the [`Stdout::lock`] method.
///
/// [`Write`]: trait.Write.html
/// [`Stdout::lock`]: struct.Stdout.html#method.lock
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StdoutLock<'a> {
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>,
}
/// Constructs a new handle to the standard output of the current process.
///
/// Each handle returned is a reference to a shared global buffer whose access
/// is synchronized via a mutex. If you need more explicit control over
/// locking, see the [Stdout::lock] method.
///
/// [Stdout::lock]: struct.Stdout.html#method.lock
///
/// # Examples
///
/// Using implicit synchronization:
///
/// ```
/// use std::io::{self, Write};
///
/// # fn foo() -> io::Result<()> {
/// io::stdout().write(b"hello world")?;
///
/// # Ok(())
/// # }
/// ```
///
/// Using explicit synchronization:
///
/// ```
/// use std::io::{self, Write};
///
/// # fn foo() -> io::Result<()> {
/// let stdout = io::stdout();
/// let mut handle = stdout.lock();
///
/// handle.write(b"hello world")?;
///
/// # Ok(())
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
= Lazy::new(stdout_init);
return Stdout {
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
};
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
let stdout = match stdout_raw() {
Ok(stdout) => Maybe::Real(stdout),
_ => Maybe::Fake,
};
Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout))))
}
}
impl Stdout {
/// Locks this handle to the standard output stream, returning a writable
/// guard.
///
/// The lock is released when the returned lock goes out of scope. The
/// returned guard also implements the `Write` trait for writing data.
///
/// # Examples
///
/// ```
/// use std::io::{self, Write};
///
/// # fn foo() -> io::Result<()> {
/// let stdout = io::stdout();
/// let mut handle = stdout.lock();
///
/// handle.write(b"hello world")?;
///
/// # Ok(())
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn lock(&self) -> StdoutLock {
StdoutLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Stdout {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Stdout { .. }")
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.lock().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.lock().flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> {
self.lock().write_fmt(args)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for StdoutLock<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.borrow_mut().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.borrow_mut().flush()
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a> fmt::Debug for StdoutLock<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("StdoutLock { .. }")
}
}
/// A handle to the standard error stream of a process.
///
/// For more information, see the [`io::stderr`] method.
///
/// [`io::stderr`]: fn.stderr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stderr {
inner: Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>>,
}
/// A locked reference to the `Stderr` handle.
///
/// This handle implements the `Write` trait and is constructed via
/// the [`Stderr::lock`] method.
///
/// [`Stderr::lock`]: struct.Stderr.html#method.lock
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StderrLock<'a> {
inner: ReentrantMutexGuard<'a, RefCell<Maybe<StderrRaw>>>,
}
/// Constructs a new handle to the standard error of the current process.
///
/// This handle is not buffered.
///
/// # Examples
///
/// Using implicit synchronization:
///
/// ```
/// use std::io::{self, Write};
///
/// # fn foo() -> io::Result<()> {
/// io::stderr().write(b"hello world")?;
///
/// # Ok(())
/// # }
/// ```
///
/// Using explicit synchronization:
///
/// ```
/// use std::io::{self, Write};
///
/// # fn foo() -> io::Result<()> {
/// let stderr = io::stderr();
/// let mut handle = stderr.lock();
///
/// handle.write(b"hello world")?;
///
/// # Ok(())
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init);
return Stderr {
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
};
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
let stderr = match stderr_raw() {
Ok(stderr) => Maybe::Real(stderr),
_ => Maybe::Fake,
};
Arc::new(ReentrantMutex::new(RefCell::new(stderr)))
}
}
impl Stderr {
/// Locks this handle to the standard error stream, returning a writable
/// guard.
///
/// The lock is released when the returned lock goes out of scope. The
/// returned guard also implements the `Write` trait for writing data.
///
/// # Examples
///
/// ```
/// use std::io::{self, Write};
///
/// fn foo() -> io::Result<()> {
/// let stderr = io::stderr();
/// let mut handle = stderr.lock();
///
/// handle.write(b"hello world")?;
///
/// Ok(())
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn lock(&self) -> StderrLock {
StderrLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Stderr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("Stderr { .. }")
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.lock().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.lock().flush()
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
self.lock().write_all(buf)
}
fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> {
self.lock().write_fmt(args)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for StderrLock<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.borrow_mut().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.borrow_mut().flush()
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl<'a> fmt::Debug for StderrLock<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad("StderrLock { .. }")
}
}
/// Resets the thread-local stderr handle to the specified writer
///
/// This will replace the current thread's stderr handle, returning the old
/// handle. All future calls to `panic!` and friends will emit their output to
/// this specified handle.
///
/// Note that this does not need to be called for all new threads; the default
/// output handle is to the process's stderr stream.
#[unstable(feature = "set_stdio",
reason = "this function may disappear completely or be replaced \
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
use panicking::LOCAL_STDERR;
use mem;
LOCAL_STDERR.with(move |slot| {
mem::replace(&mut *slot.borrow_mut(), sink)
}).and_then(|mut s| {
let _ = s.flush();
Some(s)
})
}
/// Resets the thread-local stdout handle to the specified writer
///
/// This will replace the current thread's stdout handle, returning the old
/// handle. All future calls to `print!` and friends will emit their output to
/// this specified handle.
///
/// Note that this does not need to be called for all new threads; the default
/// output handle is to the process's stdout stream.
#[unstable(feature = "set_stdio",
reason = "this function may disappear completely or be replaced \
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
use mem;
LOCAL_STDOUT.with(move |slot| {
mem::replace(&mut *slot.borrow_mut(), sink)
}).and_then(|mut s| {
let _ = s.flush();
Some(s)
})
}
#[unstable(feature = "print",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "0")]
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
// As an implementation of the `println!` macro, we want to try our best to
// not panic wherever possible and get the output somewhere. There are
// currently two possible vectors for panics we take care of here:
//
// 1. If the TLS key for the local stdout has been destroyed, accessing it
// would cause a panic. Note that we just lump in the uninitialized case
// here for convenience, we're not trying to avoid a panic.
// 2. If the local stdout is currently in use (e.g. we're in the middle of
// already printing) then accessing again would cause a panic.
//
// If, however, the actual I/O causes an error, we do indeed panic.
let result = match LOCAL_STDOUT.state() {
LocalKeyState::Uninitialized |
LocalKeyState::Destroyed => stdout().write_fmt(args),
LocalKeyState::Valid => {
LOCAL_STDOUT.with(|s| {
if let Ok(mut borrowed) = s.try_borrow_mut() {
if let Some(w) = borrowed.as_mut() {
return w.write_fmt(args);
}
}
stdout().write_fmt(args)
})
}
};
if let Err(e) = result {
panic!("failed printing to stdout: {}", e);
}
}
#[cfg(test)]
mod tests {
use thread;
use super::*;
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_doesnt_poison() {
thread::spawn(|| {
let _a = stdin();
let _a = _a.lock();
let _a = stdout();
let _a = _a.lock();
let _a = stderr();
let _a = _a.lock();
panic!();
}).join().unwrap_err();
let _a = stdin();
let _a = _a.lock();
let _a = stdout();
let _a = _a.lock();
let _a = stderr();
let _a = _a.lock();
}
}

1
ctr-std/src/lib.rs

@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
#![feature(char_escape_debug)]
#![feature(dropck_eyepatch)]
#![feature(float_extras)]
#![feature(fnbox)]
#![feature(fused)]
#![feature(generic_param_attrs)]
#![feature(int_error_internals)]

9
ctr-std/src/panicking.rs

@ -11,10 +11,19 @@ @@ -11,10 +11,19 @@
//! Implementation of various bits and pieces of the `panic!` macro and
//! associated runtime pieces.
use io::prelude::*;
use any::Any;
use cell::RefCell;
use fmt;
use __core::fmt::Display;
thread_local! {
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
RefCell::new(None)
}
}
///The compiler wants this to be here. Otherwise it won't be happy. And we like happy compilers.
#[lang = "eh_personality"]
extern fn eh_personality() {}

137
ctr-std/src/sys/unix/fd.rs

@ -0,0 +1,137 @@ @@ -0,0 +1,137 @@
// 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.
#![unstable(reason = "not public", issue = "0", feature = "fd")]
use cmp;
use io::{self, Read};
use libc::{self, c_int, c_void, ssize_t};
use mem;
use sys::cvt;
use sys_common::AsInner;
use sys_common::io::read_to_end_uninitialized;
#[derive(Debug)]
pub struct FileDesc {
fd: c_int,
}
fn max_len() -> usize {
// The maximum read limit on most posix-like systems is `SSIZE_MAX`,
// with the man page quoting that if the count of bytes to read is
// greater than `SSIZE_MAX` the result is "unspecified".
//
// On OSX, however, apparently the 64-bit libc is either buggy or
// intentionally showing odd behavior by rejecting any read with a size
// larger than or equal to INT_MAX. To handle both of these the read
// size is capped on both platforms.
if cfg!(target_os = "macos") {
<c_int>::max_value() as usize - 1
} else {
<ssize_t>::max_value() as usize
}
}
impl FileDesc {
pub fn new(fd: c_int) -> FileDesc {
FileDesc { fd: fd }
}
pub fn raw(&self) -> c_int { self.fd }
/// Extracts the actual filedescriptor without closing it.
pub fn into_raw(self) -> c_int {
let fd = self.fd;
mem::forget(self);
fd
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::read(self.fd,
buf.as_mut_ptr() as *mut c_void,
cmp::min(buf.len(), max_len()))
})?;
Ok(ret as usize)
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut me = self;
(&mut me).read_to_end(buf)
}
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
-> io::Result<isize>
{
use libc::pread as pread64;
cvt(pread64(fd, buf, count, offset))
}
unsafe {
cvt_pread64(self.fd,
buf.as_mut_ptr() as *mut c_void,
cmp::min(buf.len(), max_len()),
offset as i64)
.map(|n| n as usize)
}
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::write(self.fd,
buf.as_ptr() as *const c_void,
cmp::min(buf.len(), max_len()))
})?;
Ok(ret as usize)
}
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
-> io::Result<isize>
{
use libc::pwrite as pwrite64;
cvt(pwrite64(fd, buf, count, offset))
}
unsafe {
cvt_pwrite64(self.fd,
buf.as_ptr() as *const c_void,
cmp::min(buf.len(), max_len()),
offset as i64)
.map(|n| n as usize)
}
}
}
impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
unsafe { read_to_end_uninitialized(self, buf) }
}
}
impl AsInner<c_int> for FileDesc {
fn as_inner(&self) -> &c_int { &self.fd }
}
impl Drop for FileDesc {
fn drop(&mut self) {
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// (opened after we closed ours.
let _ = unsafe { libc::close(self.fd) };
}
}

81
ctr-std/src/sys/unix/io.rs

@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
// 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;
use libc;
use sys::fd::FileDesc;
pub struct Stdin(());
pub struct Stdout(());
pub struct Stderr(());
impl Stdin {
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDIN_FILENO);
let ret = fd.read(data);
fd.into_raw();
ret
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDIN_FILENO);
let ret = fd.read_to_end(buf);
fd.into_raw();
ret
}
}
impl Stdout {
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDOUT_FILENO);
let ret = fd.write(data);
fd.into_raw();
ret
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
}
impl Stderr {
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDERR_FILENO);
let ret = fd.write(data);
fd.into_raw();
ret
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
}
// FIXME: right now this raw stderr handle is used in a few places because
// std::io::stderr_raw isn't exposed, but once that's exposed this impl
// should go away
impl io::Write for Stderr {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
Stderr::write(self, data)
}
fn flush(&mut self) -> io::Result<()> {
Stderr::flush(self)
}
}
pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;

2
ctr-std/src/sys/unix/mod.rs

@ -15,6 +15,8 @@ use libc; @@ -15,6 +15,8 @@ use libc;
pub mod ext;
pub mod fast_thread_local;
pub mod fd;
pub mod stdio;
pub mod memchr;
pub mod mutex;
pub mod os;

81
ctr-std/src/sys/unix/stdio.rs

@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
// 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;
use libc;
use sys::fd::FileDesc;
pub struct Stdin(());
pub struct Stdout(());
pub struct Stderr(());
impl Stdin {
pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDIN_FILENO);
let ret = fd.read(data);
fd.into_raw();
ret
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDIN_FILENO);
let ret = fd.read_to_end(buf);
fd.into_raw();
ret
}
}
impl Stdout {
pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDOUT_FILENO);
let ret = fd.write(data);
fd.into_raw();
ret
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
}
impl Stderr {
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDERR_FILENO);
let ret = fd.write(data);
fd.into_raw();
ret
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
}
// FIXME: right now this raw stderr handle is used in a few places because
// std::io::stderr_raw isn't exposed, but once that's exposed this impl
// should go away
impl io::Write for Stderr {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
Stderr::write(self, data)
}
fn flush(&mut self) -> io::Result<()> {
Stderr::flush(self)
}
}
pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;

80
ctr-std/src/sys_common/at_exit_imp.rs

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation of running at_exit routines
//!
//! Documentation can be found on the `rt::at_exit` function.
use alloc::boxed::FnBox;
use ptr;
use sys_common::mutex::Mutex;
type Queue = Vec<Box<FnBox()>>;
// NB these are specifically not types from `std::sync` as they currently rely
// on poisoning and this module needs to operate at a lower level than requiring
// the thread infrastructure to be in place (useful on the borders of
// initialization/destruction).
static LOCK: Mutex = Mutex::new();
static mut QUEUE: *mut Queue = ptr::null_mut();
// The maximum number of times the cleanup routines will be run. While running
// the at_exit closures new ones may be registered, and this count is the number
// of times the new closures will be allowed to register successfully. After
// this number of iterations all new registrations will return `false`.
const ITERS: usize = 10;
unsafe fn init() -> bool {
if QUEUE.is_null() {
let state: Box<Queue> = box Vec::new();
QUEUE = Box::into_raw(state);
} else if QUEUE as usize == 1 {
// can't re-init after a cleanup
return false
}
true
}
pub fn cleanup() {
for i in 0..ITERS {
unsafe {
LOCK.lock();
let queue = QUEUE;
QUEUE = if i == ITERS - 1 {1} else {0} as *mut _;
LOCK.unlock();
// make sure we're not recursively cleaning up
assert!(queue as usize != 1);
// If we never called init, not need to cleanup!
if queue as usize != 0 {
let queue: Box<Queue> = Box::from_raw(queue);
for to_run in *queue {
to_run();
}
}
}
}
}
pub fn push(f: Box<FnBox()>) -> bool {
let mut ret = true;
unsafe {
LOCK.lock();
if init() {
(*QUEUE).push(f);
} else {
ret = false;
}
LOCK.unlock();
}
ret
}

15
ctr-std/src/sys_common/mod.rs

@ -24,6 +24,7 @@ @@ -24,6 +24,7 @@
#![allow(missing_docs)]
pub mod at_exit_imp;
pub mod io;
pub mod mutex;
pub mod poison;
@ -56,6 +57,20 @@ pub trait FromInner<Inner> { @@ -56,6 +57,20 @@ pub trait FromInner<Inner> {
fn from_inner(inner: Inner) -> Self;
}
/// Enqueues a procedure to run when the main thread exits.
///
/// Currently these closures are only run once the main *Rust* thread exits.
/// Once the `at_exit` handlers begin running, more may be enqueued, but not
/// infinitely so. Eventually a handler registration will be forced to fail.
///
/// Returns `Ok` if the handler was successfully registered, meaning that the
/// closure will be run once the main thread exits. Returns `Err` to indicate
/// that the closure could not be registered, meaning that it is not scheduled
/// to be run.
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
}
macro_rules! rtabort {
($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*)))
}

Loading…
Cancel
Save