diff options
| author | Mathieu David <mathieudavid@mathieudavid.org> | 2015-07-27 20:46:01 +0200 |
|---|---|---|
| committer | Mathieu David <mathieudavid@mathieudavid.org> | 2015-07-27 20:46:01 +0200 |
| commit | f6e9240a99e86d2c799dc29f179dd2870e51f71d (patch) | |
| tree | a7e5ba20745b16949a45a4612b2708e262693a7b /src/libstd | |
| parent | 003c3eaa62981b791f9eb7bcad015baa1e00d98c (diff) | |
| parent | 3351afeecffcc9ebaeb1188a5cde976da8e4a5aa (diff) | |
| download | rust-f6e9240a99e86d2c799dc29f179dd2870e51f71d.tar.gz rust-f6e9240a99e86d2c799dc29f179dd2870e51f71d.zip | |
Fix the relative path issue by including the files using include_bytes!
Diffstat (limited to 'src/libstd')
96 files changed, 4187 insertions, 970 deletions
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 9b94b7f7003..cf78fa7b69a 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -469,16 +469,19 @@ mod tests { use char::from_u32; #[test] - fn test_ascii() { - assert!("banana".chars().all(|c| c.is_ascii())); - assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); - } + fn test_is_ascii() { + assert!(b"".is_ascii()); + assert!(b"banana\0\x7F".is_ascii()); + assert!(b"banana\0\x7F".iter().all(|b| b.is_ascii())); + assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii()); + assert!(!b"Vi\xe1\xbb\x87t Nam".iter().all(|b| b.is_ascii())); + assert!(!b"\xe1\xbb\x87".iter().any(|b| b.is_ascii())); - #[test] - fn test_ascii_vec() { assert!("".is_ascii()); - assert!("a".is_ascii()); - assert!(!"\u{2009}".is_ascii()); + assert!("banana\0\u{7F}".is_ascii()); + assert!("banana\0\u{7F}".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华Việt Nam".chars().all(|c| c.is_ascii())); + assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii())); } #[test] @@ -538,6 +541,55 @@ mod tests { } #[test] + fn test_make_ascii_lower_case() { + macro_rules! test { + ($from: expr, $to: expr) => { + { + let mut x = $from; + x.make_ascii_lowercase(); + assert_eq!(x, $to); + } + } + } + test!(b'A', b'a'); + test!(b'a', b'a'); + test!(b'!', b'!'); + test!('A', 'a'); + test!('À', 'À'); + test!('a', 'a'); + test!('!', '!'); + test!(b"H\xc3\x89".to_vec(), b"h\xc3\x89"); + test!("HİKß".to_string(), "hİKß"); + } + + + #[test] + fn test_make_ascii_upper_case() { + macro_rules! test { + ($from: expr, $to: expr) => { + { + let mut x = $from; + x.make_ascii_uppercase(); + assert_eq!(x, $to); + } + } + } + test!(b'a', b'A'); + test!(b'A', b'A'); + test!(b'!', b'!'); + test!('a', 'A'); + test!('à', 'à'); + test!('A', 'A'); + test!('!', '!'); + test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9"); + test!("hıKß".to_string(), "HıKß"); + + let mut x = "Hello".to_string(); + x[..3].make_ascii_uppercase(); // Test IndexMut on String. + assert_eq!(x, "HELlo") + } + + #[test] fn test_eq_ignore_ascii_case() { assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl")); assert!(!"Ürl".eq_ignore_ascii_case("ürl")); diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs deleted file mode 100644 index df703b3e43e..00000000000 --- a/src/libstd/bool.rs +++ /dev/null @@ -1,14 +0,0 @@ -// 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. - -//! The boolean type - -#![doc(primitive = "bool")] -#![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 1dca3b77f38..06a30670e8b 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1638,7 +1638,7 @@ mod test_map { use super::HashMap; use super::Entry::{Occupied, Vacant}; - use iter::{range_inclusive, repeat}; + use iter::range_inclusive; use cell::RefCell; use rand::{thread_rng, Rng}; @@ -1698,7 +1698,7 @@ mod test_map { #[test] fn test_drops() { DROP_VECTOR.with(|slot| { - *slot.borrow_mut() = repeat(0).take(200).collect(); + *slot.borrow_mut() = vec![0; 200]; }); { @@ -1757,7 +1757,7 @@ mod test_map { #[test] fn test_move_iter_drops() { DROP_VECTOR.with(|v| { - *v.borrow_mut() = repeat(0).take(200).collect(); + *v.borrow_mut() = vec![0; 200]; }); let hm = { diff --git a/src/libstd/collections/hash/state.rs b/src/libstd/collections/hash/state.rs index 365e6268b3b..546e15296c7 100644 --- a/src/libstd/collections/hash/state.rs +++ b/src/libstd/collections/hash/state.rs @@ -38,7 +38,7 @@ pub trait HashState { /// A structure which is a factory for instances of `Hasher` which implement the /// default trait. /// -/// This struct has is 0-sized and does not need construction. +/// This struct is 0-sized and does not need construction. pub struct DefaultState<H>(marker::PhantomData<H>); impl<H: Default + hash::Hasher> HashState for DefaultState<H> { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 2616bc52785..349462aebe3 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -15,7 +15,7 @@ use cmp; use hash::{Hash, Hasher}; use iter::{Iterator, ExactSizeIterator}; use marker::{Copy, Send, Sync, Sized, self}; -use mem::{min_align_of, size_of}; +use mem::{align_of, size_of}; use mem; use num::wrapping::OverflowingOps; use ops::{Deref, DerefMut, Drop}; @@ -553,9 +553,9 @@ fn calculate_allocation(hash_size: usize, hash_align: usize, vals_align); let (end_of_vals, oflo2) = vals_offset.overflowing_add(vals_size); - let min_align = cmp::max(hash_align, cmp::max(keys_align, vals_align)); + let align = cmp::max(hash_align, cmp::max(keys_align, vals_align)); - (min_align, hash_offset, end_of_vals, oflo || oflo2) + (align, hash_offset, end_of_vals, oflo || oflo2) } #[test] @@ -597,9 +597,9 @@ impl<K, V> RawTable<K, V> { // factored out into a different function. let (malloc_alignment, hash_offset, size, oflo) = calculate_allocation( - hashes_size, min_align_of::<u64>(), - keys_size, min_align_of::< K >(), - vals_size, min_align_of::< V >()); + hashes_size, align_of::<u64>(), + keys_size, align_of::< K >(), + vals_size, align_of::< V >()); assert!(!oflo, "capacity overflow"); @@ -630,8 +630,8 @@ impl<K, V> RawTable<K, V> { let buffer = *self.hashes as *mut u8; let (keys_offset, vals_offset, oflo) = calculate_offsets(hashes_size, - keys_size, min_align_of::<K>(), - min_align_of::<V>()); + keys_size, align_of::<K>(), + align_of::<V>()); debug_assert!(!oflo, "capacity overflow"); unsafe { RawBucket { @@ -1005,9 +1005,9 @@ impl<K, V> Drop for RawTable<K, V> { let keys_size = self.capacity * size_of::<K>(); let vals_size = self.capacity * size_of::<V>(); let (align, _, size, oflo) = - calculate_allocation(hashes_size, min_align_of::<u64>(), - keys_size, min_align_of::<K>(), - vals_size, min_align_of::<V>()); + calculate_allocation(hashes_size, align_of::<u64>(), + keys_size, align_of::<K>(), + vals_size, align_of::<V>()); debug_assert!(!oflo, "should be impossible"); diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index ddafe416305..3621d18daed 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -160,6 +160,7 @@ mod tests { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] fn test_errors_do_not_crash() { // Open /dev/null as a library to get an error, and make sure @@ -179,6 +180,7 @@ mod tests { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod dl { use prelude::v1::*; @@ -263,7 +265,7 @@ mod dl { use sys::os; use os::windows::prelude::*; use ptr; - use sys::c::compat::kernel32::SetThreadErrorMode; + use sys::c::SetThreadErrorMode; pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> { // disable "dll load failed" error dialog. diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 2e00e126e23..6842de56d21 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -11,7 +11,7 @@ //! Inspection and manipulation of the process's environment. //! //! This module contains methods to inspect various aspects such as -//! environment varibles, process arguments, the current directory, and various +//! environment variables, process arguments, the current directory, and various //! other important directories. #![stable(feature = "env", since = "1.0.0")] @@ -36,7 +36,6 @@ use sys::os as os_imp; /// /// * Current directory does not exist. /// * There are insufficient permissions to access the current directory. -/// * The internal buffer is not large enough to hold the path. /// /// # Examples /// @@ -633,6 +632,7 @@ pub mod consts { /// - freebsd /// - dragonfly /// - bitrig + /// - netbsd /// - openbsd /// - android /// - windows @@ -759,6 +759,17 @@ mod os { pub const EXE_EXTENSION: &'static str = ""; } +#[cfg(target_os = "netbsd")] +mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "netbsd"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + #[cfg(target_os = "openbsd")] mod os { pub const FAMILY: &'static str = "unix"; diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index ffc204ada60..c9fe6e7e0b1 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use borrow::{Cow, ToOwned}; +use ascii; +use borrow::{Cow, ToOwned, Borrow}; use boxed::Box; use clone::Clone; use convert::{Into, From}; use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; use error::Error; -use fmt; +use fmt::{self, Write}; use io; use iter::Iterator; use libc; @@ -268,10 +269,26 @@ impl Deref for CString { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for CString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&String::from_utf8_lossy(self.as_bytes()), f) + fmt::Debug::fmt(&**self, f) } } +#[stable(feature = "cstr_debug", since = "1.3.0")] +impl fmt::Debug for CStr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f, "\"")); + for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) { + try!(f.write_char(byte as char)); + } + write!(f, "\"") + } +} + +#[stable(feature = "cstr_borrow", since = "1.3.0")] +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`. @@ -444,6 +461,15 @@ impl Ord for CStr { } } +#[stable(feature = "cstr_borrow", since = "1.3.0")] +impl ToOwned for CStr { + type Owned = CString; + + fn to_owned(&self) -> CString { + unsafe { CString::from_vec_unchecked(self.to_bytes().to_vec()) } + } +} + #[cfg(test)] mod tests { use prelude::v1::*; @@ -487,8 +513,8 @@ mod tests { #[test] fn formatted() { - let s = CString::new(&b"12"[..]).unwrap(); - assert_eq!(format!("{:?}", s), "\"12\""); + 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] @@ -515,4 +541,28 @@ mod tests { 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 libc::c_char; + + let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; + assert_eq!(owned.as_bytes_with_nul(), data); + } + + #[test] + fn equal_hash() { + use hash; + + let data = b"123\xE2\xFA\xA6\0"; + let ptr = data.as_ptr() as *const libc::c_char; + let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; + + let cstr_hash = hash::hash::<_, hash::SipHasher>(&cstr); + let cstring_hash = + hash::hash::<_, hash::SipHasher>(&CString::new(&data[..data.len() - 1]).unwrap()); + + assert_eq!(cstr_hash, cstring_hash); + } } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 2b0f17fb2bb..e5f2fcbae83 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -21,10 +21,11 @@ use core::prelude::*; use fmt; use ffi::OsString; -use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write}; +use io::{self, SeekFrom, Seek, Read, Write}; use path::{Path, PathBuf}; use sys::fs as fs_imp; -use sys_common::{AsInnerMut, FromInner, AsInner}; +use sys_common::io::read_to_end_uninitialized; +use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner}; use vec::Vec; /// A reference to an open file on the filesystem. @@ -269,14 +270,18 @@ impl File { /// will be extended to `size` and have all of the intermediate data filled /// in with 0s. /// + /// # Errors + /// + /// This function will return an error if the file is not opened for writing. + /// /// # Examples /// /// ```no_run /// use std::fs::File; /// /// # fn foo() -> std::io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// try!(f.set_len(0)); + /// let mut f = try!(File::create("foo.txt")); + /// try!(f.set_len(10)); /// # Ok(()) /// # } /// ``` @@ -312,6 +317,11 @@ impl FromInner<fs_imp::File> for File { File { inner: f } } } +impl IntoInner<fs_imp::File> for File { + fn into_inner(self) -> fs_imp::File { + self.inner + } +} impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -324,6 +334,9 @@ impl Read for File { 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> { + unsafe { read_to_end_uninitialized(self, buf) } + } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for File { @@ -419,7 +432,7 @@ impl OpenOptions { /// ```no_run /// use std::fs::OpenOptions; /// - /// let file = OpenOptions::new().append(true).open("foo.txt"); + /// let file = OpenOptions::new().write(true).append(true).open("foo.txt"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn append(&mut self, append: bool) -> &mut OpenOptions { @@ -436,7 +449,7 @@ impl OpenOptions { /// ```no_run /// use std::fs::OpenOptions; /// - /// let file = OpenOptions::new().truncate(true).open("foo.txt"); + /// let file = OpenOptions::new().write(true).truncate(true).open("foo.txt"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions { @@ -637,6 +650,10 @@ impl FileType { pub fn is_symlink(&self) -> bool { self.0.is_symlink() } } +impl AsInner<fs_imp::FileType> for FileType { + fn as_inner(&self) -> &fs_imp::FileType { &self.0 } +} + impl FromInner<fs_imp::FilePermissions> for Permissions { fn from_inner(f: fs_imp::FilePermissions) -> Permissions { Permissions(f) @@ -858,20 +875,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> { - let from = from.as_ref(); - let to = to.as_ref(); - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing file")) - } - - let mut reader = try!(File::open(from)); - let mut writer = try!(File::create(to)); - let perm = try!(reader.metadata()).permissions(); - - let ret = try!(io::copy(&mut reader, &mut writer)); - try!(set_permissions(to, perm)); - Ok(ret) + fs_imp::copy(from.as_ref(), to.as_ref()) } /// Creates a new hard link on the filesystem. @@ -1746,6 +1750,19 @@ mod tests { } #[test] + fn copy_src_does_not_exist() { + let tmpdir = tmpdir(); + let from = Path2::new("test/nonexistent-bogus-path"); + let to = tmpdir.join("out.txt"); + check!(check!(File::create(&to)).write(b"hello")); + assert!(fs::copy(&from, &to).is_err()); + assert!(!from.exists()); + let mut v = Vec::new(); + check!(check!(File::open(&to)).read_to_end(&mut v)); + assert_eq!(v, b"hello"); + } + + #[test] fn copy_file_ok() { let tmpdir = tmpdir(); let input = tmpdir.join("in.txt"); @@ -1814,6 +1831,18 @@ mod tests { check!(fs::set_permissions(&out, attr.permissions())); } + #[cfg(windows)] + #[test] + fn copy_file_preserves_streams() { + let tmp = tmpdir(); + check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes())); + assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 6); + assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0); + let mut v = Vec::new(); + check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v)); + assert_eq!(v, b"carrot".to_vec()); + } + #[cfg(not(windows))] // FIXME(#10264) operation not permitted? #[test] fn symlinks_work() { diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 1d0152e2751..c25aa35ffbe 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -18,10 +18,8 @@ use cmp; use error; use fmt; use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; -use ptr; -use iter; -/// Wraps a `Read` and buffers input from it +/// The `BufReader` struct adds buffering to any reader. /// /// It can be excessively inefficient to work directly with a `Read` instance. /// For example, every call to `read` on `TcpStream` results in a system call. @@ -30,7 +28,7 @@ use iter; /// /// # Examples /// -/// ```no_run +/// ``` /// use std::io::prelude::*; /// use std::io::BufReader; /// use std::fs::File; @@ -54,40 +52,111 @@ 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. + /// + /// # Examples + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("log.txt")); + /// let mut reader = BufReader::new(f); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: R) -> BufReader<R> { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } - /// Creates a new `BufReader` with the specified buffer capacity + /// Creates a new `BufReader` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with ten bytes of capacity: + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::open("log.txt")); + /// let mut reader = BufReader::with_capacity(10, f); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> { - let mut buf = Vec::with_capacity(cap); - buf.extend(iter::repeat(0).take(cap)); BufReader { inner: inner, - buf: buf, + buf: vec![0; cap], pos: 0, cap: 0, } } /// Gets a reference to the underlying reader. + /// + /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f1 = try!(File::open("log.txt")); + /// let mut reader = BufReader::new(f1); + /// + /// let f2 = reader.get_ref(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &R { &self.inner } /// Gets a mutable reference to the underlying reader. /// - /// # Warning - /// /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f1 = try!(File::open("log.txt")); + /// let mut reader = BufReader::new(f1); + /// + /// let f2 = reader.get_mut(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut R { &mut self.inner } /// Unwraps this `BufReader`, returning the underlying reader. /// /// Note that any leftover data in the internal buffer is lost. + /// + /// # Examples + /// + /// ``` + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f1 = try!(File::open("log.txt")); + /// let mut reader = BufReader::new(f1); + /// + /// let f2 = reader.into_inner(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> R { self.inner } } @@ -183,14 +252,49 @@ impl<R: Seek> Seek for BufReader<R> { } } -/// Wraps a Writer and buffers output to it +/// Wraps a writer and buffers its output. /// -/// It can be excessively inefficient to work directly with a `Write`. For -/// example, every call to `write` on `TcpStream` results in a system call. A -/// `BufWriter` keeps an in memory buffer of data and writes it to the -/// underlying `Write` in large, infrequent batches. +/// It can be excessively inefficient to work directly with something that +/// implements `Write`. For example, every call to `write` on `TcpStream` +/// results in a system call. A `BufWriter` keeps an in-memory buffer of data +/// and writes it to an underlying writer in large, infrequent batches. /// /// The buffer will be written out when the writer is dropped. +/// +/// # Examples +/// +/// Let's write the numbers one through ten to a `TcpStream`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::net::TcpStream; +/// +/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// +/// for i in 1..10 { +/// stream.write(&[i]).unwrap(); +/// } +/// ``` +/// +/// Because we're not buffering, we write each one in turn, incurring the +/// overhead of a system call per byte written. We can fix this with a +/// `BufWriter`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// for i in 1..10 { +/// stream.write(&[i]).unwrap(); +/// } +/// ``` +/// +/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped +/// together by the buffer, and will all be written out in one system call when +/// the `stream` is dropped. #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter<W: Write> { inner: Option<W>, @@ -200,18 +304,60 @@ pub struct BufWriter<W: Write> { /// An error returned by `into_inner` which combines an error that /// happened while writing out the buffer, and the buffered writer object /// which may be used to recover from the condition. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// // do stuff with the stream +/// +/// // we want to get our `TcpStream` back, so let's try: +/// +/// let stream = match stream.into_inner() { +/// Ok(s) => s, +/// Err(e) => { +/// // Here, e is an IntoInnerError +/// panic!("An error occurred"); +/// } +/// }; +/// ``` #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] 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. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> BufWriter<W> { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } - /// Creates a new `BufWriter` with the specified buffer capacity + /// Creates a new `BufWriter` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with a buffer of a hundred bytes. + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); + /// let mut buffer = BufWriter::with_capacity(100, stream); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> BufWriter<W> { BufWriter { @@ -238,32 +384,62 @@ impl<W: Write> BufWriter<W> { } } if written > 0 { - // NB: would be better expressed as .remove(0..n) if it existed - unsafe { - ptr::copy(self.buf.as_ptr().offset(written as isize), - self.buf.as_mut_ptr(), - len - written); - } + self.buf.drain(..written); } - self.buf.truncate(len - written); ret } /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_ref(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } - /// Gets a mutable reference to the underlying write. + /// Gets a mutable reference to the underlying writer. /// /// # Warning /// - /// It is inadvisable to directly read from the underlying writer. + /// It is inadvisable to directly write to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_mut(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } /// Unwraps this `BufWriter`, returning the underlying writer. /// /// The buffer is written out before returning the writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // unwrap the TcpStream and flush the buffer + /// let stream = buffer.into_inner().unwrap(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> { match self.flush_buf() { @@ -321,9 +497,34 @@ impl<W: Write> Drop for BufWriter<W> { } impl<W> IntoInnerError<W> { - /// Returns the error which caused the call to `into_inner` to fail. + /// Returns the error which caused the call to `into_inner()` to fail. /// /// This error was returned when attempting to write the internal buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's log the inner error. + /// // + /// // We'll just 'log' to stdout for this example. + /// println!("{}", e.error()); + /// + /// panic!("An unexpected error occurred."); + /// } + /// }; + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn error(&self) -> &Error { &self.1 } @@ -331,6 +532,32 @@ impl<W> IntoInnerError<W> { /// /// The returned object can be used for error recovery, such as /// re-inspecting the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is a IntoInnerError, let's re-examine the buffer: + /// let buffer = e.into_inner(); + /// + /// // do stuff to try to recover + /// + /// // afterwards, let's just return the stream + /// buffer.into_inner().unwrap() + /// } + /// }; + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> W { self.0 } } @@ -354,17 +581,74 @@ impl<W> fmt::Display for IntoInnerError<W> { } } -/// Wraps a Writer and buffers output to it, flushing whenever a newline +/// Wraps a writer and buffers output to it, flushing whenever a newline /// (`0x0a`, `'\n'`) is detected. /// -/// The buffer will be written out when the writer is dropped. +/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output. +/// But it only does this batched write when it goes out of scope, or when the +/// internal buffer is full. Sometimes, you'd prefer to write each line as it's +/// completed, rather than the entire buffer at once. Enter `LineWriter`. It +/// does exactly that. +/// +/// [bufwriter]: struct.BufWriter.html +/// +/// If there's still a partial line in the buffer when the `LineWriter` is +/// dropped, it will flush those contents. +/// +/// # Examples +/// +/// We can use `LineWriter` to write one line at a time, significantly +/// reducing the number of actual writes to the file. +/// +/// ``` +/// use std::fs::File; +/// use std::io::prelude::*; +/// use std::io::LineWriter; +/// +/// # fn foo() -> std::io::Result<()> { +/// let road_not_taken = b"I shall be telling this with a sigh +/// 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."; +/// +/// let file = try!(File::create("poem.txt")); +/// let mut file = LineWriter::new(file); +/// +/// for &byte in road_not_taken.iter() { +/// file.write(&[byte]).unwrap(); +/// } +/// +/// // let's check we did the right thing. +/// let mut file = try!(File::open("poem.txt")); +/// let mut contents = String::new(); +/// +/// try!(file.read_to_string(&mut contents)); +/// +/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter<W: Write> { inner: BufWriter<W>, } impl<W: Write> LineWriter<W> { - /// Creates a new `LineWriter` + /// Creates a new `LineWriter`. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::new(file); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> LineWriter<W> { // Lines typically aren't that long, don't use a giant buffer @@ -373,12 +657,40 @@ impl<W: Write> LineWriter<W> { /// Creates a new `LineWriter` with a specified capacity for the internal /// buffer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::with_capacity(100, file); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> { LineWriter { inner: BufWriter::with_capacity(cap, inner) } } /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let file = LineWriter::new(file); + /// + /// let reference = file.get_ref(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.get_ref() } @@ -386,12 +698,44 @@ impl<W: Write> LineWriter<W> { /// /// Caution must be taken when calling methods on the mutable reference /// returned as extra writes could corrupt the output stream. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// let mut file = LineWriter::new(file); + /// + /// // we can use reference just like file + /// let reference = file.get_mut(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } /// Unwraps this `LineWriter`, returning the underlying writer. /// /// The internal buffer is written out before returning the writer. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// # fn foo() -> std::io::Result<()> { + /// let file = try!(File::create("poem.txt")); + /// + /// let writer: LineWriter<File> = LineWriter::new(file); + /// + /// let file: File = try!(writer.into_inner()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> { self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 72743106abf..4bb7d2ebd19 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -13,19 +13,69 @@ use io::prelude::*; use cmp; use io::{self, SeekFrom, Error, ErrorKind}; -use iter::repeat; use slice; -/// A `Cursor` is a type which wraps a non-I/O object to provide a `Seek` +/// A `Cursor` wraps another type and provides it with a [`Seek`][seek] /// implementation. /// -/// Cursors are typically used with memory buffer objects in order to allow -/// `Seek`, `Read`, and `Write` implementations. For example, common cursor types -/// include `Cursor<Vec<u8>>` and `Cursor<&[u8]>`. +/// [seek]: trait.Seek.html /// -/// Implementations of the I/O traits for `Cursor<T>` are currently not generic -/// over `T` itself. Instead, specific implementations are provided for various -/// in-memory buffer types like `Vec<u8>` and `&[u8]`. +/// 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(&mut buff).unwrap(); +/// +/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Cursor<T> { @@ -35,16 +85,50 @@ pub struct Cursor<T> { 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); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] 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(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] 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(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &T { &self.inner } @@ -52,14 +136,60 @@ impl<T> Cursor<T> { /// /// 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(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut T { &mut self.inner } - /// Returns the current value of this cursor + /// 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); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn position(&self) -> u64 { self.pos } - /// Sets the value of this cursor + /// 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); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn set_position(&mut self, pos: u64) { self.pos = pos; } } @@ -143,7 +273,9 @@ impl Write for Cursor<Vec<u8>> { // currently are let pos = self.position(); let amt = pos.saturating_sub(self.inner.len() as u64); - self.inner.extend(repeat(0).take(amt as usize)); + // 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) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index a66789bf287..3b48ff30960 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -17,11 +17,37 @@ use option::Option::{self, Some, None}; use result; use sys; -/// A type for results generated by I/O related functions where the `Err` type -/// is hard-wired to `io::Error`. +/// A specialized [`Result`][result] type for I/O operations. +/// +/// [result]: ../result/enum.Result.html +/// +/// 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 `std::result::Result`. +/// 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) +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub type Result<T> = result::Result<T, Error>; diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 9021f32fad0..fbdfdeaaef4 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -9,6 +9,235 @@ // except according to those terms. //! Traits, helpers, and type definitions for core I/O functionality. +//! +//! The `std::io` module contains a number of common things you'll need +//! when doing input and output. The most core part of this module is +//! the [`Read`][read] and [`Write`][write] traits, which provide the +//! most general interface for reading and writing input and output. +//! +//! [read]: trait.Read.html +//! [write]: trait.Write.html +//! +//! # Read and Write +//! +//! Because they are traits, they're implemented by a number 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 somtimes even `Vec<T>`s. For example, `Read` +//! adds a `read()` method, which we can use on `File`s: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let mut f = try!(File::open("foo.txt")); +//! let mut buffer = [0; 10]; +//! +//! // read up to 10 bytes +//! try!(f.read(&mut buffer)); +//! +//! println!("The bytes: {:?}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! `Read` and `Write` are so important, implementors of the two traits have a +//! nickname: readers and writers. So you'll sometimes see 'a reader' instead +//! of 'a type that implements the `Read` trait'. Much easier! +//! +//! ## Seek and BufRead +//! +//! Beyond that, there are two important traits that are provided: [`Seek`][seek] +//! and [`BufRead`][bufread]. Both of these build on top of a reader to control +//! how the reading happens. `Seek` lets you control where the next byte is +//! coming from: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::SeekFrom; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let mut f = try!(File::open("foo.txt")); +//! let mut buffer = [0; 10]; +//! +//! // skip to the last 10 bytes of the file +//! try!(f.seek(SeekFrom::End(-10))); +//! +//! // read up to 10 bytes +//! try!(f.read(&mut buffer)); +//! +//! println!("The bytes: {:?}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! [seek]: trait.Seek.html +//! [bufread]: trait.BufRead.html +//! +//! `BufRead` uses an internal buffer to provide a number of other ways to read, but +//! to show it off, we'll need to talk about buffers in general. Keep reading! +//! +//! ## BufReader and BufWriter +//! +//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be +//! making near-constant calls to the operating system. To help with this, +//! `std::io` comes with two structs, `BufReader` and `BufWriter`, which wrap +//! readers and writers. The wrapper uses a buffer, reducing the number of +//! calls and providing nicer methods for accessing exactly what you want. +//! +//! For example, `BufReader` works with the `BufRead` trait to add extra +//! methods to any reader: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(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)); +//! +//! println!("{}", buffer); +//! # Ok(()) +//! # } +//! ``` +//! +//! `BufWriter` doesn't add any new ways of writing, it just buffers every call +//! to [`write()`][write]: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufWriter; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::create("foo.txt")); +//! { +//! let mut writer = BufWriter::new(f); +//! +//! // write a byte to the buffer +//! try!(writer.write(&[42])); +//! +//! } // the buffer is flushed once writer goes out of scope +//! +//! # Ok(()) +//! # } +//! ``` +//! +//! [write]: trait.Write.html#tymethod.write +//! +//! ## Standard input and output +//! +//! A very common source of input is standard input: +//! +//! ``` +//! use std::io; +//! +//! # fn foo() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! try!(io::stdin().read_line(&mut input)); +//! +//! println!("You typed: {}", input.trim()); +//! # Ok(()) +//! # } +//! ``` +//! +//! And a very common source of output is standard output: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! +//! # fn foo() -> io::Result<()> { +//! try!(io::stdout().write(&[42])); +//! # Ok(()) +//! # } +//! ``` +//! +//! Of course, using `io::stdout()` directly is less comon than something like +//! `println!`. +//! +//! ## Iterator types +//! +//! A large number of the structures provided by `std::io` are for various +//! ways of iterating over I/O. For example, `Lines` is used to split over +//! lines: +//! +//! ``` +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! # fn foo() -> io::Result<()> { +//! let f = try!(File::open("foo.txt")); +//! let mut reader = BufReader::new(f); +//! +//! for line in reader.lines() { +//! let line = try!(line); +//! println!("{}", line); +//! } +//! +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Functions +//! +//! There are a number of [functions][functions] that offer access to various +//! features. For example, we can use three of these functions to copy everything +//! from standard input to standard output: +//! +//! ``` +//! use std::io; +//! +//! # fn foo() -> io::Result<()> { +//! try!(io::copy(&mut io::stdin(), &mut io::stdout())); +//! # Ok(()) +//! # } +//! ``` +//! +//! [functions]: #functions +//! +//! ## io::Result +//! +//! Last, but certainly not least, is [`io::Result`][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!`][try] macro: +//! +//! ``` +//! use std::io; +//! +//! fn read_input() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! try!(io::stdin().read_line(&mut input)); +//! +//! println!("You typed: {}", input.trim()); +//! +//! Ok(()) +//! } +//! ``` +//! +//! The return type of `read_input()`, `io::Result<()>`, is a very common type +//! for functions which don't have a 'real' return value, but do want to return +//! errors if they happen. In this case, the only purpose of this function is +//! to read the line and print it, so we use use `()`. +//! +//! [result]: type.Result.html +//! [try]: macro.try!.html #![stable(feature = "rust1", since = "1.0.0")] @@ -16,7 +245,7 @@ use cmp; use rustc_unicode::str as core_str; use error as std_error; use fmt; -use iter::{self, Iterator, Extend}; +use iter::{Iterator}; use marker::Sized; use ops::{Drop, FnOnce}; use option::Option::{self, Some, None}; @@ -106,7 +335,7 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> if new_write_size < DEFAULT_BUF_SIZE { new_write_size *= 2; } - buf.extend(iter::repeat(0).take(new_write_size)); + buf.resize(len + new_write_size, 0); } match r.read(&mut buf[len..]) { @@ -127,14 +356,50 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> ret } -/// A trait for objects which are byte-oriented sources. +/// The `Read` trait allows for reading bytes from a source. /// -/// Readers are defined by one method, `read`. Each call to `read` will attempt -/// to pull bytes from this source into a provided buffer. +/// Implementors of the `Read` trait are sometimes called 'readers'. /// -/// Readers are intended to be composable with one another. Many objects -/// throughout the I/O and related libraries take and provide types which -/// implement the `Read` trait. +/// Readers are defined by one required method, `read()`. Each call to `read` +/// will attempt to pull bytes from this source into a provided buffer. A +/// number of other methods are implemented in terms of `read()`, giving +/// implementors a number of ways to read bytes while only needing to implement +/// a single method. +/// +/// Readers are intended to be composable with one another. Many implementors +/// throughout `std::io` take and provide types which implement the `Read` +/// trait. +/// +/// # Examples +/// +/// [`File`][file]s implement `Read`: +/// +/// [file]: ../std/fs/struct.File.html +/// +/// ``` +/// use std::io; +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// # fn foo() -> io::Result<()> { +/// let mut f = try!(File::open("foo.txt")); +/// let mut buffer = [0; 10]; +/// +/// // read up to 10 bytes +/// try!(f.read(&mut buffer)); +/// +/// let mut buffer = vec![0; 10]; +/// // read the whole file +/// try!(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)); +/// +/// // and more! See the other methods for more details. +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning @@ -164,6 +429,27 @@ pub trait Read { /// If this function encounters any form of I/O or other error, an error /// variant will be returned. If an error is returned then it must be /// guaranteed that no bytes were read. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../std/fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = [0; 10]; + /// + /// // read 10 bytes + /// try!(f.read(&mut buffer[..])); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read(&mut self, buf: &mut [u8]) -> Result<usize>; @@ -185,6 +471,27 @@ pub trait Read { /// If any other read error is encountered then this function immediately /// returns. Any bytes which have already been read will be appended to /// `buf`. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../std/fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = Vec::new(); + /// + /// // read the whole file + /// try!(f.read_to_end(&mut buffer)); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> { read_to_end(self, buf) @@ -200,7 +507,29 @@ pub trait Read { /// If the data in this stream is *not* valid UTF-8 then an error is /// returned and `buf` is unchanged. /// - /// See `read_to_end` for other error semantics. + /// See [`read_to_end()`][readtoend] for other error semantics. + /// + /// [readtoend]: #method.read_to_end + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../std/fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = String::new(); + /// + /// try!(f.read_to_string(&mut buffer)); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_to_string(&mut self, buf: &mut String) -> Result<usize> { // Note that we do *not* call `.read_to_end()` here. We are passing @@ -219,6 +548,36 @@ pub trait Read { /// /// The returned adaptor also implements `Read` and will simply borrow this /// current reader. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../std/fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::Read; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = Vec::new(); + /// let mut other_buffer = Vec::new(); + /// + /// { + /// let reference = f.by_ref(); + /// + /// // read at most 5 bytes + /// try!(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)); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } @@ -228,6 +587,27 @@ pub trait Read { /// R::Err>`. The yielded item is `Ok` if a byte was successfully read and /// `Err` otherwise for I/O errors. EOF is mapped to returning `None` from /// this iterator. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../std/fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// + /// for byte in f.bytes() { + /// println!("{}", byte.unwrap()); + /// } + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn bytes(self) -> Bytes<Self> where Self: Sized { Bytes { inner: self } @@ -243,6 +623,28 @@ pub trait Read { /// /// Currently this adaptor will discard intermediate data read, and should /// be avoided if this is not desired. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../std/fs/struct.File.html + /// + /// ``` + /// #![feature(io)] + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(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")] @@ -255,6 +657,31 @@ pub trait Read { /// The returned `Read` instance will first read all bytes from this object /// until EOF is encountered. Afterwards the output is equivalent to the /// output of `next`. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../std/fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// 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 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)); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn chain<R: Read>(self, next: R) -> Chain<Self, R> where Self: Sized { Chain { first: self, second: next, done_first: false } @@ -266,6 +693,29 @@ pub trait Read { /// `limit` bytes, after which it will always return EOF (`Ok(0)`). Any /// read errors will not count towards the number of bytes read and future /// calls to `read` may succeed. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../std/fs/struct.File.html + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer = [0; 10]; + /// + /// // read at most five bytes + /// let mut handle = f.take(5); + /// + /// try!(handle.read(&mut buffer)); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn take(self, limit: u64) -> Take<Self> where Self: Sized { Take { inner: self, limit: limit } @@ -277,6 +727,31 @@ pub trait Read { /// Whenever the returned `Read` instance is read it will write the read /// data to `out`. The current semantics of this implementation imply that /// a `write` error will not report how much data was initially read. + /// + /// # Examples + /// + /// [`File`][file]s implement `Read`: + /// + /// [file]: ../std/fs/struct.File.html + /// + /// ``` + /// #![feature(io)] + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut f = try!(File::open("foo.txt")); + /// let mut buffer1 = Vec::with_capacity(10); + /// let mut buffer2 = Vec::with_capacity(10); + /// + /// // write the output to buffer1 as we read + /// let mut handle = f.tee(&mut buffer1); + /// + /// try!(handle.read(&mut buffer2)); + /// # Ok(()) + /// # } + /// ``` #[unstable(feature = "io", reason = "the semantics of a partial read/write \ of where errors happen is currently \ unclear and may change")] @@ -287,15 +762,34 @@ pub trait Read { /// A trait for objects which are byte-oriented sinks. /// -/// The `write` method will attempt to write some data into the object, -/// returning how many bytes were successfully written. +/// Implementors of the `Write` trait are sometimes called 'writers'. +/// +/// Writers are defined by two required methods, `write()` and `flush()`: +/// +/// * 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 +/// 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` +/// trait. +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::fs::File; /// -/// 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". +/// # fn foo() -> std::io::Result<()> { +/// let mut buffer = try!(File::create("foo.txt")); /// -/// Writers are intended to be composable with one another. Many objects -/// throughout the I/O and related libraries take and provide types which -/// implement the `Write` trait. +/// try!(buffer.write(b"some bytes")); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Write { /// Write a buffer into this object, returning how many bytes were written. @@ -322,6 +816,20 @@ pub trait Write { /// /// It is **not** considered an error if the entire buffer could not be /// written to this writer. + /// + /// # Examples + /// + /// ``` + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = try!(File::create("foo.txt")); + /// + /// try!(buffer.write(b"some bytes")); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, buf: &[u8]) -> Result<usize>; @@ -332,6 +840,22 @@ pub trait Write { /// /// It is considered an error if not all bytes could be written due to /// I/O errors or EOF being reached. + /// + /// # Examples + /// + /// ``` + /// use std::io::prelude::*; + /// use std::io::BufWriter; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = BufWriter::new(try!(File::create("foo.txt"))); + /// + /// try!(buffer.write(b"some bytes")); + /// try!(buffer.flush()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn flush(&mut self) -> Result<()>; @@ -345,6 +869,20 @@ pub trait Write { /// # Errors /// /// This function will return the first error that `write` returns. + /// + /// # Examples + /// + /// ``` + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = try!(File::create("foo.txt")); + /// + /// try!(buffer.write_all(b"some bytes")); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { while !buf.is_empty() { @@ -362,17 +900,41 @@ pub trait Write { /// Writes a formatted string into this writer, returning any error /// encountered. /// - /// This method is primarily used to interface with the `format_args!` - /// macro, but it is rare that this should explicitly be called. The - /// `write!` macro should be favored to invoke this method instead. + /// This method is primarily used to interface with the + /// [`format_args!`][formatargs] macro, but it is rare that this should + /// explicitly be called. The [`write!`][write] macro should be favored to + /// invoke this method instead. + /// + /// [formatargs]: ../std/macro.format_args!.html + /// [write]: ../std/macro.write!.html /// - /// This function internally uses the `write_all` method on this trait and - /// hence will continuously write data so long as no errors are received. - /// This also means that partial writes are not indicated in this signature. + /// This function internally uses the [`write_all`][writeall] method on + /// this trait and hence will continuously write data so long as no errors + /// are received. This also means that partial writes are not indicated in + /// this signature. + /// + /// [writeall]: #method.write_all /// /// # Errors /// /// This function will return any I/O error reported while formatting. + /// + /// # Examples + /// + /// ``` + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = try!(File::create("foo.txt")); + /// + /// // this call + /// try!(write!(buffer, "{:.*}", 2, 1.234567)); + /// // turns into this: + /// try!(buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { // Create a shim which translates a Write to a fmt::Write and saves @@ -405,6 +967,23 @@ pub trait Write { /// /// The returned adaptor also implements `Write` and will simply borrow this /// current writer. + /// + /// # Examples + /// + /// ``` + /// use std::io::Write; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = try!(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")); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } @@ -416,6 +995,25 @@ pub trait Write { /// implementation do not precisely track where errors happen. For example /// an error on the second call to `write` will not report that the first /// call to `write` succeeded. + /// + /// # Examples + /// + /// ``` + /// #![feature(io)] + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer1 = try!(File::create("foo.txt")); + /// let mut buffer2 = Vec::new(); + /// + /// // write the output to buffer1 as we read + /// let mut handle = buffer1.broadcast(&mut buffer2); + /// + /// try!(handle.write(b"some bytes")); + /// # Ok(()) + /// # } + /// ``` #[unstable(feature = "io", reason = "the semantics of a partial read/write \ of where errors happen is currently \ unclear and may change")] @@ -426,17 +1024,38 @@ pub trait Write { } } -/// An object implementing `Seek` internally has some form of cursor which can -/// be moved within a stream of bytes. +/// The `Seek` trait provides a cursor which can be moved within a stream of +/// bytes. /// /// The stream typically has a fixed size, allowing seeking relative to either /// end or the current offset. +/// +/// # Examples +/// +/// [`File`][file]s implement `Seek`: +/// +/// [file]: ../std/fs/struct.File.html +/// +/// ``` +/// use std::io; +/// use std::io::prelude::*; +/// use std::fs::File; +/// use std::io::SeekFrom; +/// +/// # fn foo() -> io::Result<()> { +/// let mut f = try!(File::open("foo.txt")); +/// +/// // move the cursor 42 bytes from the start of the file +/// try!(f.seek(SeekFrom::Start(42))); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Seek { - /// Seek to an offset, in bytes, in a stream + /// Seek to an offset, in bytes, in a stream. /// - /// A seek beyond the end of a stream is allowed, but seeking before offset - /// 0 is an error. + /// A seek beyond the end of a stream is allowed, but implementation + /// defined. /// /// The behavior when seeking past the end of the stream is implementation /// defined. @@ -446,7 +1065,7 @@ pub trait Seek { /// /// # Errors /// - /// Seeking to a negative offset is considered an error + /// Seeking to a negative offset is considered an error. #[stable(feature = "rust1", since = "1.0.0")] fn seek(&mut self, pos: SeekFrom) -> Result<u64>; } @@ -505,24 +1124,68 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) } } -/// A `BufRead` is a type of reader which has some form of internal buffering to -/// allow certain kinds of reading operations to be more optimized than others. +/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it +/// to perform extra ways of reading. +/// +/// For example, reading line-by-line is inefficient without using a buffer, so +/// if you want to read by line, you'll need `BufRead`, which includes a +/// [`read_line()`][readline] method as well as a [`lines()`][lines] iterator. +/// +/// [readline]: #method.read_line +/// [lines]: #method.lines +/// +/// # Examples +/// +/// A locked standard input implements `BufRead`: +/// +/// ``` +/// use std::io; +/// use std::io::prelude::*; +/// +/// let stdin = io::stdin(); +/// for line in stdin.lock().lines() { +/// println!("{}", line.unwrap()); +/// } +/// ``` +/// +/// If you have something that implements `Read`, you can use the [`BufReader` +/// type][bufreader] to turn it into a `BufRead`. +/// +/// For example, [`File`][file] implements `Read`, but not `BufRead`. +/// `BufReader` to the rescue! /// -/// This type extends the `Read` trait with a few methods that are not -/// possible to reasonably implement with purely a read interface. +/// [bufreader]: struct.BufReader.html +/// [file]: ../fs/struct.File.html +/// +/// ``` +/// use std::io::{self, BufReader}; +/// use std::io::prelude::*; +/// use std::fs::File; +/// +/// # fn foo() -> io::Result<()> { +/// let f = try!(File::open("foo.txt")); +/// let f = BufReader::new(f); +/// +/// for line in f.lines() { +/// println!("{}", line.unwrap()); +/// } +/// +/// # Ok(()) +/// # } +/// ``` /// -/// You can use the [`BufReader` wrapper type](struct.BufReader.html) to turn any -/// reader into a buffered reader. #[stable(feature = "rust1", since = "1.0.0")] pub trait BufRead: Read { /// Fills the internal buffer of this object, returning the buffer contents. /// - /// None of the contents will be "read" in the sense that later calling - /// `read` may return the same contents. + /// This function is a lower-level call. It needs to be paired with the + /// [`consume`][consume] method to function properly. When calling this + /// method, none of the contents will be "read" in the sense that later + /// calling `read` may return the same contents. As such, `consume` must be + /// called with the number of bytes that are consumed from this buffer to + /// ensure that the bytes are never returned twice. /// - /// The `consume` function must be called with the number of bytes that are - /// consumed from this buffer returned to ensure that the bytes are never - /// returned twice. + /// [consume]: #tymethod.consume /// /// An empty buffer returned indicates that the stream has reached EOF. /// @@ -530,34 +1193,66 @@ pub trait BufRead: Read { /// /// This function will return an I/O error if the underlying reader was /// read, but returned an error. + /// + /// # Examples + /// + /// A locked standard input implements `BufRead`: + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// let mut stdin = stdin.lock(); + /// + /// // we can't have two `&mut` references to `stdin`, so use a block + /// // to end the borrow early. + /// let length = { + /// let buffer = stdin.fill_buf().unwrap(); + /// + /// // work with buffer + /// println!("{:?}", buffer); + /// + /// buffer.len() + /// }; + /// + /// // ensure the bytes we worked with aren't returned again later + /// stdin.consume(length); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn fill_buf(&mut self) -> Result<&[u8]>; /// Tells this buffer that `amt` bytes have been consumed from the buffer, /// so they should no longer be returned in calls to `read`. /// - /// This function does not perform any I/O, it simply informs this object - /// that some amount of its buffer, returned from `fill_buf`, has been - /// consumed and should no longer be returned. + /// This function is a lower-level call. It needs to be paired with the + /// [`fill_buf`][fillbuf] method to function properly. This function does + /// not perform any I/O, it simply informs this object that some amount of + /// its buffer, returned from `fill_buf`, has been consumed and should no + /// longer be returned. As such, this function may do odd things if + /// `fill_buf` isn't called before calling it. + /// + /// [fillbuf]: #tymethod.fill_buff + /// + /// The `amt` must be `<=` the number of bytes in the buffer returned by + /// `fill_buf`. /// - /// This function is used to tell the buffer how many bytes you've consumed - /// from the return value of `fill_buf`, and so may do odd things if - /// `fill_buf` isn't called before calling this. + /// # Examples /// - /// The `amt` must be `<=` the number of bytes in the buffer returned by `fill_buf`. + /// Since `consume()` is meant to be used with [`fill_buf()`][fillbuf], + /// that method's example includes an example of `consume()`. #[stable(feature = "rust1", since = "1.0.0")] fn consume(&mut self, amt: usize); - /// Read all bytes until the delimiter `byte` is reached. + /// Read all bytes into `buf` until the delimiter `byte` is reached. /// - /// This function will continue to read (and buffer) bytes from the - /// underlying stream until the delimiter or EOF is found. Once found, all - /// bytes up to, and including, the delimiter (if found) will be appended to - /// `buf`. + /// This function will read bytes from the underlying stream until the + /// delimiter or EOF is found. Once found, all bytes up to, and including, + /// the delimiter (if found) will be appended to `buf`. /// - /// If this buffered reader is currently at EOF, then this function will not - /// place any more bytes into `buf` and will return `Ok(n)` where `n` is the - /// number of bytes which were read. + /// If this reader is currently at EOF then this function will not modify + /// `buf` and will return `Ok(n)` where `n` is the number of bytes which + /// were read. /// /// # Errors /// @@ -566,18 +1261,39 @@ pub trait BufRead: Read { /// /// If an I/O error is encountered then all bytes read so far will be /// present in `buf` and its length will have been adjusted appropriately. + /// + /// # Examples + /// + /// A locked standard input implements `BufRead`. In this example, we'll + /// read from standard input until we see an `a` byte. + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// + /// fn foo() -> io::Result<()> { + /// let stdin = io::stdin(); + /// let mut stdin = stdin.lock(); + /// let mut buffer = Vec::new(); + /// + /// try!(stdin.read_until(b'a', &mut buffer)); + /// + /// println!("{:?}", buffer); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> { read_until(self, byte, buf) } - /// Read all bytes until a newline (the 0xA byte) is reached, and - /// append them to the provided buffer. + /// Read all bytes until a newline (the 0xA byte) is reached, and append + /// them to the provided buffer. /// - /// This function will continue to read (and buffer) bytes from the - /// underlying stream until the newline delimiter (the 0xA byte) or EOF is - /// found. Once found, all bytes up to, and including, the delimiter (if - /// found) will be appended to `buf`. + /// This function will read bytes from the underlying stream until the + /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes + /// up to, and including, the delimiter (if found) will be appended to + /// `buf`. /// /// If this reader is currently at EOF then this function will not modify /// `buf` and will return `Ok(n)` where `n` is the number of bytes which @@ -589,6 +1305,31 @@ pub trait BufRead: Read { /// return an error if the read bytes are not valid UTF-8. If an I/O error /// is encountered then `buf` may contain some bytes already read in the /// event that all data read so far was valid UTF-8. + /// + /// # Examples + /// + /// A locked standard input implements `BufRead`. In this example, we'll + /// read all of the lines from standard input. If we were to do this in + /// an actual project, the [`lines()`][lines] method would be easier, of + /// course. + /// + /// [lines]: #method.lines + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// let mut stdin = stdin.lock(); + /// let mut buffer = String::new(); + /// + /// while stdin.read_line(&mut buffer).unwrap() > 0 { + /// // work with buffer + /// println!("{:?}", buffer); + /// + /// buffer.clear(); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn read_line(&mut self, buf: &mut String) -> Result<usize> { // Note that we are not calling the `.read_until` method here, but @@ -606,6 +1347,22 @@ pub trait BufRead: Read { /// /// This function will yield errors whenever `read_until` would have also /// yielded an error. + /// + /// # Examples + /// + /// A locked standard input implements `BufRead`. In this example, we'll + /// read some input from standard input, splitting on commas. + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// + /// for content in stdin.lock().split(b',') { + /// println!("{:?}", content.unwrap()); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn split(self, byte: u8) -> Split<Self> where Self: Sized { Split { buf: self, delim: byte } @@ -616,6 +1373,21 @@ pub trait BufRead: Read { /// The iterator returned from this function will yield instances of /// `io::Result<String>`. Each string returned will *not* have a newline /// byte (the 0xA byte) at the end. + /// + /// # Examples + /// + /// A locked standard input implements `BufRead`: + /// + /// ``` + /// use std::io; + /// use std::io::prelude::*; + /// + /// let stdin = io::stdin(); + /// + /// for line in stdin.lock().lines() { + /// println!("{}", line.unwrap()); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn lines(self) -> Lines<Self> where Self: Sized { Lines { buf: self } @@ -624,7 +1396,10 @@ pub trait BufRead: Read { /// A `Write` adaptor which will write data to multiple locations. /// -/// For more information, see `Write::broadcast`. +/// This struct is generally created by calling [`broadcast()`][broadcast] on a +/// writer. Please see the documentation of `broadcast()` for more details. +/// +/// [broadcast]: trait.Write.html#method.broadcast #[unstable(feature = "io", reason = "awaiting stability of Write::broadcast")] pub struct Broadcast<T, U> { first: T, @@ -645,9 +1420,12 @@ impl<T: Write, U: Write> Write for Broadcast<T, U> { } } -/// Adaptor to chain together two instances of `Read`. +/// Adaptor to chain together two readers. +/// +/// This struct is generally created by calling [`chain()`][chain] on a reader. +/// Please see the documentation of `chain()` for more details. /// -/// For more information, see `Read::chain`. +/// [chain]: trait.Read.html#method.chain #[stable(feature = "rust1", since = "1.0.0")] pub struct Chain<T, U> { first: T, @@ -670,7 +1448,10 @@ impl<T: Read, U: Read> Read for Chain<T, U> { /// Reader adaptor which limits the bytes read from an underlying reader. /// -/// For more information, see `Read::take`. +/// This struct is generally created by calling [`take()`][take] on a reader. +/// Please see the documentation of `take()` for more details. +/// +/// [take]: trait.Read.html#method.take #[stable(feature = "rust1", since = "1.0.0")] pub struct Take<T> { inner: T, @@ -723,7 +1504,10 @@ impl<T: BufRead> BufRead for Take<T> { /// An adaptor which will emit all read data to a specified writer as well. /// -/// For more information see `Read::tee` +/// This struct is generally created by calling [`tee()`][tee] on a reader. +/// Please see the documentation of `tee()` for more details. +/// +/// [tee]: trait.Read.html#method.tee #[unstable(feature = "io", reason = "awaiting stability of Read::tee")] pub struct Tee<R, W> { reader: R, @@ -740,9 +1524,12 @@ impl<R: Read, W: Write> Read for Tee<R, W> { } } -/// A bridge from implementations of `Read` to an `Iterator` of `u8`. +/// An iterator over `u8` values of a reader. +/// +/// This struct is generally created by calling [`bytes()`][bytes] on a reader. +/// Please see the documentation of `bytes()` for more details. /// -/// See `Read::bytes` for more information. +/// [bytes]: trait.Read.html#method.bytes #[stable(feature = "rust1", since = "1.0.0")] pub struct Bytes<R> { inner: R, @@ -762,9 +1549,12 @@ impl<R: Read> Iterator for Bytes<R> { } } -/// A bridge from implementations of `Read` to an `Iterator` of `char`. +/// An iterator over the `char`s of a reader. /// -/// See `Read::chars` for more information. +/// 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")] pub struct Chars<R> { inner: R, @@ -846,7 +1636,10 @@ impl fmt::Display for CharsError { /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// -/// See `BufRead::split` for more information. +/// This struct is generally created by calling [`split()`][split] on a +/// `BufRead`. Please see the documentation of `split()` for more details. +/// +/// [split]: trait.BufRead.html#method.split #[stable(feature = "rust1", since = "1.0.0")] pub struct Split<B> { buf: B, @@ -872,10 +1665,12 @@ impl<B: BufRead> Iterator for Split<B> { } } -/// An iterator over the lines of an instance of `BufRead` split on a newline -/// byte. +/// An iterator over the lines of an instance of `BufRead`. /// -/// See `BufRead::lines` for more information. +/// This struct is generally created by calling [`lines()`][lines] on a +/// `BufRead`. Please see the documentation of `lines()` for more details. +/// +/// [lines]: trait.BufRead.html#method.lines #[stable(feature = "rust1", since = "1.0.0")] pub struct Lines<B> { buf: B, @@ -906,6 +1701,8 @@ mod tests { use io::prelude::*; use io; use super::Cursor; + use test; + use super::repeat; #[test] fn read_until() { @@ -984,6 +1781,14 @@ mod tests { let mut v = Vec::new(); assert_eq!(c.read_to_end(&mut v).unwrap(), 1); assert_eq!(v, b"1"); + + let cap = 1024 * 1024; + let data = (0..cap).map(|i| (i / 3) as u8).collect::<Vec<_>>(); + let mut v = Vec::new(); + let (a, b) = data.split_at(data.len() / 2); + assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len()); + assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len()); + assert_eq!(v, data); } #[test] @@ -1016,4 +1821,13 @@ mod tests { let mut buf = [0; 1]; assert_eq!(0, R.take(0).read(&mut buf).unwrap()); } + + #[bench] + fn bench_read_to_end(b: &mut test::Bencher) { + b.iter(|| { + let mut lr = repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + super::read_to_end(&mut lr, &mut vec); + }); + } } diff --git a/src/libstd/io/prelude.rs b/src/libstd/io/prelude.rs index 880770eb414..db5c1da8a42 100644 --- a/src/libstd/io/prelude.rs +++ b/src/libstd/io/prelude.rs @@ -17,10 +17,6 @@ //! # #![allow(unused_imports)] //! use std::io::prelude::*; //! ``` -//! -//! This module contains reexports of many core I/O traits such as `Read`, -//! `Write` and `BufRead`. Structures and functions are not -//! contained in this module. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 9fd48f67950..d8b7c8a282c 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -18,6 +18,7 @@ use io::lazy::Lazy; use io::{self, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; +use sys_common::io::{read_to_end_uninitialized}; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use libc; @@ -154,15 +155,42 @@ pub struct StdinLock<'a> { inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>, } -/// Creates a new handle to the global standard input stream of this process. +/// Constructs a new handle to the standard input of the current process. /// -/// The handle returned refers to a globally shared buffer between all threads. -/// Access is synchronized and can be explicitly controlled with the `lock()` -/// method. +/// 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(); +/// try!(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(); /// -/// The `Read` trait is implemented for the returned value but the `BufRead` -/// trait is not due to the global nature of the standard input stream. The -/// locked version, `StdinLock`, implements both `Read` and `BufRead`, however. +/// try!(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); @@ -204,6 +232,28 @@ impl Stdin { /// /// For detailed semantics of this method, see the documentation on /// `BufRead::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(&mut self, buf: &mut String) -> io::Result<usize> { self.lock().read_line(buf) @@ -228,6 +278,9 @@ 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> { + unsafe { read_to_end_uninitialized(self, buf) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -276,13 +329,42 @@ pub struct StdoutLock<'a> { inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>, } -/// Constructs a new reference to the standard output of the current process. +/// 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. Explicit control over synchronization is -/// provided via the `lock` method. +/// is synchronized via a mutex. If you need more explicit control over +/// locking, see the [lock() method][lock]. +/// +/// [lock]: struct.Stdout.html#method.lock +/// +/// # Examples /// -/// The returned handle implements the `Write` trait. +/// Using implicit synchronization: +/// +/// ``` +/// use std::io::{self, Write}; +/// +/// # fn foo() -> io::Result<()> { +/// try!(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(); +/// +/// try!(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>>>>> @@ -354,12 +436,38 @@ pub struct StderrLock<'a> { inner: ReentrantMutexGuard<'a, RefCell<Maybe<StderrRaw>>>, } -/// Constructs a new reference to the standard error stream of a process. +/// 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<()> { +/// try!(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(); /// -/// Each returned handle is synchronized amongst all other handles created from -/// this function. No handles are buffered, however. +/// try!(handle.write(b"hello world")); /// -/// The returned handle implements the `Write` trait. +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init); diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index d8c999f8948..dc29811ed5b 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -28,6 +28,22 @@ use io::{self, Read, Write, ErrorKind, BufRead}; /// 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(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn copy<R: Read, W: Write>(reader: &mut R, writer: &mut W) -> io::Result<u64> { let mut buf = [0; super::DEFAULT_BUF_SIZE]; @@ -45,12 +61,32 @@ pub fn copy<R: Read, W: Write>(reader: &mut R, writer: &mut W) -> io::Result<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 #[stable(feature = "rust1", since = "1.0.0")] pub struct Empty { _priv: () } -/// Creates an instance of an empty reader. +/// 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; +/// use std::io::Read; +/// +/// # fn foo() -> io::Result<String> { +/// let mut buffer = String::new(); +/// try!(io::empty().read_to_string(&mut buffer)); +/// # Ok(buffer) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn empty() -> Empty { Empty { _priv: () } } @@ -64,7 +100,12 @@ impl BufRead for Empty { fn consume(&mut self, _n: usize) {} } -/// A reader which infinitely yields one byte. +/// 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. +/// +/// [empty]: fn.repeat.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Repeat { byte: u8 } @@ -86,6 +127,11 @@ impl Read for Repeat { } /// 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. +/// +/// [empty]: fn.sink.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Sink { _priv: () } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index e27e4ba5af2..440e3a26f6b 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -10,29 +10,116 @@ //! # The Rust Standard Library //! -//! The Rust Standard Library provides the essential runtime -//! functionality for building portable Rust software. +//! The Rust Standard Library is the foundation of portable Rust +//! software, a set of minimal and battle-tested shared abstractions +//! for the [broader Rust ecosystem](https://crates.io). It offers +//! core types (e.g. [`Vec`](vec/index.html) +//! and [`Option`](option/index.html)), library-defined [operations on +//! language primitives](#primitive) (e.g. [`u32`](u32/index.html) and +//! [`str`](str/index.html)), [standard macros](#macros), +//! [I/O](io/index.html) and [multithreading](thread/index.html), among +//! [many other lovely +//! things](#what-is-in-the-standard-library-documentation?). //! -//! The rust standard library is available to all rust crates by -//! default, just as if contained an `extern crate std` import at the -//! crate root. Therefore the standard library can be accessed in -//! `use` statements through the path `std`, as in `use std::thread`, -//! or in expressions through the absolute path `::std`, as in -//! `::std::thread::sleep_ms(100)`. +//! `std` is available to all Rust crates by default, just as if each +//! one contained an `extern crate std` import at the [crate +//! root][book-crate-root]. Therefore the standard library can be +//! accessed in [`use`][book-use] statements through the path `std`, +//! as in [`use std::env`](env/index.html), or in expressions +//! through the absolute path `::std`, as in +//! [`::std::env::args()`](env/fn.args.html). //! -//! Furthermore, the standard library defines [The Rust -//! Prelude](prelude/index.html), a small collection of items, mostly -//! traits, that are imported into and available in every module. +//! [book-crate-root]: ../book/crates-and-modules.html#basic-terminology:-crates-and-modules +//! [book-use]: ../book/crates-and-modules.html#importing-modules-with-use //! -//! ## What is in the standard library +//! # How to read this documentation //! -//! The standard library is a set of minimal, battle-tested -//! core types and shared abstractions for the [broader Rust -//! ecosystem](https://crates.io) to build on. +//! If you already know the name of what you are looking for the +//! fastest way to find it is to use the <a href="#" +//! onclick="focusSearchBar();">search bar</a> at the top of the page. //! -//! The [primitive types](#primitives), though not defined in the -//! standard library, are documented here, as are the predefined -//! [macros](#macros). +//! Otherwise, you may want to jump to one of these useful sections: +//! +//! * [`std::*` modules](#modules) +//! * [Primitive types](#primitives) +//! * [Standard macros](#macros) +//! * [The Rust Prelude](prelude/index.html) +//! +//! If this is your first time, the documentation for the standard +//! library is written to be casually perused. Clicking on interesting +//! things should generally lead you to interesting places. Still, +//! there are important bits you don't want to miss, so read on for a +//! tour of the standard library and its documentation! +//! +//! Once you are familiar with the contents of the standard library +//! you may begin to find the verbosity of the prose distracting. At +//! this stage in your development you may want to press the **[-]** +//! button near the top of the page to collapse it into a more +//! skimmable view. +//! +//! While you are looking at that **[-]** button also notice the +//! **[src]** button. Rust's API documentation comes with the source +//! code and you are encouraged to read it. The standard library +//! source is generally high quality and a peek behind the curtains is +//! often enlightening. +//! +//! # What is in the standard library documentation? +//! +//! Lots of stuff. Well, broadly four things actually. +//! +//! First of all, The Rust Standard Library is divided into a number +//! of focused modules, [all listed further down this page](#modules). +//! These modules are the bedrock upon which all of Rust is forged, +//! and they have mighty names like [`std::slice`](slice/index.html) +//! and [`std::cmp`](cmp/index.html). Modules' documentation typically +//! includes an overview of the module along with examples, and are +//! a smart place to start familiarizing yourself with the library. +//! +//! Second, implicit methods on [primitive +//! types](../book/primitive-types.html) are documented here. This can +//! be a source of confusion for two reasons: +//! +//! 1. While primitives are implemented by the compiler, the standard +//! library implements methods directly on the primitive types (and +//! it is the only library that does so), which are [documented in +//! the section on primitives](#primitives). +//! 2. The standard library exports many modules *with the same name +//! as primitive types*. These define additional items related +//! to the primitive type, but not the all-important methods. +//! +//! So for example there is a [page for the primitive type +//! `i32`](primitive.i32.html) that lists all the methods that can be +//! called on 32-bit integers (mega useful), and there is a [page for +//! the module `std::i32`](i32/index.html) that documents the constant +//! values `MIN` and `MAX` (rarely useful). +//! +//! Note the documentation for the primitives +//! [`str`](primitive.str.html) and [`[T]`](primitive.slice.html) +//! (also called 'slice'). Many method calls on +//! [`String`](string/struct.String.html) and +//! [`Vec`](vec/struct.Vec.html) are actually calls to methods on +//! `str` and `[T]` respectively, via [deref +//! coercions](../book/deref-coercions.html). *Accepting that +//! primitive types are documented on their own pages will bring you a +//! deep inner wisdom. Embrace it now before proceeding.* +//! +//! Third, the standard library defines [The Rust +//! Prelude](prelude/index.html), a small collection of items - mostly +//! traits - that are imported into every module of every crate. The +//! traits in the prelude are pervasive, making the prelude +//! documentation a good entry point to learning about the library. +//! +//! And finally, the standard library exports a number of standard +//! macros, and [lists them on this page](#macros) (technically, not +//! all of the standard macros are defined by the standard library - +//! some are defined by the compiler - but they are documented here +//! the same). Like the prelude, the standard macros are imported by +//! default into all crates. +//! +//! # A Tour of The Rust Standard Library +//! +//! The rest of this crate documentation is dedicated to pointing +//! out notable features of The Rust Standard Library. //! //! ## Containers and collections //! @@ -43,17 +130,29 @@ //! [`Iterator`](iter/trait.Iterator.html), which works with the `for` //! loop to access collections. //! -//! The common container type, `Vec`, a growable vector backed by an array, -//! lives in the [`vec`](vec/index.html) module. Contiguous, unsized regions -//! of memory, `[T]`, commonly called "slices", and their borrowed versions, -//! `&[T]`, commonly called "borrowed slices", are built-in types for which the -//! [`slice`](slice/index.html) module defines many methods. +//! The standard library exposes 3 common ways to deal with contiguous +//! regions of memory: //! -//! `&str`, a UTF-8 string, is a built-in type, and the standard library -//! defines methods for it on a variety of traits in the -//! [`str`](str/index.html) module. Rust strings are immutable; -//! use the `String` type defined in [`string`](string/index.html) -//! for a mutable string builder. +//! * [`Vec<T>`](vec/index.html) - A heap-allocated *vector* that is +//! resizable at runtime. +//! * [`[T; n]`](primitive.array.html) - An inline *array* with a +//! fixed size at compile time. +//! * [`[T]`](primitive.slice.html) - A dynamically sized *slice* into +//! any other kind of contiguous storage, whether heap-allocated or +//! not. +//! +//! Slices can only be handled through some kind of *pointer*, and as +//! such come in many flavours such as: +//! +//! * `&[T]` - *shared slice* +//! * `&mut [T]` - *mutable slice* +//! * [`Box<[T]>`](boxed/index.html) - *owned slice* +//! +//! `str`, a UTF-8 string slice, is a primitive type, and the standard +//! library defines [many methods for it](primitive.str.html). Rust +//! `str`s are typically accessed as immutable references: `&str`. Use +//! the owned `String` type defined in [`string`](string/index.html) +//! for building and mutating strings. //! //! For converting to strings use the [`format!`](fmt/index.html) //! macro, and for converting from strings use the @@ -88,6 +187,7 @@ //! [`atomic`](sync/atomic/index.html) and //! [`mpsc`](sync/mpsc/index.html), which contains the channel types //! for message passing. +//! // Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) #![cfg_attr(stage0, feature(custom_attribute))] @@ -103,12 +203,14 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] +#![cfg_attr(stage0, allow(unused_features))] #![feature(alloc)] #![feature(allow_internal_unstable)] #![feature(associated_consts)] #![feature(borrow_state)] #![feature(box_raw)] #![feature(box_syntax)] +#![feature(char_from_unchecked)] #![feature(char_internals)] #![feature(clone_from_slice)] #![feature(collections)] @@ -119,6 +221,7 @@ #![feature(core_intrinsics)] #![feature(core_prelude)] #![feature(core_simd)] +#![feature(drain)] #![feature(fnbox)] #![feature(heap_api)] #![feature(int_error_internals)] @@ -133,6 +236,7 @@ #![feature(no_std)] #![feature(oom)] #![feature(optin_builtin_traits)] +#![feature(placement_in_syntax)] #![feature(rand)] #![feature(raw)] #![feature(reflect_marker)] @@ -146,11 +250,13 @@ #![feature(unique)] #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(vec_push_all)] +#![feature(vec_resize)] #![feature(wrapping)] #![feature(zero_one)] #![cfg_attr(windows, feature(str_utf16))] -#![cfg_attr(test, feature(float_from_str_radix, range_inclusive, float_extras))] +#![cfg_attr(test, feature(float_from_str_radix, range_inclusive, float_extras, hash_default))] #![cfg_attr(test, feature(test, rustc_private, float_consts))] +#![cfg_attr(target_env = "msvc", feature(link_args))] // Don't link to std. We are std. #![no_std] @@ -312,12 +418,10 @@ pub mod __rand { pub use rand::{thread_rng, ThreadRng, Rng}; } -// Modules that exist purely to document + host impl docs for primitive types - -mod array; -mod bool; -mod unit; -mod tuple; +// Include a number of private modules that exist solely to provide +// the rustdoc documentation for primitive types. Using `include!` +// because rustdoc only looks for these modules at the crate level. +include!("primitive_docs.rs"); // A curious inner-module that's not exported that contains the binding // 'std' so that macro-expanded references to std::error and such diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 02c35e9526d..697b934c676 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -36,28 +36,6 @@ #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable] -/// The entry point for panic of Rust threads. -/// -/// This macro is used to inject panic into a Rust thread, causing the thread to -/// unwind and panic entirely. Each thread's panic can be reaped as the -/// `Box<Any>` type, and the single-argument form of the `panic!` macro will be -/// the value which is transmitted. -/// -/// The multi-argument form of this macro panics with a string and has the -/// `format!` syntax for building a string. -/// -/// # Examples -/// -/// ```should_panic -/// # #![allow(unreachable_code)] -/// panic!(); -/// panic!("this is a terrible mistake!"); -/// panic!(4); // panic with the value of 4 to be collected elsewhere -/// panic!("this is a {} {message}", "fancy", message = "message"); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable] macro_rules! panic { () => ({ panic!("explicit panic") diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index bc13d966a10..61abadd88f1 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -149,9 +149,9 @@ impl Ipv4Addr { /// - 203.0.113.0/24 (TEST-NET-3) pub fn is_documentation(&self) -> bool { match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { - (192, _, 2, _) => true, + (192, 0, 2, _) => true, (198, 51, 100, _) => true, - (203, _, 113, _) => true, + (203, 0, 113, _) => true, _ => false } } @@ -442,7 +442,7 @@ impl fmt::Display for Ipv6Addr { .iter() .map(|&seg| format!("{:x}", seg)) .collect::<Vec<String>>() - .connect(":") + .join(":") } write!(fmt, "{}::{}", @@ -694,11 +694,15 @@ mod tests { check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false); check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false); check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false); + check(&[192, 0, 2, 183], false, false, false, false, false, false, false, true); + check(&[192, 1, 2, 183], false, false, false, false, true, false, false, false); check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false); + check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); + check(&[203, 0, 113, 0], false, false, false, false, false, false, false, true); + check(&[203, 2, 113, 0], false, false, false, false, true, false, false, false); check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false); check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false); - check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); - check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); + check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); } #[test] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 222059e4c0e..c410233df92 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -17,8 +17,9 @@ use io::prelude::*; use fmt; use io; use net::{ToSocketAddrs, SocketAddr, Shutdown}; +use sys_common::io::read_to_end_uninitialized; use sys_common::net as net_imp; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; /// A structure which represents a TCP stream between a local socket and a @@ -189,6 +190,9 @@ impl TcpStream { #[stable(feature = "rust1", since = "1.0.0")] impl Read for TcpStream { 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> { + unsafe { read_to_end_uninitialized(self, buf) } + } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for TcpStream { @@ -198,6 +202,9 @@ impl Write for TcpStream { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Read for &'a TcpStream { 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> { + unsafe { read_to_end_uninitialized(self, buf) } + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for &'a TcpStream { @@ -213,6 +220,10 @@ impl FromInner<net_imp::TcpStream> for TcpStream { fn from_inner(inner: net_imp::TcpStream) -> TcpStream { TcpStream(inner) } } +impl IntoInner<net_imp::TcpStream> for TcpStream { + fn into_inner(self) -> net_imp::TcpStream { self.0 } +} + impl fmt::Debug for TcpStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) @@ -291,6 +302,10 @@ impl FromInner<net_imp::TcpListener> for TcpListener { } } +impl IntoInner<net_imp::TcpListener> for TcpListener { + fn into_inner(self) -> net_imp::TcpListener { self.0 } +} + impl fmt::Debug for TcpListener { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) @@ -904,7 +919,7 @@ mod tests { // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "openbsd"), ignore)] + #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] #[test] fn timeouts() { let addr = next_test_ip4(); diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index c3cf9895205..a98ccc38735 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -17,7 +17,7 @@ use fmt; use io::{self, Error, ErrorKind}; use net::{ToSocketAddrs, SocketAddr, IpAddr}; use sys_common::net as net_imp; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use time::Duration; /// A User Datagram Protocol socket. @@ -174,6 +174,10 @@ impl FromInner<net_imp::UdpSocket> for UdpSocket { fn from_inner(inner: net_imp::UdpSocket) -> UdpSocket { UdpSocket(inner) } } +impl IntoInner<net_imp::UdpSocket> for UdpSocket { + fn into_inner(self) -> net_imp::UdpSocket { self.0 } +} + impl fmt::Debug for UdpSocket { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) @@ -360,9 +364,9 @@ mod tests { assert_eq!(format!("{:?}", udpsock), compare); } - // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code + // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "openbsd"), ignore)] + #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] #[test] fn timeouts() { let addr = next_test_ip4(); diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 0c40f6c1fc8..9d0b9c3bbb4 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -8,16 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for 32-bits floats (`f32` type) +//! The 32-bit floating point type. +//! +//! *[See also the `f32` primitive type](../primitive.f32.html).* #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#![allow(unsigned_negation)] -#![doc(primitive = "f32")] use prelude::v1::*; use core::num; +#[cfg(not(target_env = "msvc"))] use intrinsics; use libc::c_int; use num::{FpCategory, ParseFloatError}; @@ -33,12 +34,7 @@ mod cmath { use libc::{c_float, c_int}; extern { - pub fn acosf(n: c_float) -> c_float; - pub fn asinf(n: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn atan2f(a: c_float, b: c_float) -> c_float; pub fn cbrtf(n: c_float) -> c_float; - pub fn coshf(n: c_float) -> c_float; pub fn erff(n: c_float) -> c_float; pub fn erfcf(n: c_float) -> c_float; pub fn expm1f(n: c_float) -> c_float; @@ -51,32 +47,77 @@ mod cmath { pub fn log1pf(n: c_float) -> c_float; pub fn ilogbf(n: c_float) -> c_int; pub fn modff(n: c_float, iptr: &mut c_float) -> c_float; - pub fn sinhf(n: c_float) -> c_float; - pub fn tanf(n: c_float) -> c_float; - pub fn tanhf(n: c_float) -> c_float; pub fn tgammaf(n: c_float) -> c_float; #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgammaf_r")] pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float; #[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypotf")] pub fn hypotf(x: c_float, y: c_float) -> c_float; + } - #[cfg(any(unix, all(windows, not(target_env = "msvc"))))] + // See the comments in `core::float::Float::floor` for why MSVC is special + // here. + #[cfg(not(target_env = "msvc"))] + extern { + pub fn acosf(n: c_float) -> c_float; + pub fn asinf(n: c_float) -> c_float; + pub fn atan2f(a: c_float, b: c_float) -> c_float; + pub fn atanf(n: c_float) -> c_float; + pub fn coshf(n: c_float) -> c_float; pub fn frexpf(n: c_float, value: &mut c_int) -> c_float; - #[cfg(any(unix, all(windows, not(target_env = "msvc"))))] pub fn ldexpf(x: c_float, n: c_int) -> c_float; + pub fn sinhf(n: c_float) -> c_float; + pub fn tanf(n: c_float) -> c_float; + pub fn tanhf(n: c_float) -> c_float; } - #[cfg(all(windows, target_env = "msvc"))] - pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float { - f64::ldexp(x as f64, n as isize) as c_float - } + #[cfg(target_env = "msvc")] + pub use self::shims::*; + #[cfg(target_env = "msvc")] + mod shims { + use libc::{c_float, c_int}; + + pub unsafe fn acosf(n: c_float) -> c_float { + f64::acos(n as f64) as c_float + } + + pub unsafe fn asinf(n: c_float) -> c_float { + f64::asin(n as f64) as c_float + } + + pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float { + f64::atan2(n as f64, b as f64) as c_float + } + + pub unsafe fn atanf(n: c_float) -> c_float { + f64::atan(n as f64) as c_float + } + + pub unsafe fn coshf(n: c_float) -> c_float { + f64::cosh(n as f64) as c_float + } + + pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float { + let (a, b) = f64::frexp(x as f64); + *value = b as c_int; + a as c_float + } + + pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float { + f64::ldexp(x as f64, n as isize) as c_float + } + + pub unsafe fn sinhf(n: c_float) -> c_float { + f64::sinh(n as f64) as c_float + } - #[cfg(all(windows, target_env = "msvc"))] - pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float { - let (a, b) = f64::frexp(x as f64); - *value = b as c_int; - a as c_float + pub unsafe fn tanf(n: c_float) -> c_float { + f64::tan(n as f64) as c_float + } + + pub unsafe fn tanhf(n: c_float) -> c_float { + f64::tanh(n as f64) as c_float + } } } @@ -761,7 +802,13 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn sin(self) -> f32 { - unsafe { intrinsics::sinf32(self) } + return sinf(self); + + // see notes in `core::f32::Float::floor` + #[cfg(target_env = "msvc")] + fn sinf(f: f32) -> f32 { (f as f64).sin() as f32 } + #[cfg(not(target_env = "msvc"))] + fn sinf(f: f32) -> f32 { unsafe { intrinsics::sinf32(f) } } } /// Computes the cosine of a number (in radians). @@ -778,7 +825,13 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn cos(self) -> f32 { - unsafe { intrinsics::cosf32(self) } + return cosf(self); + + // see notes in `core::f32::Float::floor` + #[cfg(target_env = "msvc")] + fn cosf(f: f32) -> f32 { (f as f64).cos() as f32 } + #[cfg(not(target_env = "msvc"))] + fn cosf(f: f32) -> f32 { unsafe { intrinsics::cosf32(f) } } } /// Computes the tangent of a number (in radians). diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 41c0fcb9797..4f2f59659ac 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for 64-bits floats (`f64` type) +//! The 64-bit floating point type. +//! +//! *[See also the `f64` primitive type](../primitive.f64.html).* #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#![doc(primitive = "f64")] use prelude::v1::*; diff --git a/src/libstd/num/i16.rs b/src/libstd/num/i16.rs index 498f19b9b83..eb53e0821f2 100644 --- a/src/libstd/num/i16.rs +++ b/src/libstd/num/i16.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 16-bits integers (`i16` type) +//! The 16-bit signed integer type. +//! +//! *[See also the `i16` primitive type](../primitive.i16.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i16")] pub use core::i16::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/i32.rs b/src/libstd/num/i32.rs index aea1e92117b..3c9eedf38c7 100644 --- a/src/libstd/num/i32.rs +++ b/src/libstd/num/i32.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 32-bits integers (`i32` type) +//! The 32-bit signed integer type. +//! +//! *[See also the `i32` primitive type](../primitive.i32.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i32")] pub use core::i32::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/i64.rs b/src/libstd/num/i64.rs index 43794345fe7..2df7478a820 100644 --- a/src/libstd/num/i64.rs +++ b/src/libstd/num/i64.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 64-bits integers (`i64` type) +//! The 64-bit signed integer type. +//! +//! *[See also the `i64` primitive type](../primitive.i64.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i64")] pub use core::i64::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/i8.rs b/src/libstd/num/i8.rs index 1b03bf6f4f0..4e4bee8a791 100644 --- a/src/libstd/num/i8.rs +++ b/src/libstd/num/i8.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for signed 8-bits integers (`i8` type) +//! The 8-bit signed integer type. +//! +//! *[See also the `i8` primitive type](../primitive.i8.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i8")] pub use core::i8::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/isize.rs b/src/libstd/num/isize.rs index aa89f858f6f..d46b6b80d0d 100644 --- a/src/libstd/num/isize.rs +++ b/src/libstd/num/isize.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for pointer-sized signed integers (`isize` type) +//! The pointer-sized signed integer type. +//! +//! *[See also the `isize` primitive type](../primitive.isize.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "isize")] pub use core::isize::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u16.rs b/src/libstd/num/u16.rs index 3fda77fb69c..893618aeffa 100644 --- a/src/libstd/num/u16.rs +++ b/src/libstd/num/u16.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 16-bits integers (`u16` type) +//! The 16-bit unsigned integer type. +//! +//! *[See also the `u16` primitive type](../primitive.u16.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u16")] pub use core::u16::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u32.rs b/src/libstd/num/u32.rs index 8610f0c0147..2da25519696 100644 --- a/src/libstd/num/u32.rs +++ b/src/libstd/num/u32.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 32-bits integers (`u32` type) +//! The 32-bit unsigned integer type. +//! +//! *[See also the `u32` primitive type](../primitive.u32.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u32")] pub use core::u32::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u64.rs b/src/libstd/num/u64.rs index 3587b069656..26a8b537394 100644 --- a/src/libstd/num/u64.rs +++ b/src/libstd/num/u64.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 64-bits integer (`u64` type) +//! The 64-bit unsigned integer type. +//! +//! *[See also the `u64` primitive type](../primitive.u64.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u64")] pub use core::u64::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/u8.rs b/src/libstd/num/u8.rs index 6a285e8299c..385754b93a0 100644 --- a/src/libstd/num/u8.rs +++ b/src/libstd/num/u8.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for unsigned 8-bits integers (`u8` type) +//! The 8-bit unsigned integer type. +//! +//! *[See also the `u8` primitive type](../primitive.u8.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u8")] pub use core::u8::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 555a5cc3e20..902c78c0a46 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -9,7 +9,6 @@ // except according to those terms. #![doc(hidden)] -#![allow(unsigned_negation)] macro_rules! uint_module { ($T:ident) => ( diff --git a/src/libstd/num/usize.rs b/src/libstd/num/usize.rs index b54d8ae96c5..6960ba3b829 100644 --- a/src/libstd/num/usize.rs +++ b/src/libstd/num/usize.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations and constants for pointer-sized unsigned integers (`usize` type) +//! The pointer-sized unsigned integer type. +//! +//! *[See also the `usize` primitive type](../primitive.usize.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "usize")] pub use core::usize::{BITS, BYTES, MIN, MAX}; diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index cc4b1c944e7..859cb900460 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -24,6 +24,7 @@ #[cfg(target_os = "linux")] pub mod linux; #[cfg(target_os = "macos")] pub mod macos; #[cfg(target_os = "nacl")] pub mod nacl; +#[cfg(target_os = "netbsd")] pub mod netbsd; #[cfg(target_os = "openbsd")] pub mod openbsd; pub mod raw; diff --git a/src/libstd/array.rs b/src/libstd/os/netbsd/mod.rs index a6b8cd71a3b..bdb003b877b 100644 --- a/src/libstd/array.rs +++ b/src/libstd/os/netbsd/mod.rs @@ -8,6 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! The fixed-size array type (`[T; n]`). +//! OpenBSD-specific definitions -#![doc(primitive = "array")] +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod raw; + +pub mod fs { + #![stable(feature = "raw_ext", since = "1.1.0")] + pub use sys::fs::MetadataExt; +} diff --git a/src/libstd/os/netbsd/raw.rs b/src/libstd/os/netbsd/raw.rs new file mode 100644 index 00000000000..f9898dfbdb5 --- /dev/null +++ b/src/libstd/os/netbsd/raw.rs @@ -0,0 +1,71 @@ +// 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. + +//! NetBSD/OpenBSD-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +use os::raw::c_long; +use os::unix::raw::{uid_t, gid_t}; + +#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = i32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64; +#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; + +#[repr(C)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: mode_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: ino_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: nlink_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: uid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: gid_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: dev_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: off_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: blkcnt_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: blksize_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_flags: fflags_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gen: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_birthtime_nsec: c_long, +} diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index 156a3d428de..275f415c6fc 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -22,18 +22,107 @@ //! with the `std::` path prefix, as in `use std::vec`, `use std::thread::spawn`, //! etc. //! -//! Additionally, `std` contains a `prelude` module that reexports many of the -//! most common traits, types and functions. The contents of the prelude are -//! imported into every *module* by default. Implicitly, all modules behave as if -//! they contained the following prologue: +//! Additionally, `std` contains a versioned *prelude* that reexports many of the +//! most common traits, types and functions. *The contents of the prelude are +//! imported into every module by default*. Implicitly, all modules behave as if +//! they contained the following [`use` statement][book-use]: +//! +//! [book-use]: ../../book/crates-and-modules.html#importing-modules-with-use //! //! ```ignore //! use std::prelude::v1::*; //! ``` //! -//! The prelude is primarily concerned with exporting *traits* that are so -//! pervasive that it would be obnoxious to import for every use, particularly -//! those that define methods on primitive types. +//! The prelude is primarily concerned with exporting *traits* that +//! are so pervasive that they would be onerous to import for every use, +//! particularly those that are commonly mentioned in [generic type +//! bounds][book-traits]. +//! +//! The current version of the prelude (version 1) lives in +//! [`std::prelude::v1`](v1/index.html), and reexports the following. +//! +//! * `std::marker::`{ +//! [`Copy`](../marker/trait.Copy.html), +//! [`Send`](../marker/trait.Send.html), +//! [`Sized`](../marker/trait.Sized.html), +//! [`Sync`](../marker/trait.Sync.html) +//! }. +//! The marker traits indicate fundamental properties of types. +//! * `std::ops::`{ +//! [`Drop`](../ops/trait.Drop.html), +//! [`Fn`](../ops/trait.Fn.html), +//! [`FnMut`](../ops/trait.FnMut.html), +//! [`FnOnce`](../ops/trait.FnOnce.html) +//! }. +//! The [destructor][book-dtor] trait and the +//! [closure][book-closures] traits, reexported from the same +//! [module that also defines overloaded +//! operators](../ops/index.html). +//! * `std::mem::`[`drop`](../mem/fn.drop.html). +//! A convenience function for explicitly dropping a value. +//! * `std::boxed::`[`Box`](../boxed/struct.Box.html). +//! The owned heap pointer. +//! * `std::borrow::`[`ToOwned`](../borrow/trait.ToOwned.html). +//! The conversion trait that defines `to_owned`, the generic method +//! for creating an owned type from a borrowed type. +//! * `std::clone::`[`Clone`](../clone/trait.Clone.html). +//! The ubiquitous trait that defines `clone`, the method for +//! producing copies of values that are consider expensive to copy. +//! * `std::cmp::`{ +//! [`PartialEq`](../cmp/trait.PartialEq.html), +//! [`PartialOrd`](../cmp/trait.PartialOrd.html), +//! [`Eq`](../cmp/trait.Eq.html), +//! [`Ord`](../cmp/trait.Ord.html) +//! }. +//! The comparision traits, which implement the comparison operators +//! and are often seen in trait bounds. +//! * `std::convert::`{ +//! [`AsRef`](../convert/trait.AsRef.html), +//! [`AsMut`](../convert/trait.AsMut.html), +//! [`Into`](../convert/trait.Into.html), +//! [`From`](../convert/trait.From.html) +//! }. +//! Generic conversions, used by savvy API authors to create +//! overloaded methods. +//! * `std::default::`[`Default`](../default/trait.Default). +//! Types that have default values. +//! * `std::iter::`{ +//! [`Iterator`](../iter/trait.Iterator.html), +//! [`Extend`](../iter/trait.Extend.html), +//! [`IntoIterator`](../iter/trait.IntoIterator.html), +//! [`DoubleEndedIterator`](../iter/trait.DoubleEndedIterator.html), +//! [`ExactSizeIterator`](../iter/trait.ExactSizeIterator.html) +//! }. +//! [Iterators][book-iter]. +//! * `std::option::Option::`{ +//! [`self`](../option/enum.Option.html), +//! [`Some`](../option/enum.Option.html), +//! [`None`](../option/enum.Option.html) +//! }. +//! The ubiquitous `Option` type and its two [variants][book-enums], +//! `Some` and `None`. +//! * `std::result::Result::`{ +//! [`self`](../result/enum.Result.html), +//! [`Some`](../result/enum.Result.html), +//! [`None`](../result/enum.Result.html) +//! }. +//! The ubiquitous `Result` type and its two [variants][book-enums], +//! `Ok` and `Err`. +//! * `std::slice::`[`SliceConcatExt`](../slice/trait.SliceConcatExt.html). +//! An unstable extension to slices that shouldn't have to exist. +//! * `std::string::`{ +//! [`String`](../string/struct.String.html), +//! [`ToString`](../string/trait.ToString.html) +//! }. +//! Heap allocated strings. +//! * `std::vec::`[`Vec`](../vec/struct.Vec.html). +//! Heap allocated vectors. +//! +//! [book-traits]: ../../book/traits.html +//! [book-closures]: ../../book/closures.html +//! [book-dtor]: ../../book/drop.html +//! [book-iter]: ../../book/iterators.html +//! [book-enums]: ../../book/enums.html #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs new file mode 100644 index 00000000000..066b2b576da --- /dev/null +++ b/src/libstd/primitive_docs.rs @@ -0,0 +1,420 @@ +// 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. + +#[doc(primitive = "bool")] +// +/// The boolean type. +/// +mod prim_bool { } + +#[doc(primitive = "char")] +// +/// A Unicode scalar value. +/// +/// A `char` represents a +/// *[Unicode scalar +/// value](http://www.unicode.org/glossary/#unicode_scalar_value)*, as it can +/// contain any Unicode code point except high-surrogate and low-surrogate code +/// points. +/// +/// As such, only values in the ranges \[0x0,0xD7FF\] and \[0xE000,0x10FFFF\] +/// (inclusive) are allowed. A `char` can always be safely cast to a `u32`; +/// however the converse is not always true due to the above range limits +/// and, as such, should be performed via the `from_u32` function. +/// +/// *[See also the `std::char` module](char/index.html).* +/// +mod prim_char { } + +#[doc(primitive = "unit")] +// +/// The `()` type, sometimes called "unit" or "nil". +/// +/// The `()` type has exactly one value `()`, and is used when there +/// is no other meaningful value that could be returned. `()` is most +/// commonly seen implicitly: functions without a `-> ...` implicitly +/// have return type `()`, that is, these are equivalent: +/// +/// ```rust +/// fn long() -> () {} +/// +/// fn short() {} +/// ``` +/// +/// The semicolon `;` can be used to discard the result of an +/// expression at the end of a block, making the expression (and thus +/// the block) evaluate to `()`. For example, +/// +/// ```rust +/// fn returns_i64() -> i64 { +/// 1i64 +/// } +/// fn returns_unit() { +/// 1i64; +/// } +/// +/// let is_i64 = { +/// returns_i64() +/// }; +/// let is_unit = { +/// returns_i64(); +/// }; +/// ``` +/// +mod prim_unit { } + +#[doc(primitive = "pointer")] +// +/// Raw, unsafe pointers, `*const T`, and `*mut T`. +/// +/// Working with raw pointers in Rust is uncommon, +/// typically limited to a few patterns. +/// +/// Use the `null` function to create null pointers, and the `is_null` method +/// of the `*const T` type to check for null. The `*const T` type also defines +/// the `offset` method, for pointer math. +/// +/// # Common ways to create raw pointers +/// +/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). +/// +/// ``` +/// let my_num: i32 = 10; +/// let my_num_ptr: *const i32 = &my_num; +/// let mut my_speed: i32 = 88; +/// let my_speed_ptr: *mut i32 = &mut my_speed; +/// ``` +/// +/// To get a pointer to a boxed value, dereference the box: +/// +/// ``` +/// let my_num: Box<i32> = Box::new(10); +/// let my_num_ptr: *const i32 = &*my_num; +/// let mut my_speed: Box<i32> = Box::new(88); +/// let my_speed_ptr: *mut i32 = &mut *my_speed; +/// ``` +/// +/// This does not take ownership of the original allocation +/// and requires no resource management later, +/// but you must not use the pointer after its lifetime. +/// +/// ## 2. Consume a box (`Box<T>`). +/// +/// The `into_raw` function consumes a box and returns +/// the raw pointer. It doesn't destroy `T` or deallocate any memory. +/// +/// ``` +/// # #![feature(box_raw)] +/// let my_speed: Box<i32> = Box::new(88); +/// let my_speed: *mut i32 = Box::into_raw(my_speed); +/// +/// // By taking ownership of the original `Box<T>` though +/// // we are obligated to put it together later to be destroyed. +/// unsafe { +/// drop(Box::from_raw(my_speed)); +/// } +/// ``` +/// +/// Note that here the call to `drop` is for clarity - it indicates +/// that we are done with the given value and it should be destroyed. +/// +/// ## 3. Get it from C. +/// +/// ``` +/// # #![feature(libc)] +/// extern crate libc; +/// +/// use std::mem; +/// +/// fn main() { +/// unsafe { +/// let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>() as libc::size_t) as *mut i32; +/// if my_num.is_null() { +/// panic!("failed to allocate memory"); +/// } +/// libc::free(my_num as *mut libc::c_void); +/// } +/// } +/// ``` +/// +/// Usually you wouldn't literally use `malloc` and `free` from Rust, +/// but C APIs hand out a lot of pointers generally, so are a common source +/// of raw pointers in Rust. +/// +/// *[See also the `std::ptr` module](ptr/index.html).* +/// +mod prim_pointer { } + +#[doc(primitive = "array")] +// +/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and +/// the non-negative compile time constant size, `N`. +/// +/// Arrays values are created either with an explicit expression that lists +/// each element: `[x, y, z]` or a repeat expression: `[x; N]`. The repeat +/// expression requires that the element type is `Copy`. +/// +/// The type `[T; N]` is `Copy` if `T: Copy`. +/// +/// Arrays of sizes from 0 to 32 (inclusive) implement the following traits +/// if the element type allows it: +/// +/// - `Clone` +/// - `Debug` +/// - `IntoIterator` (implemented for `&[T; N]` and `&mut [T; N]`) +/// - `PartialEq`, `PartialOrd`, `Ord`, `Eq` +/// - `Hash` +/// - `AsRef`, `AsMut` +/// +/// Arrays dereference to [slices (`[T]`)][slice], so their methods can be called +/// on arrays. +/// +/// [slice]: primitive.slice.html +/// +/// Rust does not currently support generics over the size of an array type. +/// +/// # Examples +/// +/// ``` +/// let mut array: [i32; 3] = [0; 3]; +/// +/// array[1] = 1; +/// array[2] = 2; +/// +/// assert_eq!([1, 2], &array[1..]); +/// +/// // This loop prints: 0 1 2 +/// for x in &array { +/// print!("{} ", x); +/// } +/// +/// ``` +/// +mod prim_array { } + +#[doc(primitive = "slice")] +// +/// A dynamically-sized view into a contiguous sequence, `[T]`. +/// +/// Slices are a view into a block of memory represented as a pointer and a +/// length. +/// +/// ``` +/// // slicing a Vec +/// let vec = vec![1, 2, 3]; +/// let int_slice = &vec[..]; +/// // coercing an array to a slice +/// let str_slice: &[&str] = &["one", "two", "three"]; +/// ``` +/// +/// Slices are either mutable or shared. The shared slice type is `&[T]`, +/// while the mutable slice type is `&mut [T]`, where `T` represents the element +/// type. For example, you can mutate the block of memory that a mutable slice +/// points to: +/// +/// ``` +/// let x = &mut [1, 2, 3]; +/// x[1] = 7; +/// assert_eq!(x, &[1, 7, 3]); +/// ``` +/// +/// *[See also the `std::slice` module](slice/index.html).* +/// +mod prim_slice { } + +#[doc(primitive = "str")] +// +/// Unicode string slices. +/// +/// Rust's `str` type is one of the core primitive types of the language. `&str` +/// is the borrowed string type. This type of string can only be created from +/// other strings, unless it is a `&'static str` (see below). It is not possible +/// to move out of borrowed strings because they are owned elsewhere. +/// +/// # Examples +/// +/// Here's some code that uses a `&str`: +/// +/// ``` +/// let s = "Hello, world."; +/// ``` +/// +/// This `&str` is a `&'static str`, which is the type of string literals. +/// They're `'static` because literals are available for the entire lifetime of +/// the program. +/// +/// You can get a non-`'static` `&str` by taking a slice of a `String`: +/// +/// ``` +/// let some_string = "Hello, world.".to_string(); +/// let s = &some_string; +/// ``` +/// +/// # Representation +/// +/// Rust's string type, `str`, is a sequence of Unicode scalar values encoded as +/// a stream of UTF-8 bytes. All [strings](../../reference.html#literals) are +/// guaranteed to be validly encoded UTF-8 sequences. Additionally, strings are +/// not null-terminated and can thus contain null bytes. +/// +/// The actual representation of `str`s have direct mappings to slices: `&str` +/// is the same as `&[u8]`. +/// +/// *[See also the `std::str` module](str/index.html).* +/// +mod prim_str { } + +#[doc(primitive = "tuple")] +// +/// A finite heterogeneous sequence, `(T, U, ..)`. +/// +/// To access the _N_-th element of a tuple one can use `N` itself +/// as a field of the tuple. +/// +/// Indexing starts from zero, so `0` returns first value, `1` +/// returns second value, and so on. In general, a tuple with _S_ +/// elements provides aforementioned fields from `0` to `S-1`. +/// +/// If every type inside a tuple implements one of the following +/// traits, then a tuple itself also implements it. +/// +/// * `Clone` +/// * `PartialEq` +/// * `Eq` +/// * `PartialOrd` +/// * `Ord` +/// * `Debug` +/// * `Default` +/// * `Hash` +/// +/// # Examples +/// +/// Accessing elements of a tuple at specified indices: +/// +/// ``` +/// let x = ("colorless", "green", "ideas", "sleep", "furiously"); +/// assert_eq!(x.3, "sleep"); +/// +/// let v = (3, 3); +/// let u = (1, -5); +/// assert_eq!(v.0 * u.0 + v.1 * u.1, -12); +/// ``` +/// +/// Using traits implemented for tuples: +/// +/// ``` +/// let a = (1, 2); +/// let b = (3, 4); +/// assert!(a != b); +/// +/// let c = b.clone(); +/// assert!(b == c); +/// +/// let d : (u32, f32) = Default::default(); +/// assert_eq!(d, (0, 0.0f32)); +/// ``` +/// +mod prim_tuple { } + +#[doc(primitive = "f32")] +/// The 32-bit floating point type. +/// +/// *[See also the `std::f32` module](f32/index.html).* +/// +mod prim_f32 { } + +#[doc(primitive = "f64")] +// +/// The 64-bit floating point type. +/// +/// *[See also the `std::f64` module](f64/index.html).* +/// +mod prim_f64 { } + +#[doc(primitive = "i8")] +// +/// The 8-bit signed integer type. +/// +/// *[See also the `std::i8` module](i8/index.html).* +/// +mod prim_i8 { } + +#[doc(primitive = "i16")] +// +/// The 16-bit signed integer type. +/// +/// *[See also the `std::i16` module](i16/index.html).* +/// +mod prim_i16 { } + +#[doc(primitive = "i32")] +// +/// The 32-bit signed integer type. +/// +/// *[See also the `std::i32` module](i32/index.html).* +/// +mod prim_i32 { } + +#[doc(primitive = "i64")] +// +/// The 64-bit signed integer type. +/// +/// *[See also the `std::i64` module](i64/index.html).* +/// +mod prim_i64 { } + +#[doc(primitive = "u8")] +// +/// The 8-bit unsigned integer type. +/// +/// *[See also the `std::u8` module](u8/index.html).* +/// +mod prim_u8 { } + +#[doc(primitive = "u16")] +// +/// The 16-bit unsigned integer type. +/// +/// *[See also the `std::u16` module](u16/index.html).* +/// +mod prim_u16 { } + +#[doc(primitive = "u32")] +// +/// The 32-bit unsigned integer type. +/// +/// *[See also the `std::u32` module](u32/index.html).* +/// +mod prim_u32 { } + +#[doc(primitive = "u64")] +// +/// The 64-bit unsigned integer type. +/// +/// *[See also the `std::u64` module](u64/index.html).* +/// +mod prim_u64 { } + +#[doc(primitive = "isize")] +// +/// The pointer-sized signed integer type. +/// +/// *[See also the `std::isize` module](isize/index.html).* +/// +mod prim_isize { } + +#[doc(primitive = "usize")] +// +/// The pointer-sized signed integer type. +/// +/// *[See also the `std::usize` module](usize/index.html).* +/// +mod prim_usize { } + diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a8127b3200f..3471805b2bc 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -23,7 +23,7 @@ use path; use sync::mpsc::{channel, Receiver}; use sys::pipe::{self, AnonPipe}; use sys::process as imp; -use sys_common::{AsInner, AsInnerMut, FromInner}; +use sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use thread; /// Representation of a running or exited child process. @@ -71,6 +71,10 @@ impl AsInner<imp::Process> for Child { fn as_inner(&self) -> &imp::Process { &self.handle } } +impl IntoInner<imp::Process> for Child { + fn into_inner(self) -> imp::Process { self.handle } +} + /// A handle to a child procesess's stdin #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdin { @@ -92,6 +96,10 @@ impl AsInner<AnonPipe> for ChildStdin { fn as_inner(&self) -> &AnonPipe { &self.inner } } +impl IntoInner<AnonPipe> for ChildStdin { + fn into_inner(self) -> AnonPipe { self.inner } +} + /// A handle to a child procesess's stdout #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdout { @@ -109,6 +117,10 @@ impl AsInner<AnonPipe> for ChildStdout { fn as_inner(&self) -> &AnonPipe { &self.inner } } +impl IntoInner<AnonPipe> for ChildStdout { + fn into_inner(self) -> AnonPipe { self.inner } +} + /// A handle to a child procesess's stderr #[stable(feature = "process", since = "1.0.0")] pub struct ChildStderr { @@ -126,6 +138,10 @@ impl AsInner<AnonPipe> for ChildStderr { fn as_inner(&self) -> &AnonPipe { &self.inner } } +impl IntoInner<AnonPipe> for ChildStderr { + fn into_inner(self) -> AnonPipe { self.inner } +} + /// The `Command` type acts as a process builder, providing fine-grained control /// over how a new process should be spawned. A default configuration can be /// generated using `Command::new(program)`, where `program` gives a path to the diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index a2e6915a6a6..3f75c8bca83 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -41,10 +41,10 @@ mod imp { const NR_GETRANDOM: libc::c_long = 318; #[cfg(target_arch = "x86")] const NR_GETRANDOM: libc::c_long = 355; - #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] - const NR_GETRANDOM: libc::c_long = 384; - #[cfg(target_arch = "powerpc")] + #[cfg(any(target_arch = "arm", target_arch = "powerpc"))] const NR_GETRANDOM: libc::c_long = 384; + #[cfg(any(target_arch = "aarch64"))] + const NR_GETRANDOM: libc::c_long = 278; unsafe { syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0) @@ -187,7 +187,7 @@ mod imp { use io; use mem; use rand::Rng; - use libc::{c_int, size_t}; + use libc::{c_int, c_void, size_t}; /// A random number generator that retrieves randomness straight from /// the operating system. Platform sources: @@ -205,8 +205,9 @@ mod imp { _dummy: (), } - #[repr(C)] - struct SecRandom; + // Fake definition; this is actually a struct, but we don't use the + // contents here. + type SecRandom = c_void; #[allow(non_upper_case_globals)] const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom; diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index d23a124a6ec..52697f00264 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -44,6 +44,7 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() } target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod imp { use prelude::v1::*; diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/rt/libunwind.rs index 8f75ae5ef5c..d99b31c9f2b 100644 --- a/src/libstd/rt/libunwind.rs +++ b/src/libstd/rt/libunwind.rs @@ -106,7 +106,7 @@ extern {} #[link(name = "unwind", kind = "static")] extern {} -#[cfg(any(target_os = "android", target_os = "openbsd"))] +#[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))] #[link(name = "gcc")] extern {} diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 1729d20da20..0ac0d03e19d 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -96,7 +96,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { // own fault handlers if we hit it. sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); - sys::thread::guard::init(); + let main_guard = sys::thread::guard::init(); sys::stack_overflow::init(); // Next, set up the current Thread with the guard information we just @@ -104,7 +104,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { // but we just do this to name the main thread and to give it correct // info about the stack bounds. let thread: Thread = NewThread::new(Some("<main>".to_string())); - thread_info::set(sys::thread::guard::main(), thread); + thread_info::set(main_guard, thread); // By default, some platforms will send a *signal* when a EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE diff --git a/src/libstd/rt/unwind/gcc.rs b/src/libstd/rt/unwind/gcc.rs index 84c6d6864a9..59fc8df6107 100644 --- a/src/libstd/rt/unwind/gcc.rs +++ b/src/libstd/rt/unwind/gcc.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(private_no_mangle_fns)] + use prelude::v1::*; use any::Any; -use libc::c_void; use rt::libunwind as uw; struct Exception { @@ -41,7 +42,7 @@ pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! { } } -pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> { +pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> { let my_ep = ptr as *mut Exception; rtdebug!("caught {}", (*my_ep).uwe.exception_class); let cause = (*my_ep).cause.take(); @@ -89,7 +90,7 @@ pub mod eabi { use rt::libunwind as uw; use libc::c_int; - extern "C" { + extern { fn __gcc_personality_v0(version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -98,9 +99,8 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] + #[lang = "eh_personality"] + #[no_mangle] extern fn rust_eh_personality( version: c_int, actions: uw::_Unwind_Action, @@ -115,8 +115,9 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( _version: c_int, actions: uw::_Unwind_Action, _exception_class: uw::_Unwind_Exception_Class, @@ -142,7 +143,7 @@ pub mod eabi { use rt::libunwind as uw; use libc::c_int; - extern "C" { + extern { fn __gcc_personality_sj0(version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -151,9 +152,9 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality( + #[lang = "eh_personality"] + #[no_mangle] + pub extern fn rust_eh_personality( version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -167,8 +168,9 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( _version: c_int, actions: uw::_Unwind_Action, _exception_class: uw::_Unwind_Exception_Class, @@ -196,17 +198,16 @@ pub mod eabi { use rt::libunwind as uw; use libc::c_int; - extern "C" { + extern { fn __gcc_personality_v0(state: uw::_Unwind_State, ue_header: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context) -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] - extern "C" fn rust_eh_personality( + #[lang = "eh_personality"] + #[no_mangle] + extern fn rust_eh_personality( state: uw::_Unwind_State, ue_header: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context @@ -217,8 +218,9 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( state: uw::_Unwind_State, _ue_header: *mut uw::_Unwind_Exception, _context: *mut uw::_Unwind_Context @@ -249,12 +251,11 @@ pub mod eabi { use rt::libunwind as uw; use libc::{c_void, c_int}; - #[repr(C)] - pub struct EXCEPTION_RECORD; - #[repr(C)] - pub struct CONTEXT; - #[repr(C)] - pub struct DISPATCHER_CONTEXT; + // Fake definitions; these are actually complicated structs, + // but we don't use the contents here. + pub type EXCEPTION_RECORD = c_void; + pub type CONTEXT = c_void; + pub type DISPATCHER_CONTEXT = c_void; #[repr(C)] #[derive(Copy, Clone)] @@ -266,7 +267,7 @@ pub mod eabi { } type _Unwind_Personality_Fn = - extern "C" fn( + extern fn( version: c_int, actions: uw::_Unwind_Action, exception_class: uw::_Unwind_Exception_Class, @@ -274,7 +275,7 @@ pub mod eabi { context: *mut uw::_Unwind_Context ) -> uw::_Unwind_Reason_Code; - extern "C" { + extern { fn __gcc_personality_seh0( exceptionRecord: *mut EXCEPTION_RECORD, establisherFrame: *mut c_void, @@ -291,10 +292,9 @@ pub mod eabi { ) -> EXCEPTION_DISPOSITION; } - #[lang="eh_personality"] - #[no_mangle] // referenced from rust_try.ll - #[allow(private_no_mangle_fns)] - extern "C" fn rust_eh_personality( + #[lang = "eh_personality"] + #[no_mangle] + extern fn rust_eh_personality( exceptionRecord: *mut EXCEPTION_RECORD, establisherFrame: *mut c_void, contextRecord: *mut CONTEXT, @@ -307,15 +307,16 @@ pub mod eabi { } } - #[no_mangle] // referenced from rust_try.ll - pub extern "C" fn rust_eh_personality_catch( + #[cfg_attr(not(stage0), lang = "eh_personality_catch")] + #[no_mangle] + pub extern fn rust_eh_personality_catch( exceptionRecord: *mut EXCEPTION_RECORD, establisherFrame: *mut c_void, contextRecord: *mut CONTEXT, dispatcherContext: *mut DISPATCHER_CONTEXT ) -> EXCEPTION_DISPOSITION { - extern "C" fn inner( + extern fn inner( _version: c_int, actions: uw::_Unwind_Action, _exception_class: uw::_Unwind_Exception_Class, diff --git a/src/libstd/rt/unwind/mod.rs b/src/libstd/rt/unwind/mod.rs index c403976745a..db2310ba361 100644 --- a/src/libstd/rt/unwind/mod.rs +++ b/src/libstd/rt/unwind/mod.rs @@ -69,7 +69,6 @@ use cmp; use panicking; use fmt; use intrinsics; -use libc::c_void; use mem; use sync::atomic::{self, Ordering}; use sys_common::mutex::Mutex; @@ -127,7 +126,7 @@ extern {} /// run. pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> { let mut f = Some(f); - return inner_try(try_fn::<F>, &mut f as *mut _ as *mut c_void); + return inner_try(try_fn::<F>, &mut f as *mut _ as *mut u8); // If an inner function were not used here, then this generic function `try` // uses the native symbol `rust_try`, for which the code is statically @@ -140,11 +139,12 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> { // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll` // files and instead just have this non-generic shim the compiler can take // care of exposing correctly. - unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void) + #[cfg(not(stage0))] + unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) -> Result<(), Box<Any + Send>> { let prev = PANICKING.with(|s| s.get()); PANICKING.with(|s| s.set(false)); - let ep = rust_try(f, data); + let ep = intrinsics::try(f, data); PANICKING.with(|s| s.set(prev)); if ep.is_null() { Ok(()) @@ -152,8 +152,13 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> { Err(imp::cleanup(ep)) } } + #[cfg(stage0)] + unsafe fn inner_try(f: fn(*mut u8), data: *mut u8) + -> Result<(), Box<Any + Send>> { + Ok(f(data)) + } - extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) { + fn try_fn<F: FnOnce()>(opt_closure: *mut u8) { let opt_closure = opt_closure as *mut Option<F>; unsafe { (*opt_closure).take().unwrap()(); } } @@ -163,8 +168,8 @@ pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> { // When f(...) returns normally, the return value is null. // When f(...) throws, the return value is a pointer to the caught // exception object. - fn rust_try(f: extern fn(*mut c_void), - data: *mut c_void) -> *mut c_void; + fn rust_try(f: extern fn(*mut u8), + data: *mut u8) -> *mut u8; } } diff --git a/src/libstd/rt/unwind/seh.rs b/src/libstd/rt/unwind/seh.rs index a72c1debe14..ed44f9a8bda 100644 --- a/src/libstd/rt/unwind/seh.rs +++ b/src/libstd/rt/unwind/seh.rs @@ -8,23 +8,137 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx) +//! +//! On Windows (currently only on MSVC), the default exception handling +//! mechanism is Structured Exception Handling (SEH). This is quite different +//! than Dwarf-based exception handling (e.g. what other unix platforms use) in +//! terms of compiler internals, so LLVM is required to have a good deal of +//! extra support for SEH. Currently this support is somewhat lacking, so what's +//! here is the bare bones of SEH support. +//! +//! In a nutshell, what happens here is: +//! +//! 1. The `panic` function calls the standard Windows function `RaiseException` +//! with a Rust-specific code, triggering the unwinding process. +//! 2. All landing pads generated by the compiler (just "cleanup" landing pads) +//! use the personality function `__C_specific_handler`, a function in the +//! CRT, and the unwinding code in Windows will use this personality function +//! to execute all cleanup code on the stack. +//! 3. Eventually the "catch" code in `rust_try` (located in +//! src/rt/rust_try_msvc_64.ll) is executed, which will ensure that the +//! exception being caught is indeed a Rust exception, returning control back +//! into Rust. +//! +//! Some specific differences from the gcc-based exception handling are: +//! +//! * Rust has no custom personality function, it is instead *always* +//! __C_specific_handler, so the filtering is done in a C++-like manner +//! instead of in the personality function itself. Note that the specific +//! syntax for this (found in the rust_try_msvc_64.ll) is taken from an LLVM +//! test case for SEH. +//! * We've got some data to transmit across the unwinding boundary, +//! specifically a `Box<Any + Send + 'static>`. In Dwarf-based unwinding this +//! data is part of the payload of the exception, but I have not currently +//! figured out how to do this with LLVM's bindings. Judging by some comments +//! in the LLVM test cases this may not even be possible currently with LLVM, +//! so this is just abandoned entirely. Instead the data is stored in a +//! thread-local in `panic` and retrieved during `cleanup`. +//! +//! So given all that, the bindings here are pretty small, + +#![allow(bad_style)] + use prelude::v1::*; use any::Any; -use intrinsics; -use libc::c_void; +use libc::{c_ulong, DWORD, c_void}; +use sys_common::thread_local::StaticKey; + +// 0x R U S T +const RUST_PANIC: DWORD = 0x52555354; +static PANIC_DATA: StaticKey = StaticKey::new(None); + +// This function is provided by kernel32.dll +extern "system" { + fn RaiseException(dwExceptionCode: DWORD, + dwExceptionFlags: DWORD, + nNumberOfArguments: DWORD, + lpArguments: *const c_ulong); +} + +#[repr(C)] +pub struct EXCEPTION_POINTERS { + ExceptionRecord: *mut EXCEPTION_RECORD, + ContextRecord: *mut CONTEXT, +} + +enum CONTEXT {} + +#[repr(C)] +struct EXCEPTION_RECORD { + ExceptionCode: DWORD, + ExceptionFlags: DWORD, + ExceptionRecord: *mut _EXCEPTION_RECORD, + ExceptionAddress: *mut c_void, + NumberParameters: DWORD, + ExceptionInformation: [*mut c_ulong; EXCEPTION_MAXIMUM_PARAMETERS], +} -pub unsafe fn panic(_data: Box<Any + Send + 'static>) -> ! { - intrinsics::abort(); +enum _EXCEPTION_RECORD {} + +const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; + +pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! { + // See module docs above for an explanation of why `data` is stored in a + // thread local instead of being passed as an argument to the + // `RaiseException` function (which can in theory carry along arbitrary + // data). + let exception = Box::new(data); + rtassert!(PANIC_DATA.get().is_null()); + PANIC_DATA.set(Box::into_raw(exception) as *mut u8); + + RaiseException(RUST_PANIC, 0, 0, 0 as *const _); + rtabort!("could not unwind stack"); } -pub unsafe fn cleanup(_ptr: *mut c_void) -> Box<Any + Send + 'static> { - intrinsics::abort(); +pub unsafe fn cleanup(ptr: *mut u8) -> Box<Any + Send + 'static> { + // The `ptr` here actually corresponds to the code of the exception, and our + // real data is stored in our thread local. + rtassert!(ptr as DWORD == RUST_PANIC); + + let data = PANIC_DATA.get() as *mut Box<Any + Send + 'static>; + PANIC_DATA.set(0 as *mut u8); + rtassert!(!data.is_null()); + + *Box::from_raw(data) } +// This is required by the compiler to exist (e.g. it's a lang item), but it's +// never actually called by the compiler because __C_specific_handler is the +// personality function that is always used. Hence this is just an aborting +// stub. #[lang = "eh_personality"] -#[no_mangle] -pub extern fn rust_eh_personality() {} +fn rust_eh_personality() { + unsafe { ::intrinsics::abort() } +} +// This is a function referenced from `rust_try_msvc_64.ll` which is used to +// filter the exceptions being caught by that function. +// +// In theory local variables can be accessed through the `rbp` parameter of this +// function, but a comment in an LLVM test case indicates that this is not +// implemented in LLVM, so this is just an idempotent function which doesn't +// ferry along any other information. +// +// This function just takes a look at the current EXCEPTION_RECORD being thrown +// to ensure that it's code is RUST_PANIC, which was set by the call to +// `RaiseException` above in the `panic` function. #[no_mangle] -pub extern fn rust_eh_personality_catch() {} +#[lang = "msvc_try_filter"] +pub extern fn __rust_try_filter(eh_ptrs: *mut EXCEPTION_POINTERS, + _rbp: *mut u8) -> i32 { + unsafe { + ((*(*eh_ptrs).ExceptionRecord).ExceptionCode == RUST_PANIC) as i32 + } +} diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 04f36d99c8e..031fda089c8 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -13,7 +13,6 @@ use io::prelude::*; use env; use fmt; use intrinsics; -use libc::uintptr_t; use sync::atomic::{self, Ordering}; use sys::stdio::Stderr; @@ -22,10 +21,18 @@ use sys::stdio::Stderr; /// can't run correctly un-altered. Valgrind is there to help /// you notice weirdness in normal, un-doctored code paths! pub fn running_on_valgrind() -> bool { - extern { - fn rust_running_on_valgrind() -> uintptr_t; + return on_valgrind(); + #[cfg(windows)] + fn on_valgrind() -> bool { false } + + #[cfg(unix)] + fn on_valgrind() -> bool { + use libc::uintptr_t; + extern { + fn rust_running_on_valgrind() -> uintptr_t; + } + unsafe { rust_running_on_valgrind() != 0 } } - unsafe { rust_running_on_valgrind() != 0 } } /// Valgrind has a fixed-sized array (size around 2000) of segment descriptors diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs index be674c83e22..a3b2ab7705e 100644 --- a/src/libstd/rtdeps.rs +++ b/src/libstd/rtdeps.rs @@ -12,8 +12,8 @@ //! the standard library This varies per-platform, but these libraries are //! necessary for running libstd. -// All platforms need to link to rustrt -#[cfg(not(test))] +// A few small shims in C that haven't been translated to Rust yet +#[cfg(all(not(test), not(windows)))] #[link(name = "rust_builtin", kind = "static")] extern {} @@ -39,6 +39,7 @@ extern {} #[cfg(any(target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] #[link(name = "pthread")] extern {} diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 77aeeca7968..1453c91fd4d 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -768,6 +768,48 @@ impl<T> Receiver<T> { /// If the corresponding `Sender` has disconnected, or it disconnects while /// this call is blocking, this call will wake up and return `Err` to /// indicate that no more messages can ever be received on this channel. + /// However, since channels are buffered, messages sent before the disconnect + /// will still be properly received. + /// + /// # Examples + /// + /// ``` + /// use std::sync::mpsc; + /// use std::thread; + /// + /// let (send, recv) = mpsc::channel(); + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(Ok(1), recv.recv()); + /// ``` + /// + /// Buffering behavior: + /// + /// ``` + /// use std::sync::mpsc; + /// use std::thread; + /// use std::sync::mpsc::RecvError; + /// + /// let (send, recv) = mpsc::channel(); + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// send.send(2).unwrap(); + /// send.send(3).unwrap(); + /// drop(send); + /// }); + /// + /// // wait for the thread to join so we ensure the sender is dropped + /// handle.join().unwrap(); + /// + /// assert_eq!(Ok(1), recv.recv()); + /// assert_eq!(Ok(2), recv.recv()); + /// assert_eq!(Ok(3), recv.recv()); + /// assert_eq!(Err(RecvError), recv.recv()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn recv(&self) -> Result<T, RecvError> { loop { diff --git a/src/libstd/sys/common/io.rs b/src/libstd/sys/common/io.rs new file mode 100644 index 00000000000..151d853fc9f --- /dev/null +++ b/src/libstd/sys/common/io.rs @@ -0,0 +1,139 @@ +// 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 prelude::v1::*; +use io; +use io::ErrorKind; +use io::Read; +use slice::from_raw_parts_mut; + +// Provides read_to_end functionality over an uninitialized buffer. +// This function is unsafe because it calls the underlying +// read function with a slice into uninitialized memory. The default +// implementation of read_to_end for readers will zero out new memory in +// the buf before passing it to read, but avoiding this zero can often +// lead to a fairly significant performance win. +// +// Implementations using this method have to adhere to two guarantees: +// * The implementation of read never reads the buffer provided. +// * The implementation of read correctly reports how many bytes were written. +pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::Result<usize> { + + let start_len = buf.len(); + buf.reserve(16); + + // Always try to read into the empty space of the vector (from the length to the capacity). + // If the vector ever fills up then we reserve an extra byte which should trigger the normal + // reallocation routines for the vector, which will likely double the size. + // + // This function is similar to the read_to_end function in std::io, but the logic about + // reservations and slicing is different enough that this is duplicated here. + loop { + if buf.len() == buf.capacity() { + buf.reserve(1); + } + + let buf_slice = from_raw_parts_mut(buf.as_mut_ptr().offset(buf.len() as isize), + buf.capacity() - buf.len()); + + match r.read(buf_slice) { + Ok(0) => { return Ok(buf.len() - start_len); } + Ok(n) => { let len = buf.len() + n; buf.set_len(len); }, + Err(ref e) if e.kind() == ErrorKind::Interrupted => { } + Err(e) => { return Err(e); } + } + } +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use io::prelude::*; + use super::*; + use io; + use io::{ErrorKind, Take, Repeat, repeat}; + use test; + use slice::from_raw_parts; + + struct ErrorRepeat { + lr: Take<Repeat> + } + + fn error_repeat(byte: u8, limit: u64) -> ErrorRepeat { + ErrorRepeat { lr: repeat(byte).take(limit) } + } + + impl Read for ErrorRepeat { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let ret = self.lr.read(buf); + if let Ok(0) = ret { + return Err(io::Error::new(ErrorKind::Other, "")) + } + ret + } + } + + fn init_vec_data() -> Vec<u8> { + let mut vec = vec![10u8; 200]; + unsafe { vec.set_len(0); } + vec + } + + fn assert_all_eq(buf: &[u8], value: u8) { + for n in buf { + assert_eq!(*n, value); + } + } + + fn validate(buf: &Vec<u8>, good_read_len: usize) { + assert_all_eq(buf, 1u8); + let cap = buf.capacity(); + let end_slice = unsafe { from_raw_parts(buf.as_ptr().offset(good_read_len as isize), + cap - good_read_len) }; + assert_all_eq(end_slice, 10u8); + } + + #[test] + fn read_to_end_uninit_error() { + let mut er = error_repeat(1,100); + let mut vec = init_vec_data(); + if let Err(_) = unsafe { read_to_end_uninitialized(&mut er, &mut vec) } { + validate(&vec, 100); + } else { + assert!(false); + } + } + + #[test] + fn read_to_end_uninit_zero_len_vec() { + let mut er = repeat(1).take(100); + let mut vec = Vec::new(); + let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; + assert_all_eq(&vec, 1u8); + assert_eq!(vec.len(), n); + } + + #[test] + fn read_to_end_uninit_good() { + let mut er = repeat(1).take(100); + let mut vec = init_vec_data(); + let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; + validate(&vec, 100); + assert_eq!(vec.len(), n); + } + + #[bench] + fn bench_uninitialized(b: &mut test::Bencher) { + b.iter(|| { + let mut lr = repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + unsafe { read_to_end_uninitialized(&mut lr, &mut vec) }; + }); + } +} diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index b528575bbed..69c54f98917 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -16,6 +16,7 @@ pub mod backtrace; pub mod condvar; pub mod mutex; pub mod net; +pub mod io; pub mod poison; pub mod remutex; pub mod rwlock; diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 5890e6a7889..6dd222b8f6e 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -184,6 +184,8 @@ impl TcpStream { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) @@ -336,6 +338,8 @@ impl TcpListener { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn socket_addr(&self) -> io::Result<SocketAddr> { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) @@ -396,6 +400,8 @@ impl UdpSocket { pub fn socket(&self) -> &Socket { &self.inner } + pub fn into_socket(self) -> Socket { self.inner } + pub fn socket_addr(&self) -> io::Result<SocketAddr> { sockname(|buf, len| unsafe { libc::getsockname(*self.inner.as_inner(), buf, len) diff --git a/src/libstd/sys/common/stack.rs b/src/libstd/sys/common/stack.rs index 11982ebc572..41c8ac4aed3 100644 --- a/src/libstd/sys/common/stack.rs +++ b/src/libstd/sys/common/stack.rs @@ -170,8 +170,7 @@ pub unsafe fn record_sp_limit(limit: usize) { asm!("movl $$0x48+90*4, %eax movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile") } - #[cfg(all(target_arch = "x86", - any(target_os = "linux", target_os = "freebsd")))] + #[cfg(all(target_arch = "x86", target_os = "linux"))] #[inline(always)] unsafe fn target_record_sp_limit(limit: usize) { asm!("movl $0, %gs:48" :: "r"(limit) :: "volatile") @@ -197,11 +196,14 @@ pub unsafe fn record_sp_limit(limit: usize) { // aarch64 - FIXME(AARCH64): missing... // powerpc - FIXME(POWERPC): missing... // arm-ios - iOS segmented stack is disabled for now, see related notes - // openbsd - segmented stack is disabled + // openbsd/bitrig/netbsd - no segmented stacks. + // x86-freebsd - no segmented stacks. #[cfg(any(target_arch = "aarch64", target_arch = "powerpc", all(target_arch = "arm", target_os = "ios"), + all(target_arch = "x86", target_os = "freebsd"), target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] unsafe fn target_record_sp_limit(_: usize) { } @@ -261,8 +263,7 @@ pub unsafe fn get_sp_limit() -> usize { movl %gs:(%eax), $0" : "=r"(limit) :: "eax" : "volatile"); return limit; } - #[cfg(all(target_arch = "x86", - any(target_os = "linux", target_os = "freebsd")))] + #[cfg(all(target_arch = "x86", target_os = "linux"))] #[inline(always)] unsafe fn target_get_sp_limit() -> usize { let limit; @@ -290,15 +291,18 @@ pub unsafe fn get_sp_limit() -> usize { // aarch64 - FIXME(AARCH64): missing... // powerpc - FIXME(POWERPC): missing... - // arm-ios - iOS doesn't support segmented stacks yet. - // openbsd - OpenBSD doesn't support segmented stacks. + // arm-ios - no segmented stacks. + // openbsd/bitrig/netbsd - no segmented stacks. + // x86-freebsd - no segmented stacks.. // // This function might be called by runtime though // so it is unsafe to unreachable, let's return a fixed constant. #[cfg(any(target_arch = "aarch64", target_arch = "powerpc", all(target_arch = "arm", target_os = "ios"), + all(target_arch = "x86", target_os = "freebsd"), target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] #[inline(always)] unsafe fn target_get_sp_limit() -> usize { diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index ae55bae37aa..bb47c946e49 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -18,7 +18,7 @@ use thread::Thread; use thread::LocalKeyState; struct ThreadInfo { - stack_guard: usize, + stack_guard: Option<usize>, thread: Thread, } @@ -33,7 +33,7 @@ impl ThreadInfo { THREAD_INFO.with(move |c| { if c.borrow().is_none() { *c.borrow_mut() = Some(ThreadInfo { - stack_guard: 0, + stack_guard: None, thread: NewThread::new(None), }) } @@ -47,10 +47,10 @@ pub fn current_thread() -> Option<Thread> { } pub fn stack_guard() -> Option<usize> { - ThreadInfo::with(|info| info.stack_guard) + ThreadInfo::with(|info| info.stack_guard).and_then(|o| o) } -pub fn set(stack_guard: usize, thread: Thread) { +pub fn set(stack_guard: Option<usize>, thread: Thread) { THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ stack_guard: stack_guard, diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 8ea673d2162..6f15d606724 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -32,17 +32,18 @@ use core::str::next_code_point; use ascii::*; use borrow::Cow; +use char; use cmp; use fmt; use hash::{Hash, Hasher}; use iter::FromIterator; use mem; use ops; +use rustc_unicode::str::{Utf16Item, utf16_items}; use slice; use str; use string::String; use sys_common::AsInner; -use rustc_unicode::str::{Utf16Item, utf16_items}; use vec::Vec; const UTF8_REPLACEMENT_CHARACTER: &'static [u8] = b"\xEF\xBF\xBD"; @@ -107,7 +108,7 @@ impl CodePoint { pub fn to_char(&self) -> Option<char> { match self.value { 0xD800 ... 0xDFFF => None, - _ => Some(unsafe { mem::transmute(self.value) }) + _ => Some(unsafe { char::from_u32_unchecked(self.value) }) } } @@ -213,18 +214,16 @@ impl Wtf8Buf { // Attempt to not use an intermediate buffer by just pushing bytes // directly onto this string. let slice = slice::from_raw_parts_mut( - self.bytes.as_mut_ptr().offset(cur_len as isize), - 4 + self.bytes.as_mut_ptr().offset(cur_len as isize), 4 ); - let used = encode_utf8_raw(code_point.value, mem::transmute(slice)) - .unwrap_or(0); + let used = encode_utf8_raw(code_point.value, slice).unwrap(); self.bytes.set_len(cur_len + used); } } #[inline] pub fn as_slice(&self) -> &Wtf8 { - unsafe { mem::transmute(&*self.bytes) } + unsafe { Wtf8::from_bytes_unchecked(&self.bytes) } } /// Reserves capacity for at least `additional` more bytes to be inserted @@ -457,7 +456,16 @@ impl Wtf8 { /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] pub fn from_str(value: &str) -> &Wtf8 { - unsafe { mem::transmute(value.as_bytes()) } + unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) } + } + + /// Creates a WTF-8 slice from a WTF-8 byte slice. + /// + /// Since the byte slice is not checked for valid WTF-8, this functions is + /// marked unsafe. + #[inline] + unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 { + mem::transmute(value) } /// Returns the length, in WTF-8 bytes. @@ -682,7 +690,7 @@ fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 { #[inline] fn decode_surrogate_pair(lead: u16, trail: u16) -> char { let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32); - unsafe { mem::transmute(code_point) } + unsafe { char::from_u32_unchecked(code_point) } } /// Copied from core::str::StrPrelude::is_char_boundary @@ -699,7 +707,7 @@ pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool { #[inline] pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { // memory layout of an &[u8] and &Wtf8 are the same - mem::transmute(slice::from_raw_parts( + Wtf8::from_bytes_unchecked(slice::from_raw_parts( s.bytes.as_ptr().offset(begin as isize), end - begin )) @@ -821,7 +829,6 @@ mod tests { use prelude::v1::*; use borrow::Cow; use super::*; - use mem::transmute; #[test] fn code_point_from_u32() { @@ -962,7 +969,7 @@ mod tests { string.push_wtf8(Wtf8::from_str(" 💩")); assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - fn w(value: &[u8]) -> &Wtf8 { unsafe { transmute(value) } } + fn w(v: &[u8]) -> &Wtf8 { unsafe { Wtf8::from_bytes_unchecked(v) } } let mut string = Wtf8Buf::new(); string.push_wtf8(w(b"\xED\xA0\xBD")); // lead diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index b23a3eee1a1..ed6421f3670 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -107,8 +107,6 @@ use sys_common::backtrace::*; #[cfg(all(target_os = "ios", target_arch = "arm"))] #[inline(never)] pub fn write(w: &mut Write) -> io::Result<()> { - use result; - extern { fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; @@ -127,10 +125,10 @@ pub fn write(w: &mut Write) -> io::Result<()> { let cnt = unsafe { backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize}; // skipping the first one as it is write itself - let iter = (1..cnt).map(|i| { - print(w, i as isize, buf[i], buf[i]) - }); - result::fold(iter, (), |_, _| ()) + for i in 1..cnt { + try!(print(w, i as isize, buf[i], buf[i])) + } + Ok(()) } #[cfg(not(all(target_os = "ios", target_arch = "arm")))] @@ -363,6 +361,7 @@ fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, let selfname = if cfg!(target_os = "freebsd") || cfg!(target_os = "dragonfly") || cfg!(target_os = "bitrig") || + cfg!(target_os = "netbsd") || cfg!(target_os = "openbsd") { env::current_exe().ok() } else { diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index 99a6731c57d..eeecf7f50f7 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -34,6 +34,7 @@ use libc; target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub const FIOCLEX: libc::c_ulong = 0x20006601; @@ -60,6 +61,7 @@ pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 70; target_os = "dragonfly"))] pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 71; #[cfg(any(target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 101; #[cfg(target_os = "android")] @@ -82,6 +84,7 @@ pub struct passwd { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub struct passwd { pub pw_name: *mut libc::c_char, @@ -321,6 +324,7 @@ mod signal_os { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod signal_os { use libc; @@ -348,7 +352,7 @@ mod signal_os { pub struct sigset_t { bits: [u32; 4], } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] pub type sigset_t = libc::c_uint; // This structure has more fields, but we're not all that interested in @@ -365,7 +369,7 @@ mod signal_os { pub _status: libc::c_int, pub si_addr: *mut libc::c_void } - #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] #[repr(C)] pub struct siginfo { pub si_signo: libc::c_int, @@ -375,7 +379,7 @@ mod signal_os { } #[cfg(any(target_os = "macos", target_os = "ios", - target_os = "bitrig", target_os = "openbsd"))] + target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] #[repr(C)] pub struct sigaction { pub sa_sigaction: sighandler_t, diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 97703b83056..4ee790b0161 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -16,6 +16,7 @@ use prelude::v1::*; use fs::{self, Permissions, OpenOptions}; use io; +use libc; use os::raw::c_long; use os::unix::raw; use path::Path; @@ -178,6 +179,27 @@ impl MetadataExt for fs::Metadata { } } +/// Add special unix types (block/char device, fifo and socket) +#[unstable(feature = "file_type_ext", reason = "recently added API")] +pub trait FileTypeExt { + /// Returns whether this file type is a block device. + fn is_block_device(&self) -> bool; + /// Returns whether this file type is a char device. + fn is_char_device(&self) -> bool; + /// Returns whether this file type is a fifo. + fn is_fifo(&self) -> bool; + /// Returns whether this file type is a socket. + fn is_socket(&self) -> bool; +} + +#[unstable(feature = "file_type_ext", reason = "recently added API")] +impl FileTypeExt for fs::FileType { + fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) } + fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) } + fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) } + fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) } +} + /// Unix-specific extension methods for `fs::DirEntry` #[stable(feature = "dir_entry_ext", since = "1.1.0")] pub trait DirEntryExt { diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs index 79e59ddab5b..580d2dbcf74 100644 --- a/src/libstd/sys/unix/ext/io.rs +++ b/src/libstd/sys/unix/ext/io.rs @@ -16,7 +16,7 @@ use fs; use net; use os::raw; use sys; -use sys_common::{self, AsInner, FromInner}; +use sys_common::{self, AsInner, FromInner, IntoInner}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] @@ -59,6 +59,18 @@ pub trait FromRawFd { unsafe fn from_raw_fd(fd: RawFd) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + fn into_raw_fd(self) -> RawFd; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { @@ -71,6 +83,11 @@ impl FromRawFd for fs::File { fs::File::from_inner(sys::fs::File::from_inner(fd)) } } +impl IntoRawFd for fs::File { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for net::TcpStream { @@ -106,3 +123,19 @@ impl FromRawFd for net::UdpSocket { net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) } } + +impl IntoRawFd for net::TcpStream { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +impl IntoRawFd for net::TcpListener { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +impl IntoRawFd for net::UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index 48c77480899..f7dee1a8f35 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -45,7 +45,7 @@ pub mod prelude { #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::ffi::{OsStrExt, OsStringExt}; #[doc(no_inline)] - pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt}; + pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt}; #[doc(no_inline)] pub use super::fs::{DirEntryExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index cfe7a1f2dda..63adae17581 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -13,11 +13,11 @@ #![stable(feature = "rust1", since = "1.0.0")] use os::unix::raw::{uid_t, gid_t}; -use os::unix::io::{FromRawFd, RawFd, AsRawFd}; +use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd}; use prelude::v1::*; use process; use sys; -use sys_common::{AsInnerMut, AsInner, FromInner}; +use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; /// Unix-specific extensions to the `std::process::Command` builder #[stable(feature = "rust1", since = "1.0.0")] @@ -92,3 +92,21 @@ impl AsRawFd for process::ChildStderr { self.as_inner().fd().raw() } } + +impl IntoRawFd for process::ChildStdin { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl IntoRawFd for process::ChildStdout { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl IntoRawFd for process::ChildStderr { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 128284834ab..0c99a30f107 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -14,7 +14,7 @@ use os::unix::prelude::*; use ffi::{CString, CStr, OsString, OsStr}; use fmt; -use io::{self, Error, SeekFrom}; +use io::{self, Error, ErrorKind, SeekFrom}; use libc::{self, c_int, size_t, off_t, c_char, mode_t}; use mem; use path::{Path, PathBuf}; @@ -113,7 +113,7 @@ impl FileType { pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) } pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) } - fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } + pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode } } impl FromInner<raw::mode_t> for FilePermissions { @@ -331,6 +331,8 @@ impl File { } pub fn fd(&self) -> &FileDesc { &self.0 } + + pub fn into_fd(self) -> FileDesc { self.0 } } impl DirBuilder { @@ -370,13 +372,25 @@ impl fmt::Debug for File { readlink(&p).ok() } - #[cfg(not(target_os = "linux"))] + #[cfg(target_os = "macos")] + fn get_path(fd: c_int) -> Option<PathBuf> { + let mut buf = vec![0;libc::PATH_MAX as usize]; + let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; + if n == -1 { + return None; + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] fn get_path(_fd: c_int) -> Option<PathBuf> { // FIXME(#24570): implement this for other Unix platforms None } - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "macos"))] fn get_mode(fd: c_int) -> Option<(bool, bool)> { let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; if mode == -1 { @@ -390,7 +404,7 @@ impl fmt::Debug for File { } } - #[cfg(not(target_os = "linux"))] + #[cfg(not(any(target_os = "linux", target_os = "macos")))] fn get_mode(_fd: c_int) -> Option<(bool, bool)> { // FIXME(#24570): implement this for other Unix platforms None @@ -516,3 +530,19 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { buf.truncate(p); Ok(PathBuf::from(OsString::from_vec(buf))) } + +pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { + use fs::{File, PathExt, set_permissions}; + if !from.is_file() { + return Err(Error::new(ErrorKind::InvalidInput, + "the source path is not an existing file")) + } + + let mut reader = try!(File::open(from)); + let mut writer = try!(File::create(to)); + let perm = try!(reader.metadata()).permissions(); + + let ret = try!(io::copy(&mut reader, &mut writer)); + try!(set_permissions(to, perm)); + Ok(ret) +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index c1a4e8cee9e..6fd20b940bb 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -26,6 +26,7 @@ use ops::Neg; #[cfg(target_os = "linux")] pub use os::linux as platform; #[cfg(target_os = "macos")] pub use os::macos as platform; #[cfg(target_os = "nacl")] pub use os::nacl as platform; +#[cfg(target_os = "netbsd")] pub use os::netbsd as platform; #[cfg(target_os = "openbsd")] pub use os::openbsd as platform; pub mod backtrace; diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 1f40c18be2f..37eb7fd2ac8 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -17,7 +17,7 @@ use str; use sys::c; use net::SocketAddr; use sys::fd::FileDesc; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{getsockopt, setsockopt}; use time::Duration; @@ -127,3 +127,7 @@ impl AsInner<c_int> for Socket { impl FromInner<c_int> for Socket { fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) } } + +impl IntoInner<c_int> for Socket { + fn into_inner(self) -> c_int { self.0.into_raw() } +} diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 5178d7b8fb1..2b6b50a1a56 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -22,25 +22,17 @@ use io; use iter; use libc::{self, c_int, c_char, c_void}; use mem; -use ptr; use path::{self, PathBuf}; +use ptr; use slice; use str; use sys::c; use sys::fd; use vec; -const BUF_BYTES: usize = 2048; +const GETCWD_BUF_BYTES: usize = 2048; const TMPBUF_SZ: usize = 128; -fn bytes2path(b: &[u8]) -> PathBuf { - PathBuf::from(<OsStr as OsStrExt>::from_bytes(b)) -} - -fn os2path(os: OsString) -> PathBuf { - bytes2path(os.as_bytes()) -} - /// Returns the platform-specific value of errno pub fn errno() -> i32 { #[cfg(any(target_os = "macos", @@ -51,23 +43,13 @@ pub fn errno() -> i32 { __error() } - #[cfg(target_os = "bitrig")] - fn errno_location() -> *const c_int { - extern { - fn __errno() -> *const c_int; - } - unsafe { - __errno() - } - } - #[cfg(target_os = "dragonfly")] unsafe fn errno_location() -> *const c_int { extern { fn __dfly_error() -> *const c_int; } __dfly_error() } - #[cfg(target_os = "openbsd")] + #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] unsafe fn errno_location() -> *const c_int { extern { fn __errno() -> *const c_int; } __errno() @@ -112,12 +94,24 @@ pub fn error_string(errno: i32) -> String { } pub fn getcwd() -> io::Result<PathBuf> { - let mut buf = [0 as c_char; BUF_BYTES]; - unsafe { - if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() { - Err(io::Error::last_os_error()) - } else { - Ok(bytes2path(CStr::from_ptr(buf.as_ptr()).to_bytes())) + let mut buf = Vec::new(); + let mut n = GETCWD_BUF_BYTES; + loop { + unsafe { + buf.reserve(n); + let ptr = buf.as_mut_ptr() as *mut libc::c_char; + if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() { + let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); + buf.set_len(len); + buf.shrink_to_fit(); + return Ok(PathBuf::from(OsString::from_vec(buf))); + } else { + let error = io::Error::last_os_error(); + if error.raw_os_error() != Some(libc::ERANGE) { + return Err(error); + } + } + n *= 2; } } } @@ -139,11 +133,14 @@ pub struct SplitPaths<'a> { } pub fn split_paths<'a>(unparsed: &'a OsStr) -> SplitPaths<'a> { + fn bytes_to_path(b: &[u8]) -> PathBuf { + PathBuf::from(<OsStr as OsStrExt>::from_bytes(b)) + } fn is_colon(b: &u8) -> bool { *b == b':' } let unparsed = unparsed.as_bytes(); SplitPaths { iter: unparsed.split(is_colon as fn(&u8) -> bool) - .map(bytes2path as fn(&'a [u8]) -> PathBuf) + .map(bytes_to_path as fn(&'a [u8]) -> PathBuf) } } @@ -214,7 +211,7 @@ pub fn current_exe() -> io::Result<PathBuf> { ::fs::read_link("/proc/curproc/file") } -#[cfg(any(target_os = "bitrig", target_os = "openbsd"))] +#[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] pub fn current_exe() -> io::Result<PathBuf> { use sync::StaticMutex; static LOCK: StaticMutex = StaticMutex::new(); @@ -356,6 +353,7 @@ pub fn args() -> Args { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub fn args() -> Args { use rt; @@ -453,7 +451,7 @@ pub fn page_size() -> usize { } pub fn temp_dir() -> PathBuf { - getenv("TMPDIR".as_ref()).map(os2path).unwrap_or_else(|| { + getenv("TMPDIR".as_ref()).map(PathBuf::from).unwrap_or_else(|| { if cfg!(target_os = "android") { PathBuf::from("/data/local/tmp") } else { @@ -465,7 +463,7 @@ pub fn temp_dir() -> PathBuf { pub fn home_dir() -> Option<PathBuf> { return getenv("HOME".as_ref()).or_else(|| unsafe { fallback() - }).map(os2path); + }).map(PathBuf::from); #[cfg(any(target_os = "android", target_os = "ios"))] diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 946857c05bc..140f0c042ba 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -46,4 +46,5 @@ impl AnonPipe { pub fn raw(&self) -> libc::c_int { self.0.raw() } pub fn fd(&self) -> &FileDesc { &self.0 } + pub fn into_fd(self) -> FileDesc { self.0 } } diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 695d0ddfaaf..cc78dd4e5ef 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -423,6 +423,7 @@ fn translate_status(status: c_int) -> ExitStatus { target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod imp { pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 } diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 52494a17b9d..62689c39255 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -35,6 +35,7 @@ impl Drop for Handler { #[cfg(any(target_os = "linux", target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod imp { use sys_common::stack; @@ -149,6 +150,7 @@ mod imp { #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd")))] mod imp { use libc; diff --git a/src/libstd/sys/unix/sync.rs b/src/libstd/sys/unix/sync.rs index 41e1e206a42..9c8a1f4ca40 100644 --- a/src/libstd/sys/unix/sync.rs +++ b/src/libstd/sys/unix/sync.rs @@ -55,6 +55,7 @@ extern { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] mod os { use libc; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index bb0e12e8df8..6be61f06926 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -105,6 +105,7 @@ impl Thread { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] pub fn set_name(name: &str) { extern { @@ -162,20 +163,25 @@ impl Drop for Thread { #[cfg(all(not(target_os = "linux"), not(target_os = "macos"), not(target_os = "bitrig"), + not(target_os = "netbsd"), not(target_os = "openbsd")))] pub mod guard { - pub unsafe fn current() -> usize { 0 } - pub unsafe fn main() -> usize { 0 } - pub unsafe fn init() {} + use prelude::v1::*; + + pub unsafe fn current() -> Option<usize> { None } + pub unsafe fn init() -> Option<usize> { None } } #[cfg(any(target_os = "linux", target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] #[allow(unused_imports)] pub mod guard { + use prelude::v1::*; + use libc::{self, pthread_t}; use libc::funcs::posix88::mman::mmap; use libc::consts::os::posix88::{PROT_NONE, @@ -188,30 +194,38 @@ pub mod guard { use super::{pthread_self, pthread_attr_destroy}; use sys::os; - // These are initialized in init() and only read from after - static mut GUARD_PAGE: usize = 0; - #[cfg(any(target_os = "macos", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] - unsafe fn get_stack_start() -> *mut libc::c_void { - current() as *mut libc::c_void + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + current().map(|s| s as *mut libc::c_void) } #[cfg(any(target_os = "linux", target_os = "android"))] - unsafe fn get_stack_start() -> *mut libc::c_void { + unsafe fn get_stack_start() -> Option<*mut libc::c_void> { + use super::pthread_attr_init; + + let mut ret = None; let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); - let mut stackaddr = ptr::null_mut(); - let mut stacksize = 0; - assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); + assert_eq!(pthread_attr_init(&mut attr), 0); + if pthread_getattr_np(pthread_self(), &mut attr) == 0 { + let mut stackaddr = ptr::null_mut(); + let mut stacksize = 0; + assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, + &mut stacksize), 0); + ret = Some(stackaddr); + } assert_eq!(pthread_attr_destroy(&mut attr), 0); - stackaddr + ret } - pub unsafe fn init() { + pub unsafe fn init() -> Option<usize> { let psize = os::page_size(); - let mut stackaddr = get_stack_start(); + let mut stackaddr = match get_stack_start() { + Some(addr) => addr, + None => return None, + }; // Ensure stackaddr is page aligned! A parent process might // have reset RLIMIT_STACK to be non-page aligned. The @@ -241,25 +255,21 @@ pub mod guard { let offset = if cfg!(target_os = "linux") {2} else {1}; - GUARD_PAGE = stackaddr as usize + offset * psize; - } - - pub unsafe fn main() -> usize { - GUARD_PAGE + Some(stackaddr as usize + offset * psize) } #[cfg(target_os = "macos")] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option<usize> { extern { fn pthread_get_stackaddr_np(thread: pthread_t) -> *mut libc::c_void; fn pthread_get_stacksize_np(thread: pthread_t) -> libc::size_t; } - (pthread_get_stackaddr_np(pthread_self()) as libc::size_t - - pthread_get_stacksize_np(pthread_self())) as usize + Some((pthread_get_stackaddr_np(pthread_self()) as libc::size_t - + pthread_get_stacksize_np(pthread_self())) as usize) } - #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] - pub unsafe fn current() -> usize { + #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))] + pub unsafe fn current() -> Option<usize> { #[repr(C)] struct stack_t { ss_sp: *mut libc::c_void, @@ -276,30 +286,36 @@ pub mod guard { assert_eq!(pthread_stackseg_np(pthread_self(), &mut current_stack), 0); let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); - if pthread_main_np() == 1 { + Some(if pthread_main_np() == 1 { // main thread current_stack.ss_sp as usize - current_stack.ss_size as usize + extra } else { // new thread current_stack.ss_sp as usize - current_stack.ss_size as usize - } + }) } #[cfg(any(target_os = "linux", target_os = "android"))] - pub unsafe fn current() -> usize { + pub unsafe fn current() -> Option<usize> { + use super::pthread_attr_init; + + let mut ret = None; let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(pthread_getattr_np(pthread_self(), &mut attr), 0); - let mut guardsize = 0; - assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0); - if guardsize == 0 { - panic!("there is no guard page"); + assert_eq!(pthread_attr_init(&mut attr), 0); + if pthread_getattr_np(pthread_self(), &mut attr) == 0 { + let mut guardsize = 0; + assert_eq!(pthread_attr_getguardsize(&attr, &mut guardsize), 0); + if guardsize == 0 { + panic!("there is no guard page"); + } + let mut stackaddr = ptr::null_mut(); + let mut size = 0; + assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); + + ret = Some(stackaddr as usize + guardsize as usize); } - let mut stackaddr = ptr::null_mut(); - let mut size = 0; - assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0); assert_eq!(pthread_attr_destroy(&mut attr), 0); - - stackaddr as usize + guardsize as usize + return ret } #[cfg(any(target_os = "linux", target_os = "android"))] diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local.rs index 3afe84b2580..7238adfcc56 100644 --- a/src/libstd/sys/unix/thread_local.rs +++ b/src/libstd/sys/unix/thread_local.rs @@ -46,6 +46,7 @@ type pthread_key_t = ::libc::c_ulong; #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd"))] type pthread_key_t = ::libc::c_int; @@ -54,6 +55,7 @@ type pthread_key_t = ::libc::c_int; target_os = "freebsd", target_os = "dragonfly", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd")))] type pthread_key_t = ::libc::c_uint; diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 6b84baeca7d..db0d0f15061 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -80,6 +80,7 @@ mod inner { // OpenBSD provide it via libc #[cfg(not(any(target_os = "android", target_os = "bitrig", + target_os = "netbsd", target_os = "openbsd", target_env = "musl")))] #[link(name = "rt")] diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 3c9b2ef1b98..06c14b39e12 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -13,6 +13,9 @@ #![allow(bad_style, dead_code, overflowing_literals)] use libc; +use libc::{c_uint, c_ulong}; +use libc::{DWORD, BOOL, BOOLEAN, ERROR_CALL_NOT_IMPLEMENTED, LPVOID, HANDLE}; +use libc::{LPCWSTR, LONG}; pub use self::GET_FILEEX_INFO_LEVELS::*; pub use self::FILE_INFO_BY_HANDLE_CLASS::*; @@ -50,9 +53,13 @@ pub const WSA_FLAG_NO_HANDLE_INHERIT: libc::DWORD = 0x80; pub const ERROR_NO_MORE_FILES: libc::DWORD = 18; pub const TOKEN_READ: libc::DWORD = 0x20008; pub const FILE_FLAG_OPEN_REPARSE_POINT: libc::DWORD = 0x00200000; +pub const FILE_FLAG_BACKUP_SEMANTICS: libc::DWORD = 0x02000000; pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; pub const FSCTL_GET_REPARSE_POINT: libc::DWORD = 0x900a8; pub const IO_REPARSE_TAG_SYMLINK: libc::DWORD = 0xa000000c; +pub const IO_REPARSE_TAG_MOUNT_POINT: libc::DWORD = 0xa0000003; +pub const FSCTL_SET_REPARSE_POINT: libc::DWORD = 0x900a4; +pub const FSCTL_DELETE_REPARSE_POINT: libc::DWORD = 0x900ac; pub const SYMBOLIC_LINK_FLAG_DIRECTORY: libc::DWORD = 0x1; @@ -61,6 +68,16 @@ pub const STD_INPUT_HANDLE: libc::DWORD = -10i32 as libc::DWORD; pub const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD; pub const STD_ERROR_HANDLE: libc::DWORD = -12i32 as libc::DWORD; +pub const HANDLE_FLAG_INHERIT: libc::DWORD = 0x00000001; + +pub const PROGRESS_CONTINUE: libc::DWORD = 0; +pub const PROGRESS_CANCEL: libc::DWORD = 1; +pub const PROGRESS_STOP: libc::DWORD = 2; +pub const PROGRESS_QUIET: libc::DWORD = 3; + +pub const TOKEN_ADJUST_PRIVILEGES: libc::DWORD = 0x0020; +pub const SE_PRIVILEGE_ENABLED: libc::DWORD = 2; + #[repr(C)] #[cfg(target_arch = "x86")] pub struct WSADATA { @@ -240,7 +257,79 @@ pub struct SYMBOLIC_LINK_REPARSE_BUFFER { pub PathBuffer: libc::WCHAR, } +pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; +pub type PSRWLOCK = *mut SRWLOCK; +pub type ULONG = c_ulong; +pub type ULONG_PTR = c_ulong; +pub type LPBOOL = *mut BOOL; + +pub type LPPROGRESS_ROUTINE = ::option::Option<unsafe extern "system" fn( + TotalFileSize: libc::LARGE_INTEGER, + TotalBytesTransferred: libc::LARGE_INTEGER, + StreamSize: libc::LARGE_INTEGER, + StreamBytesTransferred: libc::LARGE_INTEGER, + dwStreamNumber: DWORD, + dwCallbackReason: DWORD, + hSourceFile: HANDLE, + hDestinationFile: HANDLE, + lpData: LPVOID, +) -> DWORD>; + +#[repr(C)] +pub struct CONDITION_VARIABLE { pub ptr: LPVOID } +#[repr(C)] +pub struct SRWLOCK { pub ptr: LPVOID } +#[repr(C)] +pub struct CRITICAL_SECTION { + CriticalSectionDebug: LPVOID, + LockCount: LONG, + RecursionCount: LONG, + OwningThread: HANDLE, + LockSemaphore: HANDLE, + SpinCount: ULONG_PTR +} + +pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { + ptr: 0 as *mut _, +}; +pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: 0 as *mut _ }; + +#[repr(C)] +pub struct LUID { + pub LowPart: libc::DWORD, + pub HighPart: libc::c_long, +} + +pub type PLUID = *mut LUID; + +#[repr(C)] +pub struct TOKEN_PRIVILEGES { + pub PrivilegeCount: libc::DWORD, + pub Privileges: [LUID_AND_ATTRIBUTES; 1], +} + +pub type PTOKEN_PRIVILEGES = *mut TOKEN_PRIVILEGES; + +#[repr(C)] +pub struct LUID_AND_ATTRIBUTES { + pub Luid: LUID, + pub Attributes: libc::DWORD, +} + +#[repr(C)] +pub struct REPARSE_MOUNTPOINT_DATA_BUFFER { + pub ReparseTag: libc::DWORD, + pub ReparseDataLength: libc::DWORD, + pub Reserved: libc::WORD, + pub ReparseTargetLength: libc::WORD, + pub ReparseTargetMaximumLength: libc::WORD, + pub Reserved1: libc::WORD, + pub ReparseTarget: libc::WCHAR, +} + + #[link(name = "ws2_32")] +#[link(name = "userenv")] extern "system" { pub fn WSAStartup(wVersionRequested: libc::WORD, lpWSAData: LPWSADATA) -> libc::c_int; @@ -295,115 +384,13 @@ extern "system" { pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL; pub fn CancelIoEx(hFile: libc::HANDLE, lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; -} - -pub mod compat { - use prelude::v1::*; - - use ffi::CString; - use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; - use sync::atomic::{AtomicUsize, Ordering}; - extern "system" { - fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; - fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; - } - - fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, - fallback: usize) -> usize { - let mut module: Vec<u16> = module.utf16_units().collect(); - module.push(0); - let symbol = CString::new(symbol).unwrap(); - let func = unsafe { - let handle = GetModuleHandleW(module.as_ptr()); - GetProcAddress(handle, symbol.as_ptr()) as usize - }; - let value = if func == 0 {fallback} else {func}; - ptr.store(value, Ordering::SeqCst); - value - } - - /// Macro for creating a compatibility fallback for a Windows function - /// - /// # Examples - /// ``` - /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) { - /// // Fallback implementation - /// }) - /// ``` - /// - /// Note that arguments unused by the fallback implementation should not be - /// called `_` as they are used to be passed to the real function if - /// available. - macro_rules! compat_fn { - ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty { $fallback:expr }) => ( - #[inline(always)] - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { - use sync::atomic::{AtomicUsize, Ordering}; - use mem; - - static PTR: AtomicUsize = AtomicUsize::new(0); - - fn load() -> usize { - ::sys::c::compat::store_func(&PTR, - stringify!($module), - stringify!($symbol), - fallback as usize) - } - - extern "system" fn fallback($($argname: $argtype),*) - -> $rettype { $fallback } - - let addr = match PTR.load(Ordering::SeqCst) { - 0 => load(), - n => n, - }; - let f: extern "system" fn($($argtype),*) -> $rettype = - mem::transmute(addr); - f($($argname),*) - } - ) - } - - /// Compatibility layer for functions in `kernel32.dll` - /// - /// Latest versions of Windows this is needed for: - /// - /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003 - /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003 - pub mod kernel32 { - use libc::c_uint; - use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE}; - use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED; - use sys::c::SetLastError; - - compat_fn! { - kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, - _lpTargetFileName: LPCWSTR, - _dwFlags: DWORD) -> BOOLEAN { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } - } - } - - compat_fn! { - kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE, - _lpszFilePath: LPCWSTR, - _cchFilePath: DWORD, - _dwFlags: DWORD) -> DWORD { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } - } - } - - compat_fn! { - kernel32::SetThreadErrorMode(_dwNewMode: DWORD, _lpOldMode: *mut DWORD) -> c_uint { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } - } - } - } -} + pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN; + pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION); -extern "system" { // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL pub fn ReadConsoleW(hConsoleInput: libc::HANDLE, lpBuffer: libc::LPVOID, @@ -447,10 +434,6 @@ extern "system" { lpCreationTime: *const libc::FILETIME, lpLastAccessTime: *const libc::FILETIME, lpLastWriteTime: *const libc::FILETIME) -> libc::BOOL; - pub fn SetFileInformationByHandle(hFile: libc::HANDLE, - FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, - lpFileInformation: libc::LPVOID, - dwBufferSize: libc::DWORD) -> libc::BOOL; pub fn GetTempPathW(nBufferLength: libc::DWORD, lpBuffer: libc::LPCWSTR) -> libc::DWORD; pub fn OpenProcessToken(ProcessHandle: libc::HANDLE, @@ -483,11 +466,88 @@ extern "system" { pub fn SwitchToThread() -> libc::BOOL; pub fn Sleep(dwMilliseconds: libc::DWORD); pub fn GetProcessId(handle: libc::HANDLE) -> libc::DWORD; -} - -#[link(name = "userenv")] -extern "system" { pub fn GetUserProfileDirectoryW(hToken: libc::HANDLE, lpProfileDir: libc::LPCWSTR, lpcchSize: *mut libc::DWORD) -> libc::BOOL; + pub fn SetHandleInformation(hObject: libc::HANDLE, + dwMask: libc::DWORD, + dwFlags: libc::DWORD) -> libc::BOOL; + pub fn CopyFileExW(lpExistingFileName: libc::LPCWSTR, + lpNewFileName: libc::LPCWSTR, + lpProgressRoutine: LPPROGRESS_ROUTINE, + lpData: libc::LPVOID, + pbCancel: LPBOOL, + dwCopyFlags: libc::DWORD) -> libc::BOOL; + pub fn LookupPrivilegeValueW(lpSystemName: libc::LPCWSTR, + lpName: libc::LPCWSTR, + lpLuid: PLUID) -> libc::BOOL; + pub fn AdjustTokenPrivileges(TokenHandle: libc::HANDLE, + DisableAllPrivileges: libc::BOOL, + NewState: PTOKEN_PRIVILEGES, + BufferLength: libc::DWORD, + PreviousState: PTOKEN_PRIVILEGES, + ReturnLength: *mut libc::DWORD) -> libc::BOOL; +} + +// Functions that aren't available on Windows XP, but we still use them and just +// provide some form of a fallback implementation. +compat_fn! { + kernel32: + + pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, + _lpTargetFileName: LPCWSTR, + _dwFlags: DWORD) -> BOOLEAN { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } + pub fn GetFinalPathNameByHandleW(_hFile: HANDLE, + _lpszFilePath: LPCWSTR, + _cchFilePath: DWORD, + _dwFlags: DWORD) -> DWORD { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } + pub fn SetThreadErrorMode(_dwNewMode: DWORD, + _lpOldMode: *mut DWORD) -> c_uint { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } + pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } + pub fn SetFileInformationByHandle(_hFile: HANDLE, + _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, + _lpFileInformation: LPVOID, + _dwBufferSize: DWORD) -> BOOL { + SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 + } + pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE, + SRWLock: PSRWLOCK, + dwMilliseconds: DWORD, + Flags: ULONG) -> BOOL { + panic!("condition variables not available") + } + pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE) + -> () { + panic!("condition variables not available") + } + pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE) + -> () { + panic!("condition variables not available") + } + pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> () { + panic!("rwlocks not available") + } + pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK) -> () { + panic!("rwlocks not available") + } + pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK) -> () { + panic!("rwlocks not available") + } + pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK) -> () { + panic!("rwlocks not available") + } + pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN { + panic!("rwlocks not available") + } + pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN { + panic!("rwlocks not available") + } } diff --git a/src/libstd/sys/windows/compat.rs b/src/libstd/sys/windows/compat.rs new file mode 100644 index 00000000000..3a03b91f24e --- /dev/null +++ b/src/libstd/sys/windows/compat.rs @@ -0,0 +1,88 @@ +// 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. + +//! A "compatibility layer" for spanning XP and Windows 7 +//! +//! The standard library currently binds many functions that are not available +//! on Windows XP, but we would also like to support building executables that +//! run on XP. To do this we specify all non-XP APIs as having a fallback +//! implementation to do something reasonable. +//! +//! This dynamic runtime detection of whether a function is available is +//! implemented with `GetModuleHandle` and `GetProcAddress` paired with a +//! static-per-function which caches the result of the first check. In this +//! manner we pay a semi-large one-time cost up front for detecting whether a +//! function is available but afterwards it's just a load and a jump. + +use prelude::v1::*; + +use ffi::CString; +use libc::{LPVOID, LPCWSTR, HMODULE, LPCSTR}; +use sync::atomic::{AtomicUsize, Ordering}; + +extern "system" { + fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; + fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; +} + +pub fn lookup(module: &str, symbol: &str) -> Option<usize> { + let mut module: Vec<u16> = module.utf16_units().collect(); + module.push(0); + let symbol = CString::new(symbol).unwrap(); + unsafe { + let handle = GetModuleHandleW(module.as_ptr()); + match GetProcAddress(handle, symbol.as_ptr()) as usize { + 0 => None, + n => Some(n), + } + } +} + +pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, + fallback: usize) -> usize { + let value = lookup(module, symbol).unwrap_or(fallback); + ptr.store(value, Ordering::SeqCst); + value +} + +macro_rules! compat_fn { + ($module:ident: $( + pub fn $symbol:ident($($argname:ident: $argtype:ty),*) + -> $rettype:ty { + $($body:expr);* + } + )*) => ($( + #[allow(unused_variables)] + pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { + use sync::atomic::{AtomicUsize, Ordering}; + use mem; + type F = unsafe extern "system" fn($($argtype),*) -> $rettype; + + static PTR: AtomicUsize = AtomicUsize::new(0); + + fn load() -> usize { + ::sys::compat::store_func(&PTR, + stringify!($module), + stringify!($symbol), + fallback as usize) + } + unsafe extern "system" fn fallback($($argname: $argtype),*) + -> $rettype { + $($body);* + } + + let addr = match PTR.load(Ordering::SeqCst) { + 0 => load(), + n => n, + }; + mem::transmute::<usize, F>(addr)($($argname),*) + } + )*) +} diff --git a/src/libstd/sys/windows/condvar.rs b/src/libstd/sys/windows/condvar.rs index baa7d1ceea3..04d62200e9b 100644 --- a/src/libstd/sys/windows/condvar.rs +++ b/src/libstd/sys/windows/condvar.rs @@ -12,35 +12,35 @@ use prelude::v1::*; use cell::UnsafeCell; use libc::{self, DWORD}; -use sys::os; +use sys::c; use sys::mutex::{self, Mutex}; -use sys::sync as ffi; +use sys::os; use time::Duration; -pub struct Condvar { inner: UnsafeCell<ffi::CONDITION_VARIABLE> } +pub struct Condvar { inner: UnsafeCell<c::CONDITION_VARIABLE> } unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} impl Condvar { pub const fn new() -> Condvar { - Condvar { inner: UnsafeCell::new(ffi::CONDITION_VARIABLE_INIT) } + Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } } #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { - let r = ffi::SleepConditionVariableSRW(self.inner.get(), - mutex::raw(mutex), - libc::INFINITE, - 0); + let r = c::SleepConditionVariableSRW(self.inner.get(), + mutex::raw(mutex), + libc::INFINITE, + 0); debug_assert!(r != 0); } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let r = ffi::SleepConditionVariableSRW(self.inner.get(), - mutex::raw(mutex), - super::dur2timeout(dur), - 0); + let r = c::SleepConditionVariableSRW(self.inner.get(), + mutex::raw(mutex), + super::dur2timeout(dur), + 0); if r == 0 { const ERROR_TIMEOUT: DWORD = 0x5B4; debug_assert_eq!(os::errno() as usize, ERROR_TIMEOUT as usize); @@ -52,12 +52,12 @@ impl Condvar { #[inline] pub unsafe fn notify_one(&self) { - ffi::WakeConditionVariable(self.inner.get()) + c::WakeConditionVariable(self.inner.get()) } #[inline] pub unsafe fn notify_all(&self) { - ffi::WakeAllConditionVariable(self.inner.get()) + c::WakeAllConditionVariable(self.inner.get()) } pub unsafe fn destroy(&self) { diff --git a/src/libstd/sys/windows/ext/io.rs b/src/libstd/sys/windows/ext/io.rs index f4717eb2425..185f1abe64b 100644 --- a/src/libstd/sys/windows/ext/io.rs +++ b/src/libstd/sys/windows/ext/io.rs @@ -13,7 +13,7 @@ use fs; use os::windows::raw; use net; -use sys_common::{self, AsInner, FromInner}; +use sys_common::{self, AsInner, FromInner, IntoInner}; use sys; /// Raw HANDLEs. @@ -50,6 +50,18 @@ pub trait FromRawHandle { unsafe fn from_raw_handle(handle: RawHandle) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw `HANDLE`. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawHandle { + /// Consumes this object, returning the raw underlying handle. + /// + /// This function **transfers ownership** of the underlying handle to the + /// caller. Callers are then the unique owners of the handle and must close + /// it once it's no longer needed. + fn into_raw_handle(self) -> RawHandle; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawHandle for fs::File { fn as_raw_handle(&self) -> RawHandle { @@ -65,6 +77,12 @@ impl FromRawHandle for fs::File { } } +impl IntoRawHandle for fs::File { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + /// Extract raw sockets. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawSocket { @@ -90,6 +108,18 @@ pub trait FromRawSocket { unsafe fn from_raw_socket(sock: RawSocket) -> Self; } +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw `SOCKET`. +#[unstable(feature = "into_raw_os", reason = "recently added API")] +pub trait IntoRawSocket { + /// Consumes this object, returning the raw underlying socket. + /// + /// This function **transfers ownership** of the underlying socket to the + /// caller. Callers are then the unique owners of the socket and must close + /// it once it's no longer needed. + fn into_raw_socket(self) -> RawSocket; +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawSocket for net::TcpStream { fn as_raw_socket(&self) -> RawSocket { @@ -130,3 +160,21 @@ impl FromRawSocket for net::UdpSocket { net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(sock)) } } + +impl IntoRawSocket for net::TcpStream { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} + +impl IntoRawSocket for net::TcpListener { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} + +impl IntoRawSocket for net::UdpSocket { + fn into_raw_socket(self) -> RawSocket { + self.into_inner().into_socket().into_inner() + } +} diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 6f59be2687a..fde21e9a798 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -12,10 +12,10 @@ #![stable(feature = "process_extensions", since = "1.2.0")] -use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle}; +use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle, IntoRawHandle}; use process; use sys; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawHandle for process::Stdio { @@ -32,6 +32,12 @@ impl AsRawHandle for process::Child { } } +impl IntoRawHandle for process::Child { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl AsRawHandle for process::ChildStdin { fn as_raw_handle(&self) -> RawHandle { @@ -52,3 +58,21 @@ impl AsRawHandle for process::ChildStderr { self.as_inner().handle().raw() as *mut _ } } + +impl IntoRawHandle for process::ChildStdin { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + +impl IntoRawHandle for process::ChildStdout { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} + +impl IntoRawHandle for process::ChildStderr { + fn into_raw_handle(self) -> RawHandle { + self.into_inner().into_handle().into_raw() as *mut _ + } +} diff --git a/src/libstd/sys/windows/ext/raw.rs b/src/libstd/sys/windows/ext/raw.rs index e1796d4b5f0..92d53e2e428 100644 --- a/src/libstd/sys/windows/ext/raw.rs +++ b/src/libstd/sys/windows/ext/raw.rs @@ -10,7 +10,7 @@ //! Windows-specific primitives -#[stable(feature = "raw_ext", since = "1.1.0")] +#![stable(feature = "raw_ext", since = "1.1.0")] use os::raw::c_void; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 437b2cc6491..4ce6d53cf12 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -30,12 +30,12 @@ pub struct File { handle: Handle } pub struct FileAttr { data: c::WIN32_FILE_ATTRIBUTE_DATA, - is_symlink: bool, + reparse_tag: libc::DWORD, } #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum FileType { - Dir, File, Symlink, ReparsePoint + Dir, File, Symlink, ReparsePoint, MountPoint, } pub struct ReadDir { @@ -133,7 +133,7 @@ impl DirEntry { pub fn file_type(&self) -> io::Result<FileType> { Ok(FileType::new(self.data.dwFileAttributes, - self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK)) + /* reparse_tag = */ self.data.dwReserved0)) } pub fn metadata(&self) -> io::Result<FileAttr> { @@ -146,7 +146,7 @@ impl DirEntry { nFileSizeHigh: self.data.nFileSizeHigh, nFileSizeLow: self.data.nFileSizeLow, }, - is_symlink: self.data.dwReserved0 == c::IO_REPARSE_TAG_SYMLINK, + reparse_tag: self.data.dwReserved0, }) } } @@ -218,10 +218,12 @@ impl OpenOptions { } impl File { - fn open_reparse_point(path: &Path) -> io::Result<File> { + fn open_reparse_point(path: &Path, write: bool) -> io::Result<File> { let mut opts = OpenOptions::new(); - opts.read(true); - opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT); + opts.read(!write); + opts.write(write); + opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT | + c::FILE_FLAG_BACKUP_SEMANTICS); File::open(path, &opts) } @@ -278,10 +280,13 @@ impl File { nFileSizeHigh: info.nFileSizeHigh, nFileSizeLow: info.nFileSizeLow, }, - is_symlink: false, + reparse_tag: 0, }; if attr.is_reparse_point() { - attr.is_symlink = self.is_symlink(); + let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + if let Ok((_, buf)) = self.reparse_point(&mut b) { + attr.reparse_tag = buf.ReparseTag; + } } Ok(attr) } @@ -314,15 +319,13 @@ impl File { pub fn handle(&self) -> &Handle { &self.handle } - fn is_symlink(&self) -> bool { - self.readlink().is_ok() - } - - fn readlink(&self) -> io::Result<PathBuf> { - let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - let mut bytes = 0; + pub fn into_handle(self) -> Handle { self.handle } + fn reparse_point<'a>(&self, + space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]) + -> io::Result<(libc::DWORD, &'a c::REPARSE_DATA_BUFFER)> { unsafe { + let mut bytes = 0; try!(cvt({ c::DeviceIoControl(self.handle.raw(), c::FSCTL_GET_REPARSE_POINT, @@ -333,12 +336,20 @@ impl File { &mut bytes, 0 as *mut _) })); - let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _; - if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK { - return Err(io::Error::new(io::ErrorKind::Other, "not a symlink")) - } + Ok((bytes, &*(space.as_ptr() as *const c::REPARSE_DATA_BUFFER))) + } + } + + fn readlink(&self) -> io::Result<PathBuf> { + let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let (_bytes, buf) = try!(self.reparse_point(&mut space)); + if buf.ReparseTag != c::IO_REPARSE_TAG_SYMLINK { + return Err(io::Error::new(io::ErrorKind::Other, "not a symlink")) + } + + unsafe { let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = - &(*buf).rest as *const _ as *const _; + &buf.rest as *const _ as *const _; let path_buffer = &(*info).PathBuffer as *const _ as *const u16; let subst_off = (*info).SubstituteNameOffset / 2; let subst_ptr = path_buffer.offset(subst_off as isize); @@ -348,8 +359,6 @@ impl File { Ok(PathBuf::from(OsString::from_wide(subst))) } } - - pub fn into_handle(self) -> Handle { self.handle } } impl FromInner<libc::HANDLE> for File { @@ -360,10 +369,13 @@ impl FromInner<libc::HANDLE> for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME(#24570): add more info here (e.g. path, mode) - f.debug_struct("File") - .field("handle", &self.handle.raw()) - .finish() + // FIXME(#24570): add more info here (e.g. mode) + let mut b = f.debug_struct("File"); + b.field("handle", &self.handle.raw()); + if let Ok(path) = get_path(&self) { + b.field("path", &path); + } + b.finish() } } @@ -383,7 +395,7 @@ impl FileAttr { pub fn attrs(&self) -> u32 { self.data.dwFileAttributes as u32 } pub fn file_type(&self) -> FileType { - FileType::new(self.data.dwFileAttributes, self.is_symlink) + FileType::new(self.data.dwFileAttributes, self.reparse_tag) } pub fn created(&self) -> u64 { self.to_u64(&self.data.ftCreationTime) } @@ -414,12 +426,12 @@ impl FilePermissions { } impl FileType { - fn new(attrs: libc::DWORD, is_symlink: bool) -> FileType { + fn new(attrs: libc::DWORD, reparse_tag: libc::DWORD) -> FileType { if attrs & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - if is_symlink { - FileType::Symlink - } else { - FileType::ReparsePoint + match reparse_tag { + c::IO_REPARSE_TAG_SYMLINK => FileType::Symlink, + c::IO_REPARSE_TAG_MOUNT_POINT => FileType::MountPoint, + _ => FileType::ReparsePoint, } } else if attrs & c::FILE_ATTRIBUTE_DIRECTORY != 0 { FileType::Dir @@ -430,7 +442,9 @@ impl FileType { pub fn is_dir(&self) -> bool { *self == FileType::Dir } pub fn is_file(&self) -> bool { *self == FileType::File } - pub fn is_symlink(&self) -> bool { *self == FileType::Symlink } + pub fn is_symlink(&self) -> bool { + *self == FileType::Symlink || *self == FileType::MountPoint + } } impl DirBuilder { @@ -488,7 +502,7 @@ pub fn rmdir(p: &Path) -> io::Result<()> { } pub fn readlink(p: &Path) -> io::Result<PathBuf> { - let file = try!(File::open_reparse_point(p)); + let file = try!(File::open_reparse_point(p, false)); file.readlink() } @@ -497,12 +511,11 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { } pub fn symlink_inner(src: &Path, dst: &Path, dir: bool) -> io::Result<()> { - use sys::c::compat::kernel32::CreateSymbolicLinkW; let src = to_utf16(src); let dst = to_utf16(dst); let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 }; try!(cvt(unsafe { - CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as libc::BOOL + c::CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), flags) as libc::BOOL })); Ok(()) } @@ -518,8 +531,15 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result<FileAttr> { let attr = try!(lstat(p)); - if attr.data.dwFileAttributes & libc::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - let opts = OpenOptions::new(); + + // If this is a reparse point, then we need to reopen the file to get the + // actual destination. We also pass the FILE_FLAG_BACKUP_SEMANTICS flag to + // ensure that we can open directories (this path may be a directory + // junction). Once the file is opened we ask the opened handle what its + // metadata information is. + if attr.is_reparse_point() { + let mut opts = OpenOptions::new(); + opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS); let file = try!(File::open(p, &opts)); file.file_attr() } else { @@ -535,9 +555,10 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> { c::GetFileExInfoStandard, &mut attr.data as *mut _ as *mut _))); if attr.is_reparse_point() { - attr.is_symlink = File::open_reparse_point(p).map(|f| { - f.is_symlink() - }).unwrap_or(false); + attr.reparse_tag = File::open_reparse_point(p, false).and_then(|f| { + let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + f.reparse_point(&mut b).map(|(_, b)| b.ReparseTag) + }).unwrap_or(0); } Ok(attr) } @@ -564,16 +585,164 @@ pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { Ok(()) } -pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { - use sys::c::compat::kernel32::GetFinalPathNameByHandleW; - - let mut opts = OpenOptions::new(); - opts.read(true); - let f = try!(File::open(p, &opts)); +fn get_path(f: &File) -> io::Result<PathBuf> { super::fill_utf16_buf(|buf, sz| unsafe { - GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, - libc::VOLUME_NAME_DOS) + c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, + libc::VOLUME_NAME_DOS) }, |buf| { PathBuf::from(OsString::from_wide(buf)) }) } + +pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { + let mut opts = OpenOptions::new(); + opts.read(true); + let f = try!(File::open(p, &opts)); + get_path(&f) +} + +pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { + unsafe extern "system" fn callback( + _TotalFileSize: libc::LARGE_INTEGER, + TotalBytesTransferred: libc::LARGE_INTEGER, + _StreamSize: libc::LARGE_INTEGER, + _StreamBytesTransferred: libc::LARGE_INTEGER, + _dwStreamNumber: libc::DWORD, + _dwCallbackReason: libc::DWORD, + _hSourceFile: HANDLE, + _hDestinationFile: HANDLE, + lpData: libc::LPVOID, + ) -> libc::DWORD { + *(lpData as *mut i64) = TotalBytesTransferred; + c::PROGRESS_CONTINUE + } + let pfrom = to_utf16(from); + let pto = to_utf16(to); + let mut size = 0i64; + try!(cvt(unsafe { + c::CopyFileExW(pfrom.as_ptr(), pto.as_ptr(), Some(callback), + &mut size as *mut _ as *mut _, ptr::null_mut(), 0) + })); + Ok(size as u64) +} + +#[test] +fn directory_junctions_are_directories() { + use ffi::OsStr; + use env; + use rand::{self, StdRng, Rng}; + + macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with: {}", stringify!($e), e), + }) + } + + let d = DirBuilder::new(); + let p = env::temp_dir(); + let mut r = rand::thread_rng(); + let ret = p.join(&format!("rust-{}", r.next_u32())); + let foo = ret.join("foo"); + let bar = ret.join("bar"); + t!(d.mkdir(&ret)); + t!(d.mkdir(&foo)); + t!(d.mkdir(&bar)); + + t!(create_junction(&bar, &foo)); + let metadata = stat(&bar); + t!(delete_junction(&bar)); + + t!(rmdir(&foo)); + t!(rmdir(&bar)); + t!(rmdir(&ret)); + + let metadata = t!(metadata); + assert!(metadata.file_type().is_dir()); + + // Creating a directory junction on windows involves dealing with reparse + // points and the DeviceIoControl function, and this code is a skeleton of + // what can be found here: + // + // http://www.flexhex.com/docs/articles/hard-links.phtml + fn create_junction(src: &Path, dst: &Path) -> io::Result<()> { + let f = try!(opendir(src, true)); + let h = f.handle().raw(); + + unsafe { + let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut db = data.as_mut_ptr() + as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER; + let mut buf = &mut (*db).ReparseTarget as *mut _; + let mut i = 0; + let v = br"\??\"; + let v = v.iter().map(|x| *x as u16); + for c in v.chain(dst.as_os_str().encode_wide()) { + *buf.offset(i) = c; + i += 1; + } + *buf.offset(i) = 0; + i += 1; + (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT; + (*db).ReparseTargetMaximumLength = (i * 2) as libc::WORD; + (*db).ReparseTargetLength = ((i - 1) * 2) as libc::WORD; + (*db).ReparseDataLength = + (*db).ReparseTargetLength as libc::DWORD + 12; + + let mut ret = 0; + cvt(c::DeviceIoControl(h as *mut _, + c::FSCTL_SET_REPARSE_POINT, + data.as_ptr() as *mut _, + (*db).ReparseDataLength + 8, + 0 as *mut _, 0, + &mut ret, + 0 as *mut _)).map(|_| ()) + } + } + + fn opendir(p: &Path, write: bool) -> io::Result<File> { + unsafe { + let mut token = 0 as *mut _; + let mut tp: c::TOKEN_PRIVILEGES = mem::zeroed(); + try!(cvt(c::OpenProcessToken(c::GetCurrentProcess(), + c::TOKEN_ADJUST_PRIVILEGES, + &mut token))); + let name: &OsStr = if write { + "SeRestorePrivilege".as_ref() + } else { + "SeBackupPrivilege".as_ref() + }; + let name = name.encode_wide().chain(Some(0)).collect::<Vec<_>>(); + try!(cvt(c::LookupPrivilegeValueW(0 as *const _, + name.as_ptr(), + &mut tp.Privileges[0].Luid))); + tp.PrivilegeCount = 1; + tp.Privileges[0].Attributes = c::SE_PRIVILEGE_ENABLED; + let size = mem::size_of::<c::TOKEN_PRIVILEGES>() as libc::DWORD; + try!(cvt(c::AdjustTokenPrivileges(token, libc::FALSE, &mut tp, size, + 0 as *mut _, 0 as *mut _))); + try!(cvt(libc::CloseHandle(token))); + + File::open_reparse_point(p, write) + } + } + + fn delete_junction(p: &Path) -> io::Result<()> { + unsafe { + let f = try!(opendir(p, true)); + let h = f.handle().raw(); + let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut db = data.as_mut_ptr() + as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER; + (*db).ReparseTag = c::IO_REPARSE_TAG_MOUNT_POINT; + let mut bytes = 0; + cvt(c::DeviceIoControl(h as *mut _, + c::FSCTL_DELETE_REPARSE_POINT, + data.as_ptr() as *mut _, + (*db).ReparseDataLength + 8, + 0 as *mut _, 0, + &mut bytes, + 0 as *mut _)).map(|_| ()) + } + } +} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 18c8add17a6..b6d080109df 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -22,6 +22,8 @@ use os::windows::ffi::{OsStrExt, OsStringExt}; use path::PathBuf; use time::Duration; +#[macro_use] pub mod compat; + pub mod backtrace; pub mod c; pub mod condvar; @@ -36,7 +38,6 @@ pub mod pipe; pub mod process; pub mod rwlock; pub mod stack_overflow; -pub mod sync; pub mod thread; pub mod thread_local; pub mod time; diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 29e370698ad..277c3d14c0e 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -8,57 +8,154 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! System Mutexes +//! +//! The Windows implementation of mutexes is a little odd and it may not be +//! immediately obvious what's going on. The primary oddness is that SRWLock is +//! used instead of CriticalSection, and this is done because: +//! +//! 1. SRWLock is several times faster than CriticalSection according to +//! benchmarks performed on both Windows 8 and Windows 7. +//! +//! 2. CriticalSection allows recursive locking while SRWLock deadlocks. The +//! Unix implementation deadlocks so consistency is preferred. See #19962 for +//! more details. +//! +//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy +//! is there there are no guarantees of fairness. +//! +//! The downside of this approach, however, is that SRWLock is not available on +//! Windows XP, so we continue to have a fallback implementation where +//! CriticalSection is used and we keep track of who's holding the mutex to +//! detect recursive locks. + use prelude::v1::*; use cell::UnsafeCell; -use sys::sync as ffi; use mem; +use sync::atomic::{AtomicUsize, Ordering}; +use sys::c; +use sys::compat; -pub struct Mutex { inner: UnsafeCell<ffi::SRWLOCK> } +pub struct Mutex { + lock: AtomicUsize, + held: UnsafeCell<bool>, +} unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} -#[inline] -pub unsafe fn raw(m: &Mutex) -> ffi::PSRWLOCK { - m.inner.get() +#[derive(Clone, Copy)] +enum Kind { + SRWLock = 1, + CriticalSection = 2, } -// So you might be asking why we're using SRWLock instead of CriticalSection? -// -// 1. SRWLock is several times faster than CriticalSection according to -// benchmarks performed on both Windows 8 and Windows 7. -// -// 2. CriticalSection allows recursive locking while SRWLock deadlocks. The Unix -// implementation deadlocks so consistency is preferred. See #19962 for more -// details. -// -// 3. While CriticalSection is fair and SRWLock is not, the current Rust policy -// is there there are no guarantees of fairness. +#[inline] +pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK { + debug_assert!(mem::size_of::<c::SRWLOCK>() <= mem::size_of_val(&m.lock)); + &m.lock as *const _ as *mut _ +} impl Mutex { pub const fn new() -> Mutex { - Mutex { inner: UnsafeCell::new(ffi::SRWLOCK_INIT) } + Mutex { + lock: AtomicUsize::new(0), + held: UnsafeCell::new(false), + } } - #[inline] pub unsafe fn lock(&self) { - ffi::AcquireSRWLockExclusive(self.inner.get()) + match kind() { + Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)), + Kind::CriticalSection => { + let re = self.remutex(); + (*re).lock(); + if !self.flag_locked() { + (*re).unlock(); + panic!("cannot recursively lock a mutex"); + } + } + } } - #[inline] pub unsafe fn try_lock(&self) -> bool { - ffi::TryAcquireSRWLockExclusive(self.inner.get()) != 0 + match kind() { + Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0, + Kind::CriticalSection => { + let re = self.remutex(); + if !(*re).try_lock() { + false + } else if self.flag_locked() { + true + } else { + (*re).unlock(); + false + } + } + } } - #[inline] pub unsafe fn unlock(&self) { - ffi::ReleaseSRWLockExclusive(self.inner.get()) + *self.held.get() = false; + match kind() { + Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), + Kind::CriticalSection => (*self.remutex()).unlock(), + } } - #[inline] pub unsafe fn destroy(&self) { - // ... + match kind() { + Kind::SRWLock => {} + Kind::CriticalSection => { + match self.lock.load(Ordering::SeqCst) { + 0 => {} + n => { Box::from_raw(n as *mut ReentrantMutex).destroy(); } + } + } + } + } + + unsafe fn remutex(&self) -> *mut ReentrantMutex { + match self.lock.load(Ordering::SeqCst) { + 0 => {} + n => return n as *mut _, + } + let mut re = Box::new(ReentrantMutex::uninitialized()); + re.init(); + let re = Box::into_raw(re); + match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { + 0 => re, + n => { Box::from_raw(re).destroy(); n as *mut _ } + } + } + + unsafe fn flag_locked(&self) -> bool { + if *self.held.get() { + false + } else { + *self.held.get() = true; + true + } + } } -pub struct ReentrantMutex { inner: UnsafeCell<ffi::CRITICAL_SECTION> } +fn kind() -> Kind { + static KIND: AtomicUsize = AtomicUsize::new(0); + + let val = KIND.load(Ordering::SeqCst); + if val == Kind::SRWLock as usize { + return Kind::SRWLock + } else if val == Kind::CriticalSection as usize { + return Kind::CriticalSection + } + + let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") { + None => Kind::CriticalSection, + Some(..) => Kind::SRWLock, + }; + KIND.store(ret as usize, Ordering::SeqCst); + return ret; +} + +pub struct ReentrantMutex { inner: UnsafeCell<c::CRITICAL_SECTION> } unsafe impl Send for ReentrantMutex {} unsafe impl Sync for ReentrantMutex {} @@ -69,23 +166,23 @@ impl ReentrantMutex { } pub unsafe fn init(&mut self) { - ffi::InitializeCriticalSection(self.inner.get()); + c::InitializeCriticalSection(self.inner.get()); } pub unsafe fn lock(&self) { - ffi::EnterCriticalSection(self.inner.get()); + c::EnterCriticalSection(self.inner.get()); } #[inline] pub unsafe fn try_lock(&self) -> bool { - ffi::TryEnterCriticalSection(self.inner.get()) != 0 + c::TryEnterCriticalSection(self.inner.get()) != 0 } pub unsafe fn unlock(&self) { - ffi::LeaveCriticalSection(self.inner.get()); + c::LeaveCriticalSection(self.inner.get()); } pub unsafe fn destroy(&self) { - ffi::DeleteCriticalSection(self.inner.get()); + c::DeleteCriticalSection(self.inner.get()); } } diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index 0b905267236..d58355ed1fe 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -21,7 +21,7 @@ use rt; use sync::Once; use sys; use sys::c; -use sys_common::{AsInner, FromInner}; +use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{setsockopt, getsockopt}; use time::Duration; @@ -82,26 +82,31 @@ impl Socket { SocketAddr::V4(..) => libc::AF_INET, SocketAddr::V6(..) => libc::AF_INET6, }; - let socket = unsafe { - c::WSASocketW(fam, ty, 0, 0 as *mut _, 0, - c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) - }; - match socket { - INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } + let socket = try!(unsafe { + match c::WSASocketW(fam, ty, 0, 0 as *mut _, 0, + c::WSA_FLAG_OVERLAPPED) { + INVALID_SOCKET => Err(last_error()), + n => Ok(Socket(n)), + } + }); + try!(socket.set_no_inherit()); + Ok(socket) } pub fn accept(&self, storage: *mut libc::sockaddr, len: *mut libc::socklen_t) -> io::Result<Socket> { - match unsafe { libc::accept(self.0, storage, len) } { - INVALID_SOCKET => Err(last_error()), - n => Ok(Socket(n)), - } + let socket = try!(unsafe { + match libc::accept(self.0, storage, len) { + INVALID_SOCKET => Err(last_error()), + n => Ok(Socket(n)), + } + }); + try!(socket.set_no_inherit()); + Ok(socket) } pub fn duplicate(&self) -> io::Result<Socket> { - unsafe { + let socket = try!(unsafe { let mut info: c::WSAPROTOCOL_INFO = mem::zeroed(); try!(cvt(c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), @@ -110,12 +115,13 @@ impl Socket { info.iSocketType, info.iProtocol, &mut info, 0, - c::WSA_FLAG_OVERLAPPED | - c::WSA_FLAG_NO_HANDLE_INHERIT) { + c::WSA_FLAG_OVERLAPPED) { INVALID_SOCKET => Err(last_error()), n => Ok(Socket(n)), } - } + }); + try!(socket.set_no_inherit()); + Ok(socket) } pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { @@ -156,6 +162,13 @@ impl Socket { Ok(Some(Duration::new(secs as u64, nsec as u32))) } } + + fn set_no_inherit(&self) -> io::Result<()> { + sys::cvt(unsafe { + c::SetHandleInformation(self.0 as libc::HANDLE, + c::HANDLE_FLAG_INHERIT, 0) + }).map(|_| ()) + } } impl Drop for Socket { @@ -171,3 +184,11 @@ impl AsInner<libc::SOCKET> for Socket { impl FromInner<libc::SOCKET> for Socket { fn from_inner(sock: libc::SOCKET) -> Socket { Socket(sock) } } + +impl IntoInner<libc::SOCKET> for Socket { + fn into_inner(self) -> libc::SOCKET { + let ret = self.0; + mem::forget(self); + ret + } +} diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index b2a6607314a..a7ece66e0f1 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -37,6 +37,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { impl AnonPipe { pub fn handle(&self) -> &Handle { &self.inner } + pub fn into_handle(self) -> Handle { self.inner } pub fn raw(&self) -> libc::HANDLE { self.inner.raw() } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 0b0268d4746..ca33e11eea0 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -220,6 +220,8 @@ impl Process { } pub fn handle(&self) -> &Handle { &self.handle } + + pub fn into_handle(self) -> Handle { self.handle } } #[derive(PartialEq, Eq, Clone, Copy, Debug)] diff --git a/src/libstd/sys/windows/rwlock.rs b/src/libstd/sys/windows/rwlock.rs index e727638e3e9..25865286db0 100644 --- a/src/libstd/sys/windows/rwlock.rs +++ b/src/libstd/sys/windows/rwlock.rs @@ -11,40 +11,40 @@ use prelude::v1::*; use cell::UnsafeCell; -use sys::sync as ffi; +use sys::c; -pub struct RWLock { inner: UnsafeCell<ffi::SRWLOCK> } +pub struct RWLock { inner: UnsafeCell<c::SRWLOCK> } unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} impl RWLock { pub const fn new() -> RWLock { - RWLock { inner: UnsafeCell::new(ffi::SRWLOCK_INIT) } + RWLock { inner: UnsafeCell::new(c::SRWLOCK_INIT) } } #[inline] pub unsafe fn read(&self) { - ffi::AcquireSRWLockShared(self.inner.get()) + c::AcquireSRWLockShared(self.inner.get()) } #[inline] pub unsafe fn try_read(&self) -> bool { - ffi::TryAcquireSRWLockShared(self.inner.get()) != 0 + c::TryAcquireSRWLockShared(self.inner.get()) != 0 } #[inline] pub unsafe fn write(&self) { - ffi::AcquireSRWLockExclusive(self.inner.get()) + c::AcquireSRWLockExclusive(self.inner.get()) } #[inline] pub unsafe fn try_write(&self) -> bool { - ffi::TryAcquireSRWLockExclusive(self.inner.get()) != 0 + c::TryAcquireSRWLockExclusive(self.inner.get()) != 0 } #[inline] pub unsafe fn read_unlock(&self) { - ffi::ReleaseSRWLockShared(self.inner.get()) + c::ReleaseSRWLockShared(self.inner.get()) } #[inline] pub unsafe fn write_unlock(&self) { - ffi::ReleaseSRWLockExclusive(self.inner.get()) + c::ReleaseSRWLockExclusive(self.inner.get()) } #[inline] diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs index 79b7de4f341..491b53c4ed9 100644 --- a/src/libstd/sys/windows/stack_overflow.rs +++ b/src/libstd/sys/windows/stack_overflow.rs @@ -8,12 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rt::util::report_overflow; use core::prelude::*; -use ptr; -use mem; + +use libc::types::os::arch::extra::{LPVOID, DWORD, LONG}; use libc; -use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL}; +use mem; +use ptr; +use rt::util::report_overflow; +use sys::c; use sys_common::stack; pub struct Handler { @@ -69,13 +71,18 @@ pub unsafe fn cleanup() { } pub unsafe fn make_handler() -> Handler { - if SetThreadStackGuarantee(&mut 0x5000) == 0 { - panic!("failed to reserve stack space for exception handling"); + // This API isn't available on XP, so don't panic in that case and just pray + // it works out ok. + if c::SetThreadStackGuarantee(&mut 0x5000) == 0 { + if libc::GetLastError() as u32 != libc::ERROR_CALL_NOT_IMPLEMENTED as u32 { + panic!("failed to reserve stack space for exception handling"); + } } Handler { _data: 0 as *mut libc::c_void } } +#[repr(C)] pub struct EXCEPTION_RECORD { pub ExceptionCode: DWORD, pub ExceptionFlags: DWORD, @@ -85,6 +92,7 @@ pub struct EXCEPTION_RECORD { pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS] } +#[repr(C)] pub struct EXCEPTION_POINTERS { pub ExceptionRecord: *mut EXCEPTION_RECORD, pub ContextRecord: LPVOID @@ -103,5 +111,4 @@ extern "system" { fn AddVectoredExceptionHandler(FirstHandler: ULONG, VectoredHandler: PVECTORED_EXCEPTION_HANDLER) -> LPVOID; - fn SetThreadStackGuarantee(StackSizeInBytes: *mut ULONG) -> BOOL; } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 9961fef714a..356787d5bf0 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -12,7 +12,6 @@ use prelude::v1::*; use io::prelude::*; use io::{self, Cursor}; -use iter::repeat; use libc; use ptr; use str; @@ -94,7 +93,7 @@ impl Stdin { let mut utf8 = self.utf8.lock().unwrap(); // Read more if the buffer is empty if utf8.position() as usize == utf8.get_ref().len() { - let mut utf16: Vec<u16> = repeat(0u16).take(0x1000).collect(); + let mut utf16 = vec![0u16; 0x1000]; let mut num = 0; try!(cvt(unsafe { c::ReadConsoleW(handle, diff --git a/src/libstd/sys/windows/sync.rs b/src/libstd/sys/windows/sync.rs deleted file mode 100644 index 5410259540e..00000000000 --- a/src/libstd/sys/windows/sync.rs +++ /dev/null @@ -1,60 +0,0 @@ -// 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. - -use libc::{BOOL, DWORD, LPVOID, LONG, HANDLE, c_ulong}; -use libc::types::os::arch::extra::BOOLEAN; - -pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; -pub type PSRWLOCK = *mut SRWLOCK; -pub type ULONG = c_ulong; -pub type ULONG_PTR = c_ulong; - -#[repr(C)] -pub struct CONDITION_VARIABLE { pub ptr: LPVOID } -#[repr(C)] -pub struct SRWLOCK { pub ptr: LPVOID } -#[repr(C)] -pub struct CRITICAL_SECTION { - CriticalSectionDebug: LPVOID, - LockCount: LONG, - RecursionCount: LONG, - OwningThread: HANDLE, - LockSemaphore: HANDLE, - SpinCount: ULONG_PTR -} - -pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { - ptr: 0 as *mut _, -}; -pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: 0 as *mut _ }; - -extern "system" { - // condition variables - pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE, - SRWLock: PSRWLOCK, - dwMilliseconds: DWORD, - Flags: ULONG) -> BOOL; - pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE); - pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE); - - // slim rwlocks - pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK); - pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK); - pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK); - pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK); - pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN; - pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; - - pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN; - pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION); -} diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 50dfee4ab10..42805c2ac52 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -86,7 +86,8 @@ impl Thread { } pub mod guard { - pub unsafe fn main() -> usize { 0 } - pub unsafe fn current() -> usize { 0 } - pub unsafe fn init() {} + use prelude::v1::*; + + pub unsafe fn current() -> Option<usize> { None } + pub unsafe fn init() -> Option<usize> { None } } diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 5002de55988..7550b7ce6c3 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -221,8 +221,8 @@ unsafe fn unregister_dtor(key: Key) -> bool { // // # The article mentions crazy stuff about "/INCLUDE"? // -// It sure does! This seems to work for now, so maybe we'll just run into -// that if we start linking with msvc? +// It sure does! We include it below for MSVC targets, but it look like for GNU +// targets we don't require it. #[link_section = ".CRT$XLB"] #[linkage = "external"] @@ -231,6 +231,13 @@ pub static p_thread_callback: unsafe extern "system" fn(LPVOID, DWORD, LPVOID) = on_tls_callback; +#[cfg(all(target_env = "msvc", target_pointer_width = "64"))] +#[link_args = "/INCLUDE:_tls_used"] +extern {} +#[cfg(all(target_env = "msvc", target_pointer_width = "32"))] +#[link_args = "/INCLUDE:__tls_used"] +extern {} + #[allow(warnings)] unsafe extern "system" fn on_tls_callback(h: LPVOID, dwReason: DWORD, diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 60563340d10..11b375dcce2 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -275,6 +275,7 @@ mod imp { use cell::{Cell, UnsafeCell}; use intrinsics; + use ptr; pub struct Key<T> { inner: UnsafeCell<Option<T>>, @@ -327,7 +328,6 @@ mod imp { #[cfg(target_os = "linux")] unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { use mem; - use ptr; use libc; use sys_common::thread_local as os; @@ -335,13 +335,13 @@ mod imp { #[linkage = "extern_weak"] static __dso_handle: *mut u8; #[linkage = "extern_weak"] - static __cxa_thread_atexit_impl: *const (); + static __cxa_thread_atexit_impl: *const libc::c_void; } if !__cxa_thread_atexit_impl.is_null() { type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), arg: *mut u8, dso_handle: *mut u8) -> libc::c_int; - mem::transmute::<*const (), F>(__cxa_thread_atexit_impl) + mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) (dtor, t, &__dso_handle as *const _ as *mut _); return } @@ -394,7 +394,24 @@ mod imp { // destructor as running for this thread so calls to `get` will return // `None`. (*ptr).dtor_running.set(true); - intrinsics::drop_in_place((*ptr).inner.get()); + + // The OSX implementation of TLS apparently had an odd aspect to it + // where the pointer we have may be overwritten while this destructor + // is running. Specifically if a TLS destructor re-accesses TLS it may + // trigger a re-initialization of all TLS variables, paving over at + // least some destroyed ones with initial values. + // + // This means that if we drop a TLS value in place on OSX that we could + // revert the value to its original state halfway through the + // destructor, which would be bad! + // + // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // instead of drop_in_place. + if cfg!(target_os = "macos") { + ptr::read((*ptr).inner.get()); + } else { + intrinsics::drop_in_place((*ptr).inner.get()); + } } } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index dbb7d3233bc..3388968c56c 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -85,33 +85,6 @@ //! value produced by the child thread, or `Err` of the value given to //! a call to `panic!` if the child panicked. //! -//! ## Scoped threads -//! -//! The `spawn` method does not allow the child and parent threads to -//! share any stack data, since that is not safe in general. However, -//! `scoped` makes it possible to share the parent's stack by forcing -//! a join before any relevant stack frames are popped: -//! -//! ```rust -//! # #![feature(scoped)] -//! use std::thread; -//! -//! let guard = thread::scoped(move || { -//! // some work here -//! }); -//! -//! // do some other work in the meantime -//! let output = guard.join(); -//! ``` -//! -//! The `scoped` function doesn't return a `Thread` directly; instead, -//! it returns a *join guard*. The join guard is an RAII-style guard -//! that will automatically join the child thread (block until it -//! terminates) when it is dropped. You can join the child thread in -//! advance by calling the `join` method on the guard, which will also -//! return the result produced by the thread. A handle to the thread -//! itself is available via the `thread` method of the join guard. -//! //! ## Configuring threads //! //! A new thread can be configured before it is spawned via the `Builder` type, @@ -288,7 +261,7 @@ impl Builder { /// upon being dropped. Because the child thread may refer to data on the /// current thread's stack (hence the "scoped" name), it cannot be detached; /// it *must* be joined before the relevant stack frame is popped. See the - /// module documentation for additional details. + /// documentation on `thread::scoped` for additional details. /// /// # Errors /// @@ -388,12 +361,30 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T> where /// Spawns a new *scoped* thread, returning a `JoinGuard` for it. /// -/// The join guard can be used to explicitly join the child thread (via -/// `join`), returning `Result<T>`, or it will implicitly join the child -/// upon being dropped. Because the child thread may refer to data on the -/// current thread's stack (hence the "scoped" name), it cannot be detached; -/// it *must* be joined before the relevant stack frame is popped. See the -/// module documentation for additional details. +/// The `spawn` method does not allow the child and parent threads to +/// share any stack data, since that is not safe in general. However, +/// `scoped` makes it possible to share the parent's stack by forcing +/// a join before any relevant stack frames are popped: +/// +/// ```rust +/// # #![feature(scoped)] +/// use std::thread; +/// +/// let guard = thread::scoped(move || { +/// // some work here +/// }); +/// +/// // do some other work in the meantime +/// let output = guard.join(); +/// ``` +/// +/// The `scoped` function doesn't return a `Thread` directly; instead, it +/// returns a *join guard*. The join guard can be used to explicitly join +/// the child thread (via `join`), returning `Result<T>`, or it will +/// implicitly join the child upon being dropped. Because the child thread +/// may refer to data on the current thread's stack (hence the "scoped" +/// name), it cannot be detached; it *must* be joined before the relevant +/// stack frame is popped. /// /// # Panics /// @@ -434,9 +425,9 @@ pub fn panicking() -> bool { /// Invokes a closure, capturing the cause of panic if one occurs. /// -/// This function will return `Ok(())` if the closure does not panic, and will -/// return `Err(cause)` if the closure panics. The `cause` returned is the -/// object with which panic was originally invoked. +/// This function will return `Ok` with the closure's result if the closure +/// does not panic, and will return `Err(cause)` if the closure panics. The +/// `cause` returned is the object with which panic was originally invoked. /// /// It is currently undefined behavior to unwind from Rust code into foreign /// code, so this function is particularly useful when Rust is called from @@ -508,9 +499,25 @@ pub fn sleep(dur: Duration) { imp::Thread::sleep(dur) } -/// Blocks unless or until the current thread's token is made available (may wake spuriously). +/// Blocks unless or until the current thread's token is made available. /// -/// See the module doc for more detail. +/// Every thread is equipped with some basic low-level blocking support, via +/// the `park()` function and the [`unpark()`][unpark] method. These can be +/// used as a more CPU-efficient implementation of a spinlock. +/// +/// [unpark]: struct.Thread.html#method.unpark +/// +/// The API is typically used by acquiring a handle to the current thread, +/// placing that handle in a shared data structure so that other threads can +/// find it, and then parking (in a loop with a check for the token actually +/// being acquired). +/// +/// A call to `park` does not guarantee that the thread will remain parked +/// forever, and callers should be prepared for this possibility. +/// +/// See the [module documentation][thread] for more detail. +/// +/// [thread]: index.html // // The implementation currently uses the trivial strategy of a Mutex+Condvar // with wakeup flag, which does not actually allow spurious wakeups. In the diff --git a/src/libstd/thread/scoped_tls.rs b/src/libstd/thread/scoped_tls.rs index 679902ec7ab..c2fad0aa89c 100644 --- a/src/libstd/thread/scoped_tls.rs +++ b/src/libstd/thread/scoped_tls.rs @@ -104,6 +104,7 @@ macro_rules! __scoped_thread_local_inner { #[cfg_attr(not(any(windows, target_os = "android", target_os = "ios", + target_os = "netbsd", target_os = "openbsd", target_arch = "aarch64")), thread_local)] @@ -215,6 +216,7 @@ impl<T> ScopedKey<T> { #[cfg(not(any(windows, target_os = "android", target_os = "ios", + target_os = "netbsd", target_os = "openbsd", target_arch = "aarch64", no_elf_tls)))] @@ -238,6 +240,7 @@ mod imp { #[cfg(any(windows, target_os = "android", target_os = "ios", + target_os = "netbsd", target_os = "openbsd", target_arch = "aarch64", no_elf_tls))] diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs deleted file mode 100644 index 08aa979cf63..00000000000 --- a/src/libstd/tuple.rs +++ /dev/null @@ -1,60 +0,0 @@ -// 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. - -//! Operations on tuples -//! -//! To access the _N_-th element of a tuple one can use `N` itself -//! as a field of the tuple. -//! -//! Indexing starts from zero, so `0` returns first value, `1` -//! returns second value, and so on. In general, a tuple with _S_ -//! elements provides aforementioned fields from `0` to `S-1`. -//! -//! If every type inside a tuple implements one of the following -//! traits, then a tuple itself also implements it. -//! -//! * `Clone` -//! * `PartialEq` -//! * `Eq` -//! * `PartialOrd` -//! * `Ord` -//! * `Debug` -//! * `Default` -//! * `Hash` -//! -//! # Examples -//! -//! Accessing elements of a tuple at specified indices: -//! -//! ``` -//! let x = ("colorless", "green", "ideas", "sleep", "furiously"); -//! assert_eq!(x.3, "sleep"); -//! -//! let v = (3, 3); -//! let u = (1, -5); -//! assert_eq!(v.0 * u.0 + v.1 * u.1, -12); -//! ``` -//! -//! Using traits implemented for tuples: -//! -//! ``` -//! let a = (1, 2); -//! let b = (3, 4); -//! assert!(a != b); -//! -//! let c = b.clone(); -//! assert!(b == c); -//! -//! let d : (u32, f32) = Default::default(); -//! assert_eq!(d, (0, 0.0f32)); -//! ``` - -#![doc(primitive = "tuple")] -#![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/unit.rs b/src/libstd/unit.rs deleted file mode 100644 index 2c3ddcd9d49..00000000000 --- a/src/libstd/unit.rs +++ /dev/null @@ -1,45 +0,0 @@ -// 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. - -#![doc(primitive = "unit")] -#![stable(feature = "rust1", since = "1.0.0")] - -//! The `()` type, sometimes called "unit" or "nil". -//! -//! The `()` type has exactly one value `()`, and is used when there -//! is no other meaningful value that could be returned. `()` is most -//! commonly seen implicitly: functions without a `-> ...` implicitly -//! have return type `()`, that is, these are equivalent: -//! -//! ```rust -//! fn long() -> () {} -//! -//! fn short() {} -//! ``` -//! -//! The semicolon `;` can be used to discard the result of an -//! expression at the end of a block, making the expression (and thus -//! the block) evaluate to `()`. For example, -//! -//! ```rust -//! fn returns_i64() -> i64 { -//! 1i64 -//! } -//! fn returns_unit() { -//! 1i64; -//! } -//! -//! let is_i64 = { -//! returns_i64() -//! }; -//! let is_unit = { -//! returns_i64(); -//! }; -//! ``` |
