diff options
| author | Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> | 2017-12-11 10:01:29 +0100 |
|---|---|---|
| committer | Oliver Schneider <git-spam-no-reply9815368754983@oli-obk.de> | 2017-12-11 10:01:29 +0100 |
| commit | 7e5583b7f88c609492bf4f7b3a08313bc501b0ad (patch) | |
| tree | e23b45097d08976bd6f288402d6ec2ddbd8a982e /src/libstd | |
| parent | 0f6b5b0423fed8c630f1b97968c3aebbed816f60 (diff) | |
| parent | 5f3bd73d8143f093c58f367b46434c2d555ef62d (diff) | |
| download | rust-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.rs | 20 | ||||
| -rw-r--r-- | src/libstd/fs.rs | 134 | ||||
| -rw-r--r-- | src/libstd/io/mod.rs | 7 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 1 | ||||
| -rw-r--r-- | src/libstd/macros.rs | 31 | ||||
| -rw-r--r-- | src/libstd/net/parser.rs | 6 | ||||
| -rw-r--r-- | src/libstd/primitive_docs.rs | 128 | ||||
| -rw-r--r-- | src/libstd/sys/unix/thread.rs | 5 | ||||
| -rw-r--r-- | src/libstd/sys_common/net.rs | 5 | ||||
| -rw-r--r-- | src/libstd/sys_common/wtf8.rs | 5 |
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 { |
