summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2017-12-11 10:01:29 +0100
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2017-12-11 10:01:29 +0100
commit7e5583b7f88c609492bf4f7b3a08313bc501b0ad (patch)
treee23b45097d08976bd6f288402d6ec2ddbd8a982e /src/libstd
parent0f6b5b0423fed8c630f1b97968c3aebbed816f60 (diff)
parent5f3bd73d8143f093c58f367b46434c2d555ef62d (diff)
downloadrust-7e5583b7f88c609492bf4f7b3a08313bc501b0ad.tar.gz
rust-7e5583b7f88c609492bf4f7b3a08313bc501b0ad.zip
Merge remote-tracking branch 'origin/master' into miri
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/collections/hash/set.rs20
-rw-r--r--src/libstd/fs.rs134
-rw-r--r--src/libstd/io/mod.rs7
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd/macros.rs31
-rw-r--r--src/libstd/net/parser.rs6
-rw-r--r--src/libstd/primitive_docs.rs128
-rw-r--r--src/libstd/sys/unix/thread.rs5
-rw-r--r--src/libstd/sys_common/net.rs5
-rw-r--r--src/libstd/sys_common/wtf8.rs5
10 files changed, 303 insertions, 39 deletions
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index 51698ce7c17..7f0e5a8d2aa 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -1152,13 +1152,9 @@ impl<'a, T, S> Iterator for Intersection<'a, T, S>
 
     fn next(&mut self) -> Option<&'a T> {
         loop {
-            match self.iter.next() {
-                None => return None,
-                Some(elt) => {
-                    if self.other.contains(elt) {
-                        return Some(elt);
-                    }
-                }
+            let elt = self.iter.next()?;
+            if self.other.contains(elt) {
+                return Some(elt);
             }
         }
     }
@@ -1202,13 +1198,9 @@ impl<'a, T, S> Iterator for Difference<'a, T, S>
 
     fn next(&mut self) -> Option<&'a T> {
         loop {
-            match self.iter.next() {
-                None => return None,
-                Some(elt) => {
-                    if !self.other.contains(elt) {
-                        return Some(elt);
-                    }
-                }
+            let elt = self.iter.next()?;
+            if !self.other.contains(elt) {
+                return Some(elt);
             }
         }
     }
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index b07733d3c80..f40aed2478a 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -211,6 +211,115 @@ pub struct DirBuilder {
     recursive: bool,
 }
 
+/// Read the entire contents of a file into a bytes vector.
+///
+/// This is a convenience function for using [`File::open`] and [`read_to_end`]
+/// with fewer imports and without an intermediate variable.
+///
+/// [`File::open`]: struct.File.html#method.open
+/// [`read_to_end`]: ../io/trait.Read.html#method.read_to_end
+///
+/// # Errors
+///
+/// This function will return an error if `path` does not already exist.
+/// Other errors may also be returned according to [`OpenOptions::open`].
+///
+/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
+///
+/// It will also return an error if it encounters while reading an error
+/// of a kind other than [`ErrorKind::Interrupted`].
+///
+/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(fs_read_write)]
+///
+/// use std::fs;
+/// use std::net::SocketAddr;
+///
+/// # fn foo() -> Result<(), Box<std::error::Error + 'static>> {
+/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?;
+/// # Ok(())
+/// # }
+/// ```
+#[unstable(feature = "fs_read_write", issue = "46588")]
+pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
+    let mut bytes = Vec::new();
+    File::open(path)?.read_to_end(&mut bytes)?;
+    Ok(bytes)
+}
+
+/// Read the entire contents of a file into a string.
+///
+/// This is a convenience function for using [`File::open`] and [`read_to_string`]
+/// with fewer imports and without an intermediate variable.
+///
+/// [`File::open`]: struct.File.html#method.open
+/// [`read_to_string`]: ../io/trait.Read.html#method.read_to_string
+///
+/// # Errors
+///
+/// This function will return an error if `path` does not already exist.
+/// Other errors may also be returned according to [`OpenOptions::open`].
+///
+/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
+///
+/// It will also return an error if it encounters while reading an error
+/// of a kind other than [`ErrorKind::Interrupted`],
+/// or if the contents of the file are not valid UTF-8.
+///
+/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(fs_read_write)]
+///
+/// use std::fs;
+/// use std::net::SocketAddr;
+///
+/// # fn foo() -> Result<(), Box<std::error::Error + 'static>> {
+/// let foo: SocketAddr = fs::read_string("address.txt")?.parse()?;
+/// # Ok(())
+/// # }
+/// ```
+#[unstable(feature = "fs_read_write", issue = "46588")]
+pub fn read_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
+    let mut string = String::new();
+    File::open(path)?.read_to_string(&mut string)?;
+    Ok(string)
+}
+
+/// Write a slice as the entire contents of a file.
+///
+/// This function will create a file if it does not exist,
+/// and will entirely replace its contents if it does.
+///
+/// This is a convenience function for using [`File::create`] and [`write_all`]
+/// with fewer imports.
+///
+/// [`File::create`]: struct.File.html#method.create
+/// [`write_all`]: ../io/trait.Write.html#method.write_all
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(fs_read_write)]
+///
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// fs::write("foo.txt", b"Lorem ipsum")?;
+/// # Ok(())
+/// # }
+/// ```
+#[unstable(feature = "fs_read_write", issue = "46588")]
+pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
+    File::create(path)?.write_all(contents.as_ref())
+}
+
 impl File {
     /// Attempts to open a file in read-only mode.
     ///
@@ -1912,7 +2021,9 @@ mod tests {
     ) }
 
     #[cfg(unix)]
