diff options
Diffstat (limited to 'src/libstd/io')
| -rw-r--r-- | src/libstd/io/buffered.rs | 18 | ||||
| -rw-r--r-- | src/libstd/io/lazy.rs | 24 | ||||
| -rw-r--r-- | src/libstd/io/mod.rs | 44 |
3 files changed, 39 insertions, 47 deletions
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 4def601f1c0..2a1294f23b2 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -120,7 +120,7 @@ impl<R> fmt::Debug for BufReader<R> where R: fmt::Debug { /// /// The buffer will be written out when the writer is dropped. #[stable(feature = "rust1", since = "1.0.0")] -pub struct BufWriter<W> { +pub struct BufWriter<W: Write> { inner: Option<W>, buf: Vec<u8>, } @@ -220,7 +220,7 @@ impl<W: Write> Write for BufWriter<W> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<W> fmt::Debug for BufWriter<W> where W: fmt::Debug { +impl<W: Write> fmt::Debug for BufWriter<W> where W: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "BufWriter {{ writer: {:?}, buffer: {}/{} }}", self.inner.as_ref().unwrap(), self.buf.len(), self.buf.capacity()) @@ -276,7 +276,7 @@ impl<W> fmt::Display for IntoInnerError<W> { /// /// The buffer will be written out when the writer is dropped. #[stable(feature = "rust1", since = "1.0.0")] -pub struct LineWriter<W> { +pub struct LineWriter<W: Write> { inner: BufWriter<W>, } @@ -335,7 +335,7 @@ impl<W: Write> Write for LineWriter<W> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<W> fmt::Debug for LineWriter<W> where W: fmt::Debug { +impl<W: Write> fmt::Debug for LineWriter<W> where W: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "LineWriter {{ writer: {:?}, buffer: {}/{} }}", self.inner.inner, self.inner.buf.len(), @@ -343,16 +343,16 @@ impl<W> fmt::Debug for LineWriter<W> where W: fmt::Debug { } } -struct InternalBufWriter<W>(BufWriter<W>); +struct InternalBufWriter<W: Write>(BufWriter<W>); -impl<W> InternalBufWriter<W> { +impl<W: Read + Write> InternalBufWriter<W> { fn get_mut(&mut self) -> &mut BufWriter<W> { let InternalBufWriter(ref mut w) = *self; return w; } } -impl<W: Read> Read for InternalBufWriter<W> { +impl<W: Read + Write> Read for InternalBufWriter<W> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.get_mut().inner.as_mut().unwrap().read(buf) } @@ -367,7 +367,7 @@ impl<W: Read> Read for InternalBufWriter<W> { /// /// The output buffer will be written out when this stream is dropped. #[stable(feature = "rust1", since = "1.0.0")] -pub struct BufStream<S> { +pub struct BufStream<S: Write> { inner: BufReader<InternalBufWriter<S>> } @@ -448,7 +448,7 @@ impl<S: Read + Write> Write for BufStream<S> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<S> fmt::Debug for BufStream<S> where S: fmt::Debug { +impl<S: Write> fmt::Debug for BufStream<S> where S: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let reader = &self.inner; let writer = &self.inner.inner.0; diff --git a/src/libstd/io/lazy.rs b/src/libstd/io/lazy.rs index c9b105f72a5..df280dab37d 100644 --- a/src/libstd/io/lazy.rs +++ b/src/libstd/io/lazy.rs @@ -35,25 +35,33 @@ impl<T: Send + Sync + 'static> Lazy<T> { pub fn get(&'static self) -> Option<Arc<T>> { let _g = self.lock.lock(); unsafe { - let mut ptr = *self.ptr.get(); + let ptr = *self.ptr.get(); if ptr.is_null() { - ptr = boxed::into_raw(self.init()); - *self.ptr.get() = ptr; + Some(self.init()) } else if ptr as usize == 1 { - return None + None + } else { + Some((*ptr).clone()) } - Some((*ptr).clone()) } } - fn init(&'static self) -> Box<Arc<T>> { - rt::at_exit(move || unsafe { + 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 = rt::at_exit(move || { let g = self.lock.lock(); let ptr = *self.ptr.get(); *self.ptr.get() = 1 as *mut _; drop(g); drop(Box::from_raw(ptr)) }); - Box::new((self.init)()) + let ret = (self.init)(); + if registered.is_ok() { + *self.ptr.get() = boxed::into_raw(Box::new(ret.clone())); + } + return ret } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 39c718c96b3..c6ae4d0dbec 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -16,13 +16,12 @@ use cmp; use unicode::str as core_str; use error as std_error; use fmt; -use iter::Iterator; +use iter::{self, Iterator, IteratorExt, Extend}; use marker::Sized; use ops::{Drop, FnOnce}; use option::Option::{self, Some, None}; use result::Result::{Ok, Err}; use result; -use slice; use string::String; use str; use vec::Vec; @@ -50,41 +49,26 @@ mod stdio; const DEFAULT_BUF_SIZE: usize = 64 * 1024; // Acquires a slice of the vector `v` from its length to its capacity -// (uninitialized data), reads into it, and then updates the length. +// (after initializing the data), reads into it, and then updates the length. // // This function is leveraged to efficiently read some bytes into a destination // vector without extra copying and taking advantage of the space that's already // in `v`. -// -// The buffer we're passing down, however, is pointing at uninitialized data -// (the end of a `Vec`), and many operations will be *much* faster if we don't -// have to zero it out. In order to prevent LLVM from generating an `undef` -// value when reads happen from this uninitialized memory, we force LLVM to -// think it's initialized by sending it through a black box. This should prevent -// actual undefined behavior after optimizations. fn with_end_to_cap<F>(v: &mut Vec<u8>, f: F) -> Result<usize> where F: FnOnce(&mut [u8]) -> Result<usize> { - unsafe { - let n = try!(f({ - let base = v.as_mut_ptr().offset(v.len() as isize); - black_box(slice::from_raw_parts_mut(base, - v.capacity() - v.len())) - })); - - // If the closure (typically a `read` implementation) reported that it - // read a larger number of bytes than the vector actually has, we need - // to be sure to clamp the vector to at most its capacity. - let new_len = cmp::min(v.capacity(), v.len() + n); - v.set_len(new_len); - return Ok(n); - } - - // Semi-hack used to prevent LLVM from retaining any assumptions about - // `dummy` over this function call - unsafe fn black_box<T>(mut dummy: T) -> T { - asm!("" :: "r"(&mut dummy) : "memory"); - dummy + let len = v.len(); + let new_area = v.capacity() - len; + v.extend(iter::repeat(0).take(new_area)); + match f(&mut v[len..]) { + Ok(n) => { + v.truncate(len + n); + Ok(n) + } + Err(e) => { + v.truncate(len); + Err(e) + } } } |
