aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/io
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-08-19 17:48:00 -0600
committerFenrir <[email protected]>2018-08-19 17:56:18 -0600
commit5d28bfcfd6086c3328837de9695099ea39048d0d (patch)
treea514fde042ff2a504a03305bfe0894ff8cd8d47e /ctr-std/src/io
parentUpdate for latest nightly 2018-06-09 (#70) (diff)
downloadctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.tar.xz
ctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.zip
Update for nightly-2018-08-18
Diffstat (limited to 'ctr-std/src/io')
-rw-r--r--ctr-std/src/io/buffered.rs85
-rw-r--r--ctr-std/src/io/cursor.rs57
-rw-r--r--ctr-std/src/io/error.rs25
-rw-r--r--ctr-std/src/io/lazy.rs30
-rw-r--r--ctr-std/src/io/mod.rs171
-rw-r--r--ctr-std/src/io/stdio.rs40
-rw-r--r--ctr-std/src/io/util.rs2
7 files changed, 117 insertions, 293 deletions
diff --git a/ctr-std/src/io/buffered.rs b/ctr-std/src/io/buffered.rs
index ee297d3..03c97de 100644
--- a/ctr-std/src/io/buffered.rs
+++ b/ctr-std/src/io/buffered.rs
@@ -61,7 +61,8 @@ pub struct BufReader<R> {
}
impl<R: Read> BufReader<R> {
- /// Creates a new `BufReader` with a default buffer capacity.
+ /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB,
+ /// but may change in the future.
///
/// # Examples
///
@@ -153,33 +154,6 @@ impl<R: Read> BufReader<R> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
- /// Returns `true` if there are no bytes in the internal buffer.
- ///
- /// # Examples
- //
- /// ```no_run
- /// # #![feature(bufreader_is_empty)]
- /// use std::io::BufReader;
- /// use std::io::BufRead;
- /// use std::fs::File;
- ///
- /// fn main() -> std::io::Result<()> {
- /// let f1 = File::open("log.txt")?;
- /// let mut reader = BufReader::new(f1);
- /// assert!(reader.is_empty());
- ///
- /// if reader.fill_buf()?.len() > 0 {
- /// assert!(!reader.is_empty());
- /// }
- /// Ok(())
- /// }
- /// ```
- #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")]
- #[rustc_deprecated(since = "1.26.0", reason = "use .buffer().is_empty() instead")]
- pub fn is_empty(&self) -> bool {
- self.buffer().is_empty()
- }
-
/// Returns a reference to the internally buffered data.
///
/// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
@@ -454,7 +428,8 @@ pub struct BufWriter<W: Write> {
pub struct IntoInnerError<W>(W, Error);
impl<W: Write> BufWriter<W> {
- /// Creates a new `BufWriter` with a default buffer capacity.
+ /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB,
+ /// but may change in the future.
///
/// # Examples
///
@@ -738,7 +713,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// reducing the number of actual writes to the file.
///
/// ```no_run
-/// use std::fs::File;
+/// use std::fs::{self, File};
/// use std::io::prelude::*;
/// use std::io::LineWriter;
///
@@ -752,17 +727,30 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// let file = File::create("poem.txt")?;
/// let mut file = LineWriter::new(file);
///
-/// for &byte in road_not_taken.iter() {
-/// file.write(&[byte]).unwrap();
-/// }
+/// file.write_all(b"I shall be telling this with a sigh")?;
///
-/// // let's check we did the right thing.
-/// let mut file = File::open("poem.txt")?;
-/// let mut contents = String::new();
+/// // No bytes are written until a newline is encountered (or
+/// // the internal buffer is filled).
+/// assert_eq!(fs::read_to_string("poem.txt")?, "");
+/// file.write_all(b"\n")?;
+/// assert_eq!(
+/// fs::read_to_string("poem.txt")?,
+/// "I shall be telling this with a sigh\n",
+/// );
///
-/// file.read_to_string(&mut contents)?;
+/// // Write the rest of the poem.
+/// file.write_all(b"Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.")?;
///
-/// assert_eq!(contents.as_bytes(), &road_not_taken[..]);
+/// // The last line of the poem doesn't end in a newline, so
+/// // we have to flush or drop the `LineWriter` to finish
+/// // writing.
+/// file.flush()?;
+///
+/// // Confirm the whole poem was written.
+/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]);
/// Ok(())
/// }
/// ```
@@ -862,7 +850,7 @@ impl<W: Write> LineWriter<W> {
///
/// The internal buffer is written out before returning the writer.
///
- // # Errors
+ /// # Errors
///
/// An `Err` will be returned if an error occurs while flushing the buffer.
///
@@ -1251,25 +1239,6 @@ mod tests {
}
#[test]
- #[allow(deprecated)]
- fn read_char_buffered() {
- let buf = [195, 159];
- let reader = BufReader::with_capacity(1, &buf[..]);
- assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß');
- }
-
- #[test]
- #[allow(deprecated)]
- fn test_chars() {
- let buf = [195, 159, b'a'];
- let reader = BufReader::with_capacity(1, &buf[..]);
- let mut it = reader.chars();
- assert_eq!(it.next().unwrap().unwrap(), 'ß');
- assert_eq!(it.next().unwrap().unwrap(), 'a');
- assert!(it.next().is_none());
- }
-
- #[test]
#[should_panic]
fn dont_panic_in_drop_on_panicked_flush() {
struct FailFlushWriter;
diff --git a/ctr-std/src/io/cursor.rs b/ctr-std/src/io/cursor.rs
index 8ac5257..14f2015 100644
--- a/ctr-std/src/io/cursor.rs
+++ b/ctr-std/src/io/cursor.rs
@@ -10,15 +10,17 @@
use io::prelude::*;
+use core::convert::TryInto;
use cmp;
use io::{self, Initializer, SeekFrom, Error, ErrorKind};
-/// A `Cursor` wraps another type and provides it with a
+/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
///
-/// `Cursor`s 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.
+/// `Cursor`s are used with in-memory buffers, anything implementing
+/// `AsRef<[u8]>`, 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
@@ -86,11 +88,11 @@ pub struct Cursor<T> {
}
impl<T> Cursor<T> {
- /// Creates a new cursor wrapping the provided underlying I/O object.
+ /// Creates a new cursor wrapping the provided underlying in-memory buffer.
///
- /// Cursor initial position is `0` even if underlying object (e.
- /// g. `Vec`) is not empty. So writing to cursor starts with
- /// overwriting `Vec` content, not with appending to it.
+ /// Cursor initial position is `0` even if underlying buffer (e.g. `Vec`)
+ /// is not empty. So writing to cursor starts with overwriting `Vec`
+ /// content, not with appending to it.
///
/// # Examples
///
@@ -259,26 +261,9 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<us
Ok(amt)
}
-/// Compensate removal of some impls per
-/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243
-#[cfg(any(target_pointer_width = "16",
- target_pointer_width = "32"))]
-fn try_into(n: u64) -> Result<usize, ()> {
- if n <= (<usize>::max_value() as u64) {
- Ok(n as usize)
- } else {
- Err(())
- }
-}
-
-#[cfg(any(target_pointer_width = "64"))]
-fn try_into(n: u64) -> Result<usize, ()> {
- Ok(n as usize)
-}
-
// Resizing write implementation
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
- let pos: usize = try_into(*pos_mut).map_err(|_| {
+ let pos: usize = (*pos_mut).try_into().map_err(|_| {
Error::new(ErrorKind::InvalidInput,
"cursor position exceeds maximum possible vector length")
})?;
@@ -566,26 +551,6 @@ mod tests {
}
#[test]
- #[allow(deprecated)]
- 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]
- #[allow(deprecated)]
- 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[..]);
diff --git a/ctr-std/src/io/error.rs b/ctr-std/src/io/error.rs
index bdd675e..3e50988 100644
--- a/ctr-std/src/io/error.rs
+++ b/ctr-std/src/io/error.rs
@@ -83,7 +83,7 @@ enum Repr {
#[derive(Debug)]
struct Custom {
kind: ErrorKind,
- error: Box<error::Error+Send+Sync>,
+ error: Box<dyn error::Error+Send+Sync>,
}
/// A list specifying general categories of I/O error.
@@ -97,6 +97,7 @@ struct Custom {
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
+#[non_exhaustive]
pub enum ErrorKind {
/// An entity was not found, often a file.
#[stable(feature = "rust1", since = "1.0.0")]
@@ -180,15 +181,6 @@ pub enum ErrorKind {
/// read.
#[stable(feature = "read_exact", since = "1.6.0")]
UnexpectedEof,
-
- /// A marker variant that tells the compiler that users of this enum cannot
- /// match it exhaustively.
- #[unstable(feature = "io_error_internals",
- reason = "better expressed through extensible enums that this \
- enum cannot be exhaustively matched against",
- issue = "0")]
- #[doc(hidden)]
- __Nonexhaustive,
}
impl ErrorKind {
@@ -212,7 +204,6 @@ impl ErrorKind {
ErrorKind::Interrupted => "operation interrupted",
ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file",
- ErrorKind::__Nonexhaustive => unreachable!()
}
}
}
@@ -250,12 +241,12 @@ impl Error {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<E>(kind: ErrorKind, error: E) -> Error
- where E: Into<Box<error::Error+Send+Sync>>
+ where E: Into<Box<dyn error::Error+Send+Sync>>
{
Self::_new(kind, error.into())
}
- fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
+ fn _new(kind: ErrorKind, error: Box<dyn error::Error+Send+Sync>) -> Error {
Error {
repr: Repr::Custom(Box::new(Custom {
kind,
@@ -373,7 +364,7 @@ impl Error {
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
- pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
+ pub fn get_ref(&self) -> Option<&(dyn error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
@@ -444,7 +435,7 @@ impl Error {
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
- pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
+ pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error+Send+Sync+'static)> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
@@ -478,7 +469,7 @@ impl Error {
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
- pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
+ pub fn into_inner(self) -> Option<Box<dyn error::Error+Send+Sync>> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
@@ -551,7 +542,7 @@ impl error::Error for Error {
}
}
- fn cause(&self) -> Option<&error::Error> {
+ fn cause(&self) -> Option<&dyn error::Error> {
match self.repr {
Repr::Os(..) => None,
Repr::Simple(..) => None,
diff --git a/ctr-std/src/io/lazy.rs b/ctr-std/src/io/lazy.rs
index 9cef4e3..4fb367f 100644
--- a/ctr-std/src/io/lazy.rs
+++ b/ctr-std/src/io/lazy.rs
@@ -15,15 +15,21 @@ use sys_common;
use sys_common::mutex::Mutex;
pub struct Lazy<T> {
+ // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly!
lock: Mutex,
ptr: Cell<*mut Arc<T>>,
init: fn() -> Arc<T>,
}
+#[inline]
+const fn done<T>() -> *mut Arc<T> { 1_usize as *mut _ }
+
unsafe impl<T> Sync for Lazy<T> {}
impl<T: Send + Sync + 'static> Lazy<T> {
- pub const fn new(init: fn() -> Arc<T>) -> Lazy<T> {
+ /// Safety: `init` must not call `get` on the variable that is being
+ /// initialized.
+ pub const unsafe fn new(init: fn() -> Arc<T>) -> Lazy<T> {
Lazy {
lock: Mutex::new(),
ptr: Cell::new(ptr::null_mut()),
@@ -33,32 +39,34 @@ impl<T: Send + Sync + 'static> Lazy<T> {
pub fn get(&'static self) -> Option<Arc<T>> {
unsafe {
- self.lock.lock();
+ let _guard = self.lock.lock();
let ptr = self.ptr.get();
- let ret = if ptr.is_null() {
+ if ptr.is_null() {
Some(self.init())
- } else if ptr as usize == 1 {
+ } else if ptr == done() {
None
} else {
Some((*ptr).clone())
- };
- self.lock.unlock();
- return ret
+ }
}
}
+ // Must only be called with `lock` held
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();
+ let ptr = {
+ let _guard = self.lock.lock();
+ self.ptr.replace(done())
+ };
drop(Box::from_raw(ptr))
});
+ // This could reentrantly call `init` again, which is a problem
+ // because our `lock` allows reentrancy!
+ // That's why `new` is unsafe and requires the caller to ensure no reentrancy happens.
let ret = (self.init)();
if registered.is_ok() {
self.ptr.set(Box::into_raw(Box::new(ret.clone())));
diff --git a/ctr-std/src/io/mod.rs b/ctr-std/src/io/mod.rs
index eba4e9f..b83f3fb 100644
--- a/ctr-std/src/io/mod.rs
+++ b/ctr-std/src/io/mod.rs
@@ -147,7 +147,7 @@
//! ```
//!
//! Note that you cannot use the [`?` operator] in functions that do not return
-//! a [`Result<T, E>`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`]
+//! a [`Result<T, E>`][`Result`]. Instead, you can call [`.unwrap()`]
//! or `match` on the return value to catch any possible errors:
//!
//! ```no_run
@@ -270,10 +270,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
use cmp;
-use core::str as core_str;
-use error as std_error;
use fmt;
-use result;
use str;
use memchr;
use ptr;
@@ -357,19 +354,26 @@ fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
// avoid paying to allocate and zero a huge chunk of memory if the reader only
// has 4 bytes while still making large reads if the reader does have a ton
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
-// time is 4,500 times (!) slower than this if the reader has a very small
-// amount of data to return.
+// time is 4,500 times (!) slower than a default reservation size of 32 if the
+// reader has a very small amount of data to return.
//
// Because we're extending the buffer with uninitialized data for trusted
// readers, we need to make sure to truncate that if any of this panics.
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
+ read_to_end_with_reservation(r, buf, 32)
+}
+
+fn read_to_end_with_reservation<R: Read + ?Sized>(r: &mut R,
+ buf: &mut Vec<u8>,
+ reservation_size: usize) -> Result<usize>
+{
let start_len = buf.len();
let mut g = Guard { len: buf.len(), buf: buf };
let ret;
loop {
if g.len == g.buf.len() {
unsafe {
- g.buf.reserve(32);
+ g.buf.reserve(reservation_size);
let capacity = g.buf.capacity();
g.buf.set_len(capacity);
r.initializer().initialize(&mut g.buf[g.len..]);
@@ -800,53 +804,6 @@ pub trait Read {
Bytes { inner: self }
}
- /// Transforms this `Read` instance to an [`Iterator`] over [`char`]s.
- ///
- /// This adaptor will attempt to interpret this reader as a UTF-8 encoded
- /// sequence of characters. The returned iterator will return [`None`] once
- /// EOF is reached for this reader. Otherwise each element yielded will be a
- /// [`Result`]`<`[`char`]`, E>` where `E` may contain information about what I/O error
- /// occurred or where decoding failed.
- ///
- /// Currently this adaptor will discard intermediate data read, and should
- /// be avoided if this is not desired.
- ///
- /// # Examples
- ///
- /// [`File`]s implement `Read`:
- ///
- /// [`File`]: ../fs/struct.File.html
- /// [`Iterator`]: ../../std/iter/trait.Iterator.html
- /// [`Result`]: ../../std/result/enum.Result.html
- /// [`char`]: ../../std/primitive.char.html
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
- /// ```no_run
- /// #![feature(io)]
- /// use std::io;
- /// use std::io::prelude::*;
- /// use std::fs::File;
- ///
- /// fn main() -> io::Result<()> {
- /// let mut f = File::open("foo.txt")?;
- ///
- /// for c in f.chars() {
- /// println!("{}", c.unwrap());
- /// }
- /// Ok(())
- /// }
- /// ```
- #[unstable(feature = "io", reason = "the semantics of a partial read/write \
- of where errors happen is currently \
- unclear and may change",
- issue = "27802")]
- #[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
- #[allow(deprecated)]
- fn chars(self) -> Chars<Self> where Self: Sized {
- Chars { inner: self }
- }
-
/// Creates an adaptor which will chain this stream with another.
///
/// The returned `Read` instance will first read all bytes from this object
@@ -1949,6 +1906,12 @@ impl<T: Read> Read for Take<T> {
unsafe fn initializer(&self) -> Initializer {
self.inner.initializer()
}
+
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
+ let reservation_size = cmp::min(self.limit, 32) as usize;
+
+ read_to_end_with_reservation(self, buf, reservation_size)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1972,7 +1935,7 @@ impl<T: BufRead> BufRead for Take<T> {
}
}
-fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> {
+fn read_one_byte(reader: &mut dyn Read) -> Option<Result<u8>> {
let mut buf = [0];
loop {
return match reader.read(&mut buf) {
@@ -2005,104 +1968,6 @@ impl<R: Read> Iterator for Bytes<R> {
}
}
-/// An iterator over the `char`s of a reader.
-///
-/// This struct is generally created by calling [`chars`][chars] on a reader.
-/// Please see the documentation of `chars()` for more details.
-///
-/// [chars]: trait.Read.html#method.chars
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[derive(Debug)]
-#[allow(deprecated)]
-pub struct Chars<R> {
- inner: R,
-}
-
-/// An enumeration of possible errors that can be generated from the `Chars`
-/// adapter.
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead:
- https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")]
-#[derive(Debug)]
-#[allow(deprecated)]
-pub enum CharsError {
- /// Variant representing that the underlying stream was read successfully
- /// but it did not contain valid utf8 data.
- NotUtf8,
-
- /// Variant representing that an I/O error occurred.
- Other(Error),
-}
-
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[allow(deprecated)]
-impl<R: Read> Iterator for Chars<R> {
- type Item = result::Result<char, CharsError>;
-
- fn next(&mut self) -> Option<result::Result<char, CharsError>> {
- let first_byte = match read_one_byte(&mut self.inner)? {
- Ok(b) => b,
- Err(e) => return Some(Err(CharsError::Other(e))),
- };
- let width = core_str::utf8_char_width(first_byte);
- if width == 1 { return Some(Ok(first_byte as char)) }
- if width == 0 { return Some(Err(CharsError::NotUtf8)) }
- let mut buf = [first_byte, 0, 0, 0];
- {
- let mut start = 1;
- while start < width {
- match self.inner.read(&mut buf[start..width]) {
- Ok(0) => return Some(Err(CharsError::NotUtf8)),
- Ok(n) => start += n,
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
- Err(e) => return Some(Err(CharsError::Other(e))),
- }
- }
- }
- Some(match str::from_utf8(&buf[..width]).ok() {
- Some(s) => Ok(s.chars().next().unwrap()),
- None => Err(CharsError::NotUtf8),
- })
- }
-}
-
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[allow(deprecated)]
-impl std_error::Error for CharsError {
- fn description(&self) -> &str {
- match *self {
- CharsError::NotUtf8 => "invalid utf8 encoding",
- CharsError::Other(ref e) => std_error::Error::description(e),
- }
- }
- fn cause(&self) -> Option<&std_error::Error> {
- match *self {
- CharsError::NotUtf8 => None,
- CharsError::Other(ref e) => e.cause(),
- }
- }
-}
-
-#[unstable(feature = "io", reason = "awaiting stability of Read::chars",
- issue = "27802")]
-#[allow(deprecated)]
-impl fmt::Display for CharsError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- CharsError::NotUtf8 => {
- "byte stream did not contain valid utf8".fmt(f)
- }
- CharsError::Other(ref e) => e.fmt(f),
- }
- }
-}
-
/// An iterator over the contents of an instance of `BufRead` split on a
/// particular byte.
///
diff --git a/ctr-std/src/io/stdio.rs b/ctr-std/src/io/stdio.rs
index 2472bed..1f256f5 100644
--- a/ctr-std/src/io/stdio.rs
+++ b/ctr-std/src/io/stdio.rs
@@ -21,7 +21,7 @@ use thread::LocalKey;
/// Stdout used by print! and println! macros
thread_local! {
- static LOCAL_STDOUT: RefCell<Option<Box<Write + Send>>> = {
+ static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
RefCell::new(None)
}
}
@@ -197,12 +197,13 @@ pub struct StdinLock<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin {
- static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init);
+ static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = unsafe { Lazy::new(stdin_init) };
return Stdin {
inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
};
fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
+ // This must not reentrantly access `INSTANCE`
let stdin = match stdin_raw() {
Ok(stdin) => Maybe::Real(stdin),
_ => Maybe::Fake
@@ -396,12 +397,13 @@ pub struct StdoutLock<'a> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
- = Lazy::new(stdout_init);
+ = unsafe { Lazy::new(stdout_init) };
return Stdout {
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
};
fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
+ // This must not reentrantly access `INSTANCE`
let stdout = match stdout_raw() {
Ok(stdout) => Maybe::Real(stdout),
_ => Maybe::Fake,
@@ -531,12 +533,14 @@ pub struct StderrLock<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
- static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init);
+ static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> =
+ unsafe { Lazy::new(stderr_init) };
return Stderr {
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
};
fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
+ // This must not reentrantly access `INSTANCE`
let stderr = match stderr_raw() {
Ok(stderr) => Maybe::Real(stderr),
_ => Maybe::Fake,
@@ -624,7 +628,7 @@ impl<'a> fmt::Debug for StderrLock<'a> {
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
-pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
+pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
use panicking::LOCAL_STDERR;
use mem;
LOCAL_STDERR.with(move |slot| {
@@ -648,7 +652,7 @@ pub fn set_panic(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
with a more general mechanism",
issue = "0")]
#[doc(hidden)]
-pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
+pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
use mem;
LOCAL_STDOUT.with(move |slot| {
mem::replace(&mut *slot.borrow_mut(), sink)
@@ -670,7 +674,7 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
/// However, if the actual I/O causes an error, this function does panic.
fn print_to<T>(
args: fmt::Arguments,
- local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
+ local_s: &'static LocalKey<RefCell<Option<Box<dyn Write+Send>>>>,
global_s: fn() -> T,
label: &str,
)
@@ -712,10 +716,32 @@ pub fn _eprint(args: fmt::Arguments) {
#[cfg(test)]
mod tests {
+ use panic::{UnwindSafe, RefUnwindSafe};
use thread;
use super::*;
#[test]
+ fn stdout_unwind_safe() {
+ assert_unwind_safe::<Stdout>();
+ }
+ #[test]
+ fn stdoutlock_unwind_safe() {
+ assert_unwind_safe::<StdoutLock>();
+ assert_unwind_safe::<StdoutLock<'static>>();
+ }
+ #[test]
+ fn stderr_unwind_safe() {
+ assert_unwind_safe::<Stderr>();
+ }
+ #[test]
+ fn stderrlock_unwind_safe() {
+ assert_unwind_safe::<StderrLock>();
+ assert_unwind_safe::<StderrLock<'static>>();
+ }
+
+ fn assert_unwind_safe<T: UnwindSafe + RefUnwindSafe>() {}
+
+ #[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn panic_doesnt_poison() {
thread::spawn(|| {
diff --git a/ctr-std/src/io/util.rs b/ctr-std/src/io/util.rs
index 195310a..33f741d 100644
--- a/ctr-std/src/io/util.rs
+++ b/ctr-std/src/io/util.rs
@@ -223,7 +223,7 @@ mod tests {
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);
+ assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17);
}
#[test]