-    macro_rules! error { ($e:expr, $s:expr) => (
+    macro_rules! error { ($e:expr, $s:expr) => ( error_contains!($e, $s) ) }
+
+    macro_rules! error_contains { ($e:expr, $s:expr) => (
         match $e {
             Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
             Err(ref err) => assert!(err.to_string().contains($s),
@@ -2922,6 +3033,27 @@ mod tests {
     }
 
     #[test]
+    fn write_then_read() {
+        let mut bytes = [0; 1024];
+        StdRng::new().unwrap().fill_bytes(&mut bytes);
+
+        let tmpdir = tmpdir();
+
+        check!(fs::write(&tmpdir.join("test"), &bytes[..]));
+        let v = check!(fs::read(&tmpdir.join("test")));
+        assert!(v == &bytes[..]);
+
+        check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
+        error_contains!(fs::read_string(&tmpdir.join("not-utf8")),
+                        "stream did not contain valid UTF-8");
+
+        let s = "𐁁𐀓𐀠𐀴𐀍";
+        check!(fs::write(&tmpdir.join("utf8"), s.as_bytes()));
+        let string = check!(fs::read_string(&tmpdir.join("utf8")));
+        assert_eq!(string, s);
+    }
+
+    #[test]
     fn file_try_clone() {
         let tmpdir = tmpdir();
 
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index b7a3695b470..9c401d7663f 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -2019,10 +2019,9 @@ impl<R: Read> Iterator for Chars<R> {
     type Item = result::Result<char, CharsError>;
 
     fn next(&mut self) -> Option<result::Result<char, CharsError>> {
-        let first_byte = match read_one_byte(&mut self.inner) {
-            None => return None,
-            Some(Ok(b)) => b,
-            Some(Err(e)) => return Some(Err(CharsError::Other(e))),
+        let first_byte = match read_one_byte(&mut self.inner)? {
+            Ok(b) => b,
+            Err(e) => return Some(Err(CharsError::Other(e))),
         };
         let width = core_str::utf8_char_width(first_byte);
         if width == 1 { return Some(Ok(first_byte as char)) }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index bf177ac7f2c..12e6231136e 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -260,6 +260,7 @@
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(exact_size_is_empty)]
+#![feature(fs_read_write)]
 #![feature(fixed_size_array)]
 #![feature(float_from_str_radix)]
 #![feature(fn_traits)]
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 7d62f94056f..de46fedaebb 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -282,9 +282,34 @@ pub mod builtin {
 
     /// Unconditionally causes compilation to fail with the given error message when encountered.
     ///
-    /// For more information, see the [RFC].
+    /// This macro should be used when a crate uses a conditional compilation strategy to provide
+    /// better error messages for errornous conditions.
     ///
-    /// [RFC]: https://github.com/rust-lang/rfcs/blob/master/text/1695-add-error-macro.md
+    /// # Examples
+    ///
+    /// Two such examples are macros and `#[cfg]` environments.
+    ///
+    /// Emit better compiler error if a macro is passed invalid values.
+    ///
+    /// ```compile_fail
+    /// macro_rules! give_me_foo_or_bar {
+    ///     (foo) => {};
+    ///     (bar) => {};
+    ///     ($x:ident) => {
+    ///         compile_error!("This macro only accepts `foo` or `bar`");
+    ///     }
+    /// }
+    ///
+    /// give_me_foo_or_bar!(neither);
+    /// // ^ will fail at compile time with message "This macro only accepts `foo` or `bar`"
+    /// ```
+    ///
+    /// Emit compiler error if one of a number of features isn't available.
+    ///
+    /// ```compile_fail
+    /// #[cfg(not(any(feature = "foo", feature = "bar")))]
+    /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.")
+    /// ```
     #[stable(feature = "compile_error_macro", since = "1.20.0")]
     #[macro_export]
     macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) }
@@ -606,7 +631,7 @@ pub mod builtin {
     #[macro_export]
     macro_rules! module_path { () => ({ /* compiler built-in */ }) }
 
-    /// Boolean evaluation of configuration flags.
+    /// Boolean evaluation of configuration flags, at compile-time.
     ///
     /// In addition to the `#[cfg]` attribute, this macro is provided to allow
     /// boolean expression evaluation of configuration flags. This frequently
diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs
index 7d7c67ff3f9..9f7125fb935 100644
--- a/src/libstd/net/parser.rs
+++ b/src/libstd/net/parser.rs
@@ -170,11 +170,7 @@ impl<'a> Parser<'a> {
                 return None;
             }
 
-            let octet = self.read_number(10, 3, 0x100).map(|n| n as u8);
-            match octet {
-                Some(d) => bs[i] = d,
-                None => return None,
-            };
+            bs[i] = self.read_number(10, 3, 0x100).map(|n| n as u8)?;
             i += 1;
         }
         Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs
index 9e1da318242..a456e466341 100644
--- a/src/libstd/primitive_docs.rs
+++ b/src/libstd/primitive_docs.rs
@@ -67,6 +67,134 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 mod prim_bool { }
 
+#[doc(primitive = "never")]
+//
+/// The `!` type, also called "never".
+///
+/// `!` represents the type of computations which never resolve to any value at all. For example,
+/// the [`exit`] function `fn exit(code: i32) -> !` exits the process without ever returning, and
+/// so returns `!`.
+///
+/// `break`, `continue` and `return` expressions also have type `!`. For example we are allowed to
+/// write:
+///
+/// ```
+/// #![feature(never_type)]
+/// # fn foo() -> u32 {
+/// let x: ! = {
+///     return 123
+/// };
+/// # }
+/// ```
+///
+/// Although the `let` is pointless here, it illustrates the meaning of `!`. Since `x` is never
+/// assigned a value (because `return` returns from the entire function), `x` can be given type
+/// `!`. We could also replace `return 123` with a `panic!` or a never-ending `loop` and this code
+/// would still be valid.
+///
+/// A more realistic usage of `!` is in this code:
+///
+/// ```
+/// # fn get_a_number() -> Option<u32> { None }
+/// # loop {
+/// let num: u32 = match get_a_number() {
+///     Some(num) => num,
+///     None => break,
+/// };
+/// # }
+/// ```
+///
+/// Both match arms must produce values of type [`u32`], but since `break` never produces a value
+/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another
+/// behaviour of the `!` type - expressions with type `!` will coerce into any other type.
+///
+/// [`u32`]: primitive.str.html
+/// [`exit`]: process/fn.exit.html
+///
+/// # `!` and generics
+///
+/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`]
+/// trait:
+///
+/// ```
+/// trait FromStr: Sized {
+///     type Err;
+///     fn from_str(s: &str) -> Result<Self, Self::Err>;
+/// }
+/// ```
+///
+/// When implementing this trait for [`String`] we need to pick a type for [`Err`]. And since
+/// converting a string into a string will never result in an error, the appropriate type is `!`.
+/// (Currently the type actually used is an enum with no variants, though this is only because `!`
+/// was added to Rust at a later date and it may change in the future). With an [`Err`] type of
+/// `!`, if we have to call [`String::from_str`] for some reason the result will be a
+/// [`Result<String, !>`] which we can unpack like this:
+///
+/// ```ignore (string-from-str-error-type-is-not-never-yet)
+/// // NOTE: This does not work today!
+/// let Ok(s) = String::from_str("hello");
+/// ```
+///
+/// Since the [`Err`] variant contains a `!`, it can never occur. So we can exhaustively match on
+/// [`Result<T, !>`] by just taking the [`Ok`] variant. This illustrates another behaviour of `!` -
+/// it can be used to "delete" certain enum variants from generic types like `Result`.
+///
+/// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str
+/// [`Result<String, !>`]: result/enum.Result.html
+/// [`Result<T, !>`]: result/enum.Result.html
+/// [`Ok`]: result/enum.Result.html#variant.Ok
+/// [`String`]: string/struct.String.html
+/// [`Err`]: result/enum.Result.html#variant.Err
+/// [`FromStr`]: str/trait.FromStr.html
+///
+/// # `!` and traits
+///
+/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
+/// which doesn't `panic!`. As is turns out, most traits can have an `impl` for `!`. Take [`Debug`]
+/// for example:
+///
+/// ```
+/// # #![feature(never_type)]
+/// # use std::fmt;
+/// # trait Debug {
+/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result;
+/// # }
+/// impl Debug for ! {
+///     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+///         *self
+///     }
+/// }
+/// ```
+///
+/// Once again we're using `!`'s ability to coerce into any other type, in this case
+/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be
+/// called (because there is no value of type `!` for it to be called with). Writing `*self`
+/// essentially tells the compiler "We know that this code can never be run, so just treat the
+/// entire function body has having type [`fmt::Result`]". This pattern can be used a lot when
+/// implementing traits for `!`. Generally, any trait which only has methods which take a `self`
+/// parameter should have such as impl.
+///
+/// On the other hand, one trait which would not be appropriate to implement is [`Default`]:
+///
+/// ```
+/// trait Default {
+///     fn default() -> Self;
+/// }
+/// ```
+///
+/// Since `!` has no values, it has no default value either. It's true that we could write an
+/// `impl` for this which simply panics, but the same is true for any type (we could `impl
+/// Default` for (eg.) [`File`] by just making [`default()`] panic.)
+///
+/// [`fmt::Result`]: fmt/type.Result.html
+/// [`File`]: fs/struct.File.html
+/// [`Debug`]: fmt/trait.Debug.html
+/// [`Default`]: default/trait.Default.html
+/// [`default()`]: default/trait.Default.html#tymethod.default
+///
+#[unstable(feature = "never_type_impls", issue = "35121")]
+mod prim_never { }
+
 #[doc(primitive = "char")]
 //
 /// A character type.
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index 9da33f5adac..cb249af4254 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -255,10 +255,7 @@ pub mod guard {
 
     pub unsafe fn init() -> Option<usize> {
         let psize = os::page_size();
-        let mut stackaddr = match get_stack_start() {
-            Some(addr) => addr,
-            None => return None,
-        };
+        let mut stackaddr = get_stack_start()?;
 
         // Ensure stackaddr is page aligned! A parent process might
         // have reset RLIMIT_STACK to be non-page aligned. The
diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs
index c76b0bcf1c9..c70b39995eb 100644
--- a/src/libstd/sys_common/net.rs
+++ b/src/libstd/sys_common/net.rs
@@ -136,10 +136,7 @@ impl Iterator for LookupHost {
     fn next(&mut self) -> Option<SocketAddr> {
         loop {
             unsafe {
-                let cur = match self.cur.as_ref() {
-                    None => return None,
-                    Some(c) => c,
-                };
+                let cur = self.cur.as_ref()?;
                 self.cur = cur.ai_next;
                 match sockaddr_to_addr(mem::transmute(cur.ai_addr),
                                        cur.ai_addrlen as usize)
diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs
index e212b5006f2..b2fc559bb37 100644
--- a/src/libstd/sys_common/wtf8.rs
+++ b/src/libstd/sys_common/wtf8.rs
@@ -578,10 +578,7 @@ impl Wtf8 {
     fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> {
         let mut iter = self.bytes[pos..].iter();
         loop {
-            let b = match iter.next() {
-                None => return None,
-                Some(&b) => b,
-            };
+            let b = *iter.next()?;
             if b < 0x80 {
                 pos += 1;
             } else if b < 0xE0 {