From 45c10db41f2af5919621ff69f5dc090cc917c1d3 Mon Sep 17 00:00:00 2001 From: bcoopers Date: Sun, 29 Mar 2015 19:08:53 -0400 Subject: Clarified and simplified algorithm for increasing size of buffer in read_to_end() --- src/libstd/io/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 830a88bb6c9..3de9a068926 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -101,15 +101,14 @@ fn append_to_string(buf: &mut String, f: F) -> Result fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { let start_len = buf.len(); let mut len = start_len; - let mut cap_bump = 16; + let min_cap_bump = 16; let ret; loop { if len == buf.len() { if buf.capacity() == buf.len() { - if cap_bump < DEFAULT_BUF_SIZE { - cap_bump *= 2; - } - buf.reserve(cap_bump); + // reserve() rounds up our request to the nearest power of two, so after the first + // time the capacity is exceeded, we double our capacity at each call to reserve. + buf.reserve(min_cap_bump); } let new_area = buf.capacity() - buf.len(); buf.extend(iter::repeat(0).take(new_area)); -- cgit 1.4.1-3-g733a5 From 2982fe39ad93e29709a2e1414a4228718c8de28a Mon Sep 17 00:00:00 2001 From: bcoopers Date: Sun, 29 Mar 2015 19:23:46 -0400 Subject: 80 character line limit --- src/libstd/io/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 3de9a068926..bc3791b99d0 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -106,8 +106,9 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result loop { if len == buf.len() { if buf.capacity() == buf.len() { - // reserve() rounds up our request to the nearest power of two, so after the first - // time the capacity is exceeded, we double our capacity at each call to reserve. + // reserve() rounds up our request to the nearest power of two, + // so after the first time the capacity is exceeded, we double + // our capacity at each call to reserve. buf.reserve(min_cap_bump); } let new_area = buf.capacity() - buf.len(); -- cgit 1.4.1-3-g733a5 From 8d3e55908ae0e51f04c170133c9f9739886b8e2e Mon Sep 17 00:00:00 2001 From: bcoopers Date: Sun, 29 Mar 2015 19:29:11 -0400 Subject: Clearer wording --- src/libstd/io/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index bc3791b99d0..c4ec2a7ca17 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -106,9 +106,9 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result loop { if len == buf.len() { if buf.capacity() == buf.len() { - // reserve() rounds up our request to the nearest power of two, - // so after the first time the capacity is exceeded, we double - // our capacity at each call to reserve. + // reserve() rounds up our request such that every request + // (with maybe the exception of the first request) for the + // same amount of space doubles our capacity. buf.reserve(min_cap_bump); } let new_area = buf.capacity() - buf.len(); -- cgit 1.4.1-3-g733a5 From 240734c31e529557583a0dc8e97abf858b4a375d Mon Sep 17 00:00:00 2001 From: bcoopers Date: Mon, 30 Mar 2015 13:59:32 -0400 Subject: Only zero at most 64k at a time. We still use the doubling reallocation strategy since extend() calls reserve() and/or push() for us. --- src/libstd/io/mod.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index c4ec2a7ca17..6b03fb45c77 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -101,18 +101,14 @@ fn append_to_string(buf: &mut String, f: F) -> Result fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { let start_len = buf.len(); let mut len = start_len; - let min_cap_bump = 16; + let mut new_write_size = 16; let ret; loop { if len == buf.len() { - if buf.capacity() == buf.len() { - // reserve() rounds up our request such that every request - // (with maybe the exception of the first request) for the - // same amount of space doubles our capacity. - buf.reserve(min_cap_bump); + if new_write_size < DEFAULT_BUF_SIZE { + new_write_size *= 2; } - let new_area = buf.capacity() - buf.len(); - buf.extend(iter::repeat(0).take(new_area)); + buf.extend(iter::repeat(0).take(new_write_size)); } match r.read(&mut buf[len..]) { -- cgit 1.4.1-3-g733a5 From 8ded1562658915f6160f5b83e5036c6900c139e3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 1 Apr 2015 01:11:38 -0400 Subject: Add examples + documentation for std::path --- src/libstd/path.rs | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 58d3ae9f7cf..df0b3842b7a 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -344,6 +344,15 @@ impl<'a> Prefix<'a> { /// Determine whether the character is one of the permitted path /// separators for the current platform. +/// +/// # Examples +/// +/// ``` +/// use std::path; +/// +/// assert!(path::is_separator('/')); +/// assert!(!path::is_separator('❤')); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_separator(c: char) -> bool { use ascii::*; @@ -540,6 +549,18 @@ impl<'a> AsRef for Component<'a> { /// /// See the module documentation for an in-depth explanation of components and /// their role in the API. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// +/// let path = Path::new("/tmp/foo/bar.txt"); +/// +/// for component in path.components() { +/// println!("{:?}", component); +/// } +/// ``` #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Components<'a> { @@ -610,6 +631,16 @@ impl<'a> Components<'a> { } /// Extract a slice corresponding to the portion of the path remaining for iteration. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo/bar.txt"); + /// + /// println!("{:?}", path.components().as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { let mut comps = self.clone(); @@ -1207,12 +1238,28 @@ impl Path { /// Directly wrap a string slice as a `Path` slice. /// /// This is a cost-free conversion. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// Path::new("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new + ?Sized>(s: &S) -> &Path { unsafe { mem::transmute(s.as_ref()) } } /// Yield the underlying `OsStr` slice. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let os_str = Path::new("foo.txt").as_os_str(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &OsStr { &self.inner @@ -1221,6 +1268,14 @@ impl Path { /// Yield a `&str` slice if the `Path` is valid unicode. /// /// This conversion may entail doing a check for UTF-8 validity. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path_str = Path::new("foo.txt").to_str(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_str(&self) -> Option<&str> { self.inner.to_str() @@ -1229,12 +1284,28 @@ impl Path { /// Convert a `Path` to a `Cow`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path_str = Path::new("foo.txt").to_string_lossy(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_string_lossy(&self) -> Cow { self.inner.to_string_lossy() } /// Convert a `Path` to an owned `PathBuf`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path_str = Path::new("foo.txt").to_path_buf(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_path_buf(&self) -> PathBuf { PathBuf::from(self.inner.to_os_string()) @@ -1248,6 +1319,14 @@ impl Path { /// * On Windows, a path is absolute if it has a prefix and starts with the /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. In /// other words, `path.is_absolute() == path.prefix().is_some() && path.has_root()`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// assert_eq!(false, Path::new("foo.txt").is_absolute()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_absolute(&self) -> bool { self.has_root() && @@ -1255,6 +1334,14 @@ impl Path { } /// A path is *relative* if it is not absolute. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// assert!(Path::new("foo.txt").is_relative()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_relative(&self) -> bool { !self.is_absolute() @@ -1278,6 +1365,14 @@ impl Path { /// * has no prefix and begins with a separator, e.g. `\\windows` /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows` /// * has any non-disk prefix, e.g. `\\server\share` + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// assert!(Path::new("/etc/passwd").has_root()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn has_root(&self) -> bool { self.components().has_root() @@ -1294,8 +1389,11 @@ impl Path { /// /// let path = Path::new("/foo/bar"); /// let foo = path.parent().unwrap(); + /// /// assert!(foo == Path::new("/foo")); + /// /// let root = foo.parent().unwrap(); + /// /// assert!(root == Path::new("/")); /// assert!(root.parent() == None); /// ``` @@ -1315,6 +1413,17 @@ impl Path { /// /// If the path terminates in `.`, `..`, or consists solely or a root of /// prefix, `file_name` will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("hello_world.rs"); + /// let filename = "hello_world.rs"; + /// + /// assert_eq!(filename, path.file_name().unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { self.components().next_back().and_then(|p| match p { @@ -1334,12 +1443,32 @@ impl Path { } /// Determines whether `base` is a prefix of `self`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/etc/passwd"); + /// + /// assert!(path.starts_with("/etc")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn starts_with>(&self, base: P) -> bool { iter_after(self.components(), base.as_ref().components()).is_some() } /// Determines whether `child` is a suffix of `self`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/etc/passwd"); + /// + /// assert!(path.ends_with("passwd")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn ends_with>(&self, child: P) -> bool { iter_after(self.components().rev(), child.as_ref().components().rev()).is_some() @@ -1353,6 +1482,16 @@ impl Path { /// * The entire file name if there is no embedded `.`; /// * The entire file name if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name before the final `.` + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("foo.rs"); + /// + /// assert_eq!("foo", path.file_stem().unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_stem(&self) -> Option<&OsStr> { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) @@ -1366,6 +1505,16 @@ impl Path { /// * None, if there is no embedded `.`; /// * None, if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name after the final `.` + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("foo.rs"); + /// + /// assert_eq!("rs", path.extension().unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn extension(&self) -> Option<&OsStr> { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after)) @@ -1374,6 +1523,16 @@ impl Path { /// Creates an owned `PathBuf` with `path` adjoined to `self`. /// /// See `PathBuf::push` for more details on what it means to adjoin a path. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp"); + /// + /// let new_path = path.join("foo"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn join>(&self, path: P) -> PathBuf { let mut buf = self.to_path_buf(); @@ -1384,6 +1543,16 @@ impl Path { /// Creates an owned `PathBuf` like `self` but with the given file name. /// /// See `PathBuf::set_file_name` for more details. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// let new_path = path.with_file_name("bar.rs"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_file_name>(&self, file_name: S) -> PathBuf { let mut buf = self.to_path_buf(); @@ -1394,6 +1563,16 @@ impl Path { /// Creates an owned `PathBuf` like `self` but with the given extension. /// /// See `PathBuf::set_extension` for more details. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// let new_path = path.with_extension("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { let mut buf = self.to_path_buf(); @@ -1402,6 +1581,18 @@ impl Path { } /// Produce an iterator over the components of the path. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// for component in path.components() { + /// println!("{:?}", component); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn components(&self) -> Components { let prefix = parse_prefix(self.as_os_str()); @@ -1415,6 +1606,18 @@ impl Path { } /// Produce an iterator over the path's components viewed as `OsStr` slices. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// for component in path.iter() { + /// println!("{:?}", component); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter { Iter { inner: self.components() } @@ -1422,6 +1625,16 @@ impl Path { /// Returns an object that implements `Display` for safely printing paths /// that may contain non-Unicode data. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// println!("{}", path.display()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn display(&self) -> Display { Display { path: self } -- cgit 1.4.1-3-g733a5 From 28d7693930513e0591458e09b430483dd69fd3da Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Wed, 1 Apr 2015 20:38:58 +0300 Subject: iOS: os::last_os_error() fallout --- src/libstd/rand/os.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 7aba40dc6be..38c57eec684 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -185,9 +185,9 @@ mod imp { mod imp { use prelude::v1::*; + use io; use old_io::IoResult; use mem; - use os; use rand::Rng; use libc::{c_int, size_t}; @@ -241,7 +241,7 @@ mod imp { SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr()) }; if ret == -1 { - panic!("couldn't generate random bytes: {}", os::last_os_error()); + panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); } } } -- cgit 1.4.1-3-g733a5 From ed63d32651105e56afceb94cbb86f115db235825 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 Apr 2015 10:11:46 -0400 Subject: Add (unstable) FnBox trait as a nicer replacement for `Thunk`. The doc comment includes a test that also shows how it can be used. --- src/liballoc/boxed.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 1 + 2 files changed, 76 insertions(+) (limited to 'src/libstd') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 550b25ac3a7..8d3a63ceb50 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -355,3 +355,78 @@ impl<'a, 'b> From<&'b str> for Box { } } } + +/// `FnBox` is a version of the `FnOnce` intended for use with boxed +/// closure objects. The idea is that where one would normally store a +/// `Box` in a data structure, you should use +/// `Box`. The two traits behave essentially the same, except +/// that a `FnBox` closure can only be called if it is boxed. (Note +/// that `FnBox` may be deprecated in the future if `Box` +/// closures become directly usable.) +/// +/// ### Example +/// +/// Here is a snippet of code which creates a hashmap full of boxed +/// once closures and then removes them one by one, calling each +/// closure as it is removed. Note that the type of the closures +/// stored in the map is `Box i32>` and not `Box i32>`. +/// +/// ``` +/// #![feature(core)] +/// +/// use std::boxed::FnBox; +/// use std::collections::HashMap; +/// +/// fn make_map() -> HashMap i32>> { +/// let mut map: HashMap i32>> = HashMap::new(); +/// map.insert(1, Box::new(|| 22)); +/// map.insert(2, Box::new(|| 44)); +/// map +/// } +/// +/// fn main() { +/// let mut map = make_map(); +/// for i in &[1, 2] { +/// let f = map.remove(&i).unwrap(); +/// assert_eq!(f(), i * 22); +/// } +/// } +/// ``` +#[cfg(not(stage0))] +#[rustc_paren_sugar] +#[unstable(feature = "core", reason = "Newly introduced")] +pub trait FnBox { + type Output; + + extern "rust-call" fn call_box(self: Box, args: A) -> Self::Output; +} + +#[cfg(not(stage0))] +impl FnBox for F + where F: FnOnce +{ + type Output = F::Output; + + extern "rust-call" fn call_box(self: Box, args: A) -> F::Output { + self.call_once(args) + } +} + +#[cfg(not(stage0))] +impl FnOnce for Box> { + type Output = R; + + extern "rust-call" fn call_once(self, args: A) -> R { + self.call_box(args) + } +} + +#[cfg(not(stage0))] +impl FnOnce for Box+Send> { + type Output = R; + + extern "rust-call" fn call_once(self, args: A) -> R { + self.call_box(args) + } +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 41ac3d60df5..3c73ce7634c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -243,6 +243,7 @@ mod uint_macros; #[path = "num/f64.rs"] pub mod f64; pub mod ascii; + pub mod thunk; /* Common traits */ -- cgit 1.4.1-3-g733a5 From cade32acf6f5ff209ee082d70350d9bc0362985a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 Apr 2015 11:12:30 -0400 Subject: Remove `Thunk` struct and `Invoke` trait; change `Thunk` to be an alias for `Box`. I found the alias was still handy because it is shorter than the fully written type. This is a [breaking-change]: convert code using `Invoke` to use `FnBox`, which is usually pretty straight-forward. Code using thunk mostly works if you change `Thunk::new => Box::new` and `foo.invoke(arg)` to `foo(arg)`. --- src/compiletest/compiletest.rs | 3 +-- src/liballoc/boxed.rs | 12 ++++------- src/librustdoc/test.rs | 3 +-- src/libstd/rt/at_exit_imp.rs | 2 +- src/libstd/rt/mod.rs | 3 +-- src/libstd/sync/future.rs | 5 +++-- src/libstd/sys/common/thread.rs | 3 ++- src/libstd/thread/mod.rs | 28 +++++++++++++++----------- src/libstd/thunk.rs | 42 +++------------------------------------ src/libtest/lib.rs | 29 ++++++++++++++------------- src/test/run-pass/issue-11709.rs | 2 +- src/test/run-pass/issue-11958.rs | 2 +- src/test/run-pass/issue-17897.rs | 6 +++--- src/test/run-pass/issue-18188.rs | 4 ++-- src/test/run-pass/issue-2190-1.rs | 4 ++-- src/test/run-pass/issue-3609.rs | 1 - 16 files changed, 56 insertions(+), 93 deletions(-) (limited to 'src/libstd') diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 7fd09f9e1f5..f00ff9bcbe5 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -31,7 +31,6 @@ extern crate log; use std::env; use std::fs; use std::path::{Path, PathBuf}; -use std::thunk::Thunk; use getopts::{optopt, optflag, reqopt}; use common::Config; use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen}; @@ -351,7 +350,7 @@ pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName { pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn { let config = (*config).clone(); let testfile = testfile.to_path_buf(); - test::DynTestFn(Thunk::new(move || { + test::DynTestFn(Box::new(move || { runtest::run(config, &testfile) })) } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8d3a63ceb50..8e3be7dd05b 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -393,28 +393,25 @@ impl<'a, 'b> From<&'b str> for Box { /// } /// } /// ``` -#[cfg(not(stage0))] #[rustc_paren_sugar] #[unstable(feature = "core", reason = "Newly introduced")] pub trait FnBox { type Output; - extern "rust-call" fn call_box(self: Box, args: A) -> Self::Output; + fn call_box(self: Box, args: A) -> Self::Output; } -#[cfg(not(stage0))] impl FnBox for F where F: FnOnce { type Output = F::Output; - extern "rust-call" fn call_box(self: Box, args: A) -> F::Output { + fn call_box(self: Box, args: A) -> F::Output { self.call_once(args) } } -#[cfg(not(stage0))] -impl FnOnce for Box> { +impl<'a,A,R> FnOnce for Box+'a> { type Output = R; extern "rust-call" fn call_once(self, args: A) -> R { @@ -422,8 +419,7 @@ impl FnOnce for Box> { } } -#[cfg(not(stage0))] -impl FnOnce for Box+Send> { +impl<'a,A,R> FnOnce for Box+Send+'a> { type Output = R; extern "rust-call" fn call_once(self, args: A) -> R { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index babbe15b17d..f5bee6240d4 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -19,7 +19,6 @@ use std::path::PathBuf; use std::process::Command; use std::str; use std::sync::{Arc, Mutex}; -use std::thunk::Thunk; use testing; use rustc_lint; @@ -366,7 +365,7 @@ impl Collector { ignore: should_ignore, should_panic: testing::ShouldPanic::No, // compiler failures are test failures }, - testfn: testing::DynTestFn(Thunk::new(move|| { + testfn: testing::DynTestFn(Box::new(move|| { runtest(&test, &cratename, libs, diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs index 9079c0aaffb..beb2870807a 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/rt/at_exit_imp.rs @@ -64,7 +64,7 @@ pub fn cleanup() { if queue as usize != 0 { let queue: Box = Box::from_raw(queue); for to_run in *queue { - to_run.invoke(()); + to_run(); } } } diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 696c7960c3e..632d9647212 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -21,7 +21,6 @@ use prelude::v1::*; use sys; -use thunk::Thunk; use usize; // Reexport some of our utilities which are expected by other crates. @@ -153,7 +152,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { /// that the closure could not be registered, meaning that it is not scheduled /// to be rune. pub fn at_exit(f: F) -> Result<(), ()> { - if at_exit_imp::push(Thunk::new(f)) {Ok(())} else {Err(())} + if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} } /// One-time runtime cleanup. diff --git a/src/libstd/sync/future.rs b/src/libstd/sync/future.rs index b2afe28fed4..2cdde1aca9e 100644 --- a/src/libstd/sync/future.rs +++ b/src/libstd/sync/future.rs @@ -36,6 +36,7 @@ use core::prelude::*; use core::mem::replace; +use boxed::Box; use self::FutureState::*; use sync::mpsc::{Receiver, channel}; use thunk::Thunk; @@ -84,7 +85,7 @@ impl Future { match replace(&mut self.state, Evaluating) { Forced(_) | Evaluating => panic!("Logic error."), Pending(f) => { - self.state = Forced(f.invoke(())); + self.state = Forced(f()); self.get_ref() } } @@ -114,7 +115,7 @@ impl Future { * function. It is not spawned into another task. */ - Future {state: Pending(Thunk::new(f))} + Future {state: Pending(Box::new(f))} } } diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys/common/thread.rs index f45daea18a2..1845b6266ed 100644 --- a/src/libstd/sys/common/thread.rs +++ b/src/libstd/sys/common/thread.rs @@ -25,6 +25,7 @@ pub fn start_thread(main: *mut libc::c_void) { unsafe { stack::record_os_managed_stack_bounds(0, usize::MAX); let _handler = stack_overflow::Handler::new(); - Box::from_raw(main as *mut Thunk).invoke(()); + let main: Box = Box::from_raw(main as *mut Thunk); + main(); } } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 1202b353317..9ab35382845 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -257,7 +257,7 @@ impl Builder { pub fn spawn(self, f: F) -> io::Result where F: FnOnce(), F: Send + 'static { - self.spawn_inner(Thunk::new(f)).map(|i| JoinHandle(i)) + self.spawn_inner(Box::new(f)).map(|i| JoinHandle(i)) } /// Spawn a new child thread that must be joined within a given @@ -279,7 +279,7 @@ impl Builder { pub fn scoped<'a, T, F>(self, f: F) -> io::Result> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { - self.spawn_inner(Thunk::new(f)).map(|inner| { + self.spawn_inner(Box::new(f)).map(|inner| { JoinGuard { inner: inner, _marker: PhantomData } }) } @@ -315,7 +315,7 @@ impl Builder { thread_info::set(imp::guard::current(), their_thread); } - let mut output = None; + let mut output: Option = None; let try_result = { let ptr = &mut output; @@ -327,7 +327,11 @@ impl Builder { // 'unwinding' flag in the thread itself. For these reasons, // this unsafety should be ok. unsafe { - unwind::try(move || *ptr = Some(f.invoke(()))) + unwind::try(move || { + let f: Thunk<(), T> = f; + let v: T = f(); + *ptr = Some(v) + }) } }; unsafe { @@ -340,7 +344,7 @@ impl Builder { }; Ok(JoinInner { - native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }), + native: try!(unsafe { imp::create(stack_size, Box::new(main)) }), thread: my_thread, packet: my_packet, joined: false, @@ -820,7 +824,7 @@ mod test { let x: Box<_> = box 1; let x_in_parent = (&*x) as *const i32 as usize; - spawnfn(Thunk::new(move|| { + spawnfn(Box::new(move|| { let x_in_child = (&*x) as *const i32 as usize; tx.send(x_in_child).unwrap(); })); @@ -832,7 +836,7 @@ mod test { #[test] fn test_avoid_copying_the_body_spawn() { avoid_copying_the_body(|v| { - thread::spawn(move || v.invoke(())); + thread::spawn(move || v()); }); } @@ -840,7 +844,7 @@ mod test { fn test_avoid_copying_the_body_thread_spawn() { avoid_copying_the_body(|f| { thread::spawn(move|| { - f.invoke(()); + f(); }); }) } @@ -849,7 +853,7 @@ mod test { fn test_avoid_copying_the_body_join() { avoid_copying_the_body(|f| { let _ = thread::spawn(move|| { - f.invoke(()) + f() }).join(); }) } @@ -862,13 +866,13 @@ mod test { // valgrind-friendly. try this at home, instead..!) const GENERATIONS: u32 = 16; fn child_no(x: u32) -> Thunk<'static> { - return Thunk::new(move|| { + return Box::new(move|| { if x < GENERATIONS { - thread::spawn(move|| child_no(x+1).invoke(())); + thread::spawn(move|| child_no(x+1)()); } }); } - thread::spawn(|| child_no(0).invoke(())); + thread::spawn(|| child_no(0)()); } #[test] diff --git a/src/libstd/thunk.rs b/src/libstd/thunk.rs index a9cb05b368f..6091794ed42 100644 --- a/src/libstd/thunk.rs +++ b/src/libstd/thunk.rs @@ -12,45 +12,9 @@ #![allow(missing_docs)] #![unstable(feature = "std_misc")] -use alloc::boxed::Box; +use alloc::boxed::{Box, FnBox}; use core::marker::Send; -use core::ops::FnOnce; -pub struct Thunk<'a, A=(),R=()> { - invoke: Box+Send + 'a>, -} +pub type Thunk<'a, A=(), R=()> = + Box + Send + 'a>; -impl<'a, R> Thunk<'a,(),R> { - pub fn new(func: F) -> Thunk<'a,(),R> - where F : FnOnce() -> R, F : Send + 'a - { - Thunk::with_arg(move|()| func()) - } -} - -impl<'a,A,R> Thunk<'a,A,R> { - pub fn with_arg(func: F) -> Thunk<'a,A,R> - where F : FnOnce(A) -> R, F : Send + 'a - { - Thunk { - invoke: Box::::new(func) - } - } - - pub fn invoke(self, arg: A) -> R { - self.invoke.invoke(arg) - } -} - -pub trait Invoke { - fn invoke(self: Box, arg: A) -> R; -} - -impl Invoke for F - where F : FnOnce(A) -> R -{ - fn invoke(self: Box, arg: A) -> R { - let f = *self; - f(arg) - } -} diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index f7e5c9f1dee..879ed03009f 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -62,6 +62,7 @@ use self::OutputLocation::*; use stats::Stats; use getopts::{OptGroup, optflag, optopt}; use serialize::Encodable; +use std::boxed::FnBox; use term::Terminal; use term::color::{Color, RED, YELLOW, GREEN, CYAN}; @@ -79,7 +80,7 @@ use std::path::PathBuf; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; use std::thread; -use std::thunk::{Thunk, Invoke}; +use std::thunk::Thunk; use std::time::Duration; // to be used by rustc to compile tests in libtest @@ -158,7 +159,7 @@ pub enum TestFn { StaticBenchFn(fn(&mut Bencher)), StaticMetricFn(fn(&mut MetricMap)), DynTestFn(Thunk<'static>), - DynMetricFn(Box Invoke<&'a mut MetricMap>+'static>), + DynMetricFn(Box), DynBenchFn(Box) } @@ -936,7 +937,7 @@ pub fn run_test(opts: &TestOpts, io::set_print(box Sink(data2.clone())); io::set_panic(box Sink(data2)); } - testfn.invoke(()) + testfn() }).unwrap(); let test_result = calc_result(&desc, result_guard.join()); let stdout = data.lock().unwrap().to_vec(); @@ -957,7 +958,7 @@ pub fn run_test(opts: &TestOpts, } DynMetricFn(f) => { let mut mm = MetricMap::new(); - f.invoke(&mut mm); + f.call_box((&mut mm,)); // TODO unfortunate monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap(); return; } @@ -969,7 +970,7 @@ pub fn run_test(opts: &TestOpts, } DynTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, f), StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, - Thunk::new(move|| f())) + Box::new(move|| f())) } } @@ -1185,7 +1186,7 @@ mod tests { ignore: true, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1202,7 +1203,7 @@ mod tests { ignore: true, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1219,7 +1220,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes(None) }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1236,7 +1237,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes(Some("error message")) }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1253,7 +1254,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes(Some("foobar")) }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1270,7 +1271,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes(None) }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1306,7 +1307,7 @@ mod tests { ignore: true, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(move|| {})), + testfn: DynTestFn(Box::new(move|| {})), }, TestDescAndFn { desc: TestDesc { @@ -1314,7 +1315,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(move|| {})), + testfn: DynTestFn(Box::new(move|| {})), }); let filtered = filter_tests(&opts, tests); @@ -1350,7 +1351,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(testfn)), + testfn: DynTestFn(Box::new(testfn)), }; tests.push(test); } diff --git a/src/test/run-pass/issue-11709.rs b/src/test/run-pass/issue-11709.rs index da3efb4fea8..3ad78f088f9 100644 --- a/src/test/run-pass/issue-11709.rs +++ b/src/test/run-pass/issue-11709.rs @@ -25,7 +25,7 @@ fn test(slot: &mut Option>) -> () { let a = slot.take(); let _a = match a { // `{let .. a(); }` would break - Some(a) => { let _a = a.invoke(()); }, + Some(a) => { let _a = a(); }, None => (), }; } diff --git a/src/test/run-pass/issue-11958.rs b/src/test/run-pass/issue-11958.rs index ed2009dab1b..def85b47667 100644 --- a/src/test/run-pass/issue-11958.rs +++ b/src/test/run-pass/issue-11958.rs @@ -23,5 +23,5 @@ use std::thunk::Thunk; pub fn main() { let mut x = 1; - let _thunk = Thunk::new(move|| { x = 2; }); + let _thunk = Box::new(move|| { x = 2; }); } diff --git a/src/test/run-pass/issue-17897.rs b/src/test/run-pass/issue-17897.rs index 3fbdb92e906..cf8c54fdd80 100644 --- a/src/test/run-pass/issue-17897.rs +++ b/src/test/run-pass/issue-17897.rs @@ -12,10 +12,10 @@ use std::thunk::Thunk; -fn action(cb: Thunk) -> usize { - cb.invoke(1) +fn action(cb: Thunk<(usize,), usize>) -> usize { + cb(1) } pub fn main() { - println!("num: {}", action(Thunk::with_arg(move |u| u))); + println!("num: {}", action(Box::new(move |u| u))); } diff --git a/src/test/run-pass/issue-18188.rs b/src/test/run-pass/issue-18188.rs index cd28d642551..059d25173c2 100644 --- a/src/test/run-pass/issue-18188.rs +++ b/src/test/run-pass/issue-18188.rs @@ -16,13 +16,13 @@ use std::thunk::Thunk; pub trait Promisable: Send + Sync {} impl Promisable for T {} -pub fn propagate<'a, T, E, F, G>(action: F) -> Thunk<'a,Result, Result> +pub fn propagate<'a, T, E, F, G>(action: F) -> Thunk<'a, (Result,), Result> where T: Promisable + Clone + 'a, E: Promisable + Clone + 'a, F: FnOnce(&T) -> Result + Send + 'a, G: FnOnce(Result) -> Result + 'a { - Thunk::with_arg(move |result: Result| { + Box::new(move |result: Result| { match result { Ok(ref t) => action(t), Err(ref e) => Err(e.clone()), diff --git a/src/test/run-pass/issue-2190-1.rs b/src/test/run-pass/issue-2190-1.rs index b2c21a274cb..5c84c30aa7f 100644 --- a/src/test/run-pass/issue-2190-1.rs +++ b/src/test/run-pass/issue-2190-1.rs @@ -18,11 +18,11 @@ use std::thunk::Thunk; static generations: usize = 1024+256+128+49; fn spawn(f: Thunk<'static>) { - Builder::new().stack_size(32 * 1024).spawn(move|| f.invoke(())); + Builder::new().stack_size(32 * 1024).spawn(move|| f()); } fn child_no(x: usize) -> Thunk<'static> { - Thunk::new(move|| { + Box::new(move|| { if x < generations { spawn(child_no(x+1)); } diff --git a/src/test/run-pass/issue-3609.rs b/src/test/run-pass/issue-3609.rs index 45eb21374e2..2167a3df976 100644 --- a/src/test/run-pass/issue-3609.rs +++ b/src/test/run-pass/issue-3609.rs @@ -13,7 +13,6 @@ use std::thread; use std::sync::mpsc::Sender; -use std::thunk::Invoke; type RingBuffer = Vec ; type SamplesFn = Box; -- cgit 1.4.1-3-g733a5 From 19d3dab31b1fca3abc3ba00173b9148bd70d24b0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 Apr 2015 15:25:47 -0400 Subject: Collect the definition of the `Error` trait into `libstd` for now. This sidesteps a coherence difficulty where `liballoc` had to prove that `&str: !Error`, which didn't involve any local types. --- src/liballoc/boxed.rs | 53 +-------------- src/libcollections/string.rs | 11 ---- src/libcore/error.rs | 56 ---------------- src/libcore/lib.rs | 1 - src/libcore/num/mod.rs | 41 ++++++------ src/libcore/str/mod.rs | 16 ----- src/libstd/error.rs | 152 +++++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 2 +- 8 files changed, 175 insertions(+), 157 deletions(-) delete mode 100644 src/libcore/error.rs create mode 100644 src/libstd/error.rs (limited to 'src/libstd') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c4541e34cdb..bbf5d7a6042 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -51,15 +51,12 @@ use core::prelude::*; use core::any::Any; use core::cmp::Ordering; use core::default::Default; -use core::error::Error; use core::fmt; use core::hash::{self, Hash}; use core::mem; use core::ops::{Deref, DerefMut}; -use core::ptr::{self, Unique}; -use core::raw::{TraitObject, Slice}; - -use heap; +use core::ptr::{Unique}; +use core::raw::{TraitObject}; /// A value that represents the heap. This is the default place that the `box` /// keyword allocates into when no place is supplied. @@ -303,49 +300,3 @@ impl DoubleEndedIterator for Box { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Box {} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + Send + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> From<&'b str> for Box { - fn from(err: &'b str) -> Box { - #[derive(Debug)] - struct StringError(Box); - impl Error for StringError { - fn description(&self) -> &str { &self.0 } - } - impl fmt::Display for StringError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } - } - - // Unfortunately `String` is located in libcollections, so we construct - // a `Box` manually here. - unsafe { - let alloc = if err.len() == 0 { - 0 as *mut u8 - } else { - let ptr = heap::allocate(err.len(), 1); - if ptr.is_null() { ::oom(); } - ptr as *mut u8 - }; - ptr::copy(err.as_bytes().as_ptr(), alloc, err.len()); - Box::new(StringError(mem::transmute(Slice { - data: alloc, - len: err.len(), - }))) - } - } -} diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index d8d7ad9887a..7a772532091 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -17,7 +17,6 @@ use core::prelude::*; use core::default::Default; -use core::error::Error; use core::fmt; use core::hash; use core::iter::{IntoIterator, FromIterator}; @@ -723,11 +722,6 @@ impl fmt::Display for FromUtf8Error { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf8Error { - fn description(&self) -> &str { "invalid utf-8" } -} - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for FromUtf16Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -735,11 +729,6 @@ impl fmt::Display for FromUtf16Error { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf16Error { - fn description(&self) -> &str { "invalid utf-16" } -} - #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for String { fn from_iter>(iter: I) -> String { diff --git a/src/libcore/error.rs b/src/libcore/error.rs deleted file mode 100644 index 24035b7d9a8..00000000000 --- a/src/libcore/error.rs +++ /dev/null @@ -1,56 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Traits for working with Errors. -//! -//! # The `Error` trait -//! -//! `Error` is a trait representing the basic expectations for error values, -//! i.e. values of type `E` in `Result`. At a minimum, errors must provide -//! a description, but they may optionally provide additional detail (via -//! `Display`) and cause chain information: -//! -//! ``` -//! use std::fmt::Display; -//! -//! trait Error: Display { -//! fn description(&self) -> &str; -//! -//! fn cause(&self) -> Option<&Error> { None } -//! } -//! ``` -//! -//! The `cause` method is generally used when errors cross "abstraction -//! boundaries", i.e. when a one module must report an error that is "caused" -//! by an error from a lower-level module. This setup makes it possible for the -//! high-level module to provide its own errors that do not commit to any -//! particular implementation, but also reveal some of its implementation for -//! debugging via `cause` chains. - -#![stable(feature = "rust1", since = "1.0.0")] - -use prelude::*; -use fmt::{Debug, Display}; - -/// Base functionality for all errors in Rust. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Error: Debug + Display { - /// A short description of the error. - /// - /// The description should not contain newlines or sentence-ending - /// punctuation, to facilitate embedding in larger user-facing - /// strings. - #[stable(feature = "rust1", since = "1.0.0")] - fn description(&self) -> &str; - - /// The lower-level cause of this error, if any. - #[stable(feature = "rust1", since = "1.0.0")] - fn cause(&self) -> Option<&Error> { None } -} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 3a9af50fefb..2189e2c3ad1 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -147,7 +147,6 @@ pub mod slice; pub mod str; pub mod hash; pub mod fmt; -pub mod error; #[doc(primitive = "bool")] mod bool { diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index a4829ed96b3..7daa1a9f420 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -20,7 +20,6 @@ use self::wrapping::{OverflowingOps, WrappingOps}; use char::CharExt; use clone::Clone; use cmp::{PartialEq, Eq, PartialOrd, Ord}; -use error::Error; use fmt; use intrinsics; use iter::Iterator; @@ -2948,16 +2947,9 @@ enum IntErrorKind { Underflow, } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseIntError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseIntError { - fn description(&self) -> &str { +impl ParseIntError { + #[unstable(feature = "core", reason = "available through Error trait")] + pub fn description(&self) -> &str { match self.kind { IntErrorKind::Empty => "cannot parse integer from empty string", IntErrorKind::InvalidDigit => "invalid digit found in string", @@ -2967,6 +2959,13 @@ impl Error for ParseIntError { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseIntError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + /// An error which can be returned when parsing a float. #[derive(Debug, Clone, PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] @@ -2978,19 +2977,19 @@ enum FloatErrorKind { Invalid, } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseFloatError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseFloatError { - fn description(&self) -> &str { +impl ParseFloatError { + #[unstable(feature = "core", reason = "available through Error trait")] + pub fn description(&self) -> &str { match self.kind { FloatErrorKind::Empty => "cannot parse float from empty string", FloatErrorKind::Invalid => "invalid float literal", } } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseFloatError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 934c4515614..4c366d32718 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -22,7 +22,6 @@ use char::CharExt; use clone::Clone; use cmp::{self, Eq}; use default::Default; -use error::Error; use fmt; use iter::ExactSizeIterator; use iter::{Map, Iterator, DoubleEndedIterator}; @@ -192,11 +191,6 @@ impl fmt::Display for ParseBoolError { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseBoolError { - fn description(&self) -> &str { "failed to parse bool" } -} - /* Section: Creating a string */ @@ -241,16 +235,6 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { mem::transmute(v) } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for Utf8Error { - fn description(&self) -> &str { - match *self { - Utf8Error::TooShort => "invalid utf-8: not enough bytes", - Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents", - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libstd/error.rs b/src/libstd/error.rs new file mode 100644 index 00000000000..150ffcdd77a --- /dev/null +++ b/src/libstd/error.rs @@ -0,0 +1,152 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Traits for working with Errors. +//! +//! # The `Error` trait +//! +//! `Error` is a trait representing the basic expectations for error values, +//! i.e. values of type `E` in `Result`. At a minimum, errors must provide +//! a description, but they may optionally provide additional detail (via +//! `Display`) and cause chain information: +//! +//! ``` +//! use std::fmt::Display; +//! +//! trait Error: Display { +//! fn description(&self) -> &str; +//! +//! fn cause(&self) -> Option<&Error> { None } +//! } +//! ``` +//! +//! The `cause` method is generally used when errors cross "abstraction +//! boundaries", i.e. when a one module must report an error that is "caused" +//! by an error from a lower-level module. This setup makes it possible for the +//! high-level module to provide its own errors that do not commit to any +//! particular implementation, but also reveal some of its implementation for +//! debugging via `cause` chains. + +#![stable(feature = "rust1", since = "1.0.0")] + +// A note about crates and the facade: +// +// Originally, the `Error` trait was defined in libcore, and the impls +// were scattered about. However, coherence objected to this +// arrangement, because to create the blanket impls for `Box` required +// knowing that `&str: !Error`, and we have no means to deal with that +// sort of conflict just now. Therefore, for the time being, we have +// moved the `Error` trait into libstd. As we evolve a sol'n to the +// coherence challenge (e.g., specialization, neg impls, etc) we can +// reconsider what crate these items belong in. + +use boxed::Box; +use convert::From; +use fmt::{self, Debug, Display}; +use marker::Send; +use num; +use option::Option; +use option::Option::None; +use str; +use string::{self, String}; + +/// Base functionality for all errors in Rust. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Error: Debug + Display { + /// A short description of the error. + /// + /// The description should not contain newlines or sentence-ending + /// punctuation, to facilitate embedding in larger user-facing + /// strings. + #[stable(feature = "rust1", since = "1.0.0")] + fn description(&self) -> &str; + + /// The lower-level cause of this error, if any. + #[stable(feature = "rust1", since = "1.0.0")] + fn cause(&self) -> Option<&Error> { None } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + Send + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b> From<&'b str> for Box { + fn from(err: &'b str) -> Box { + #[derive(Debug)] + struct StringError(String); + + impl Error for StringError { + fn description(&self) -> &str { &self.0 } + } + + impl Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } + } + + Box::new(StringError(String::from_str(err))) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for str::ParseBoolError { + fn description(&self) -> &str { "failed to parse bool" } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for str::Utf8Error { + fn description(&self) -> &str { + match *self { + str::Utf8Error::TooShort => "invalid utf-8: not enough bytes", + str::Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents", + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for num::ParseIntError { + fn description(&self) -> &str { + self.description() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for num::ParseFloatError { + fn description(&self) -> &str { + self.description() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for string::FromUtf8Error { + fn description(&self) -> &str { + "invalid utf-8" + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for string::FromUtf16Error { + fn description(&self) -> &str { + "invalid utf-16" + } +} + diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 41ac3d60df5..807f0c5753e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -183,7 +183,7 @@ pub use core::raw; pub use core::simd; pub use core::result; pub use core::option; -pub use core::error; +pub mod error; #[cfg(not(test))] pub use alloc::boxed; pub use alloc::rc; -- cgit 1.4.1-3-g733a5 From e98dce3e00a7b6bfd264418ef993bbf9cdb1f0b6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 1 Apr 2015 11:28:34 -0700 Subject: std: Changing the meaning of the count to splitn This commit is an implementation of [RFC 979][rfc] which changes the meaning of the count parameter to the `splitn` function on strings and slices. The parameter now means the number of items that are returned from the iterator, not the number of splits that are made. [rfc]: https://github.com/rust-lang/rfcs/pull/979 Closes #23911 [breaking-change] --- src/compiletest/header.rs | 2 +- src/libcollections/slice.rs | 24 ++++++++++++++++++------ src/libcollections/str.rs | 28 +++++++++++++++++----------- src/libcollectionstest/slice.rs | 25 +++++++++++++------------ src/libcollectionstest/str.rs | 14 +++++++------- src/libcore/slice.rs | 14 ++++++++------ src/libcore/str/mod.rs | 20 +++++++++----------- src/libcoretest/str.rs | 8 ++++---- src/librustc/session/config.rs | 6 +++--- src/librustc_driver/pretty.rs | 2 +- src/librustdoc/lib.rs | 2 +- src/libstd/net/addr.rs | 2 +- src/libstd/path.rs | 2 +- src/libstd/sys/unix/os.rs | 2 +- 14 files changed, 85 insertions(+), 66 deletions(-) (limited to 'src/libstd') diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 9612c0e06a3..f5505b6e83a 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -311,7 +311,7 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> { parse_name_value_directive(line, "exec-env").map(|nv| { // nv is either FOO or FOO=BAR let mut strs: Vec = nv - .splitn(1, '=') + .splitn(2, '=') .map(|s| s.to_string()) .collect(); diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 4599aff000d..d35173cbebf 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -328,9 +328,12 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to splitting at most `n` times. The matched element is + /// `pred`, limited to returning at most `n` items. The matched element is /// not contained in the subslices. /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// /// # Examples /// /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`, @@ -338,7 +341,7 @@ impl [T] { /// /// ``` /// let v = [10, 40, 30, 20, 60, 50]; - /// for group in v.splitn(1, |num| *num % 3 == 0) { + /// for group in v.splitn(2, |num| *num % 3 == 0) { /// println!("{:?}", group); /// } /// ``` @@ -349,10 +352,13 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred` limited to splitting at most `n` times. This starts at the end of + /// `pred` limited to returning at most `n` items. This starts at the end of /// the slice and works backwards. The matched element is not contained in /// the subslices. /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// /// # Examples /// /// Print the slice split once, starting from the end, by numbers divisible @@ -360,7 +366,7 @@ impl [T] { /// /// ``` /// let v = [10, 40, 30, 20, 60, 50]; - /// for group in v.rsplitn(1, |num| *num % 3 == 0) { + /// for group in v.rsplitn(2, |num| *num % 3 == 0) { /// println!("{:?}", group); /// } /// ``` @@ -626,8 +632,11 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to splitting at most `n` times. The matched element is + /// `pred`, limited to returning at most `n` items. The matched element is /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut @@ -636,9 +645,12 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred` limited to splitting at most `n` times. This starts at the end of + /// `pred` limited to returning at most `n` items. This starts at the end of /// the slice and works backwards. The matched element is not contained in /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index f8f2909291f..c22b6fb9286 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -610,24 +610,27 @@ impl str { core_str::StrExt::split(&self[..], pat) } - /// An iterator over substrings of `self`, separated by characters matched by a pattern, - /// restricted to splitting at most `count` times. + /// An iterator over substrings of `self`, separated by characters matched + /// by a pattern, returning most `count` items. /// /// The pattern can be a simple `&str`, or a closure that determines /// the split. /// + /// The last element returned, if any, will contain the remainder of the + /// string. + /// /// # Examples /// /// Simple `&str` patterns: /// /// ``` /// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect(); - /// assert_eq!(v, ["Mary", "had", "a little lambda"]); + /// assert_eq!(v, ["Mary", "had a little lambda"]); /// /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(2, 'X').collect(); - /// assert_eq!(v, ["lion", "", "tigerXleopard"]); + /// assert_eq!(v, ["lion", "XtigerXleopard"]); /// - /// let v: Vec<&str> = "abcXdef".splitn(0, 'X').collect(); + /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); /// assert_eq!(v, ["abcXdef"]); /// /// let v: Vec<&str> = "".splitn(1, 'X').collect(); @@ -637,7 +640,7 @@ impl str { /// More complex patterns with a lambda: /// /// ``` - /// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_numeric()).collect(); + /// let v: Vec<&str> = "abc1def2ghi".splitn(2, |c: char| c.is_numeric()).collect(); /// assert_eq!(v, ["abc", "def2ghi"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -705,25 +708,28 @@ impl str { } /// An iterator over substrings of `self`, separated by a pattern, - /// starting from the end of the string, restricted to splitting - /// at most `count` times. + /// starting from the end of the string, restricted to returning + /// at most `count` items. + /// + /// The last element returned, if any, will contain the remainder of the + /// string. /// /// # Examples /// /// Simple patterns: /// /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect(); + /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect(); /// assert_eq!(v, ["lamb", "little", "Mary had a"]); /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(1, "::").collect(); + /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect(); /// assert_eq!(v, ["leopard", "lion::tiger"]); /// ``` /// /// More complex patterns with a lambda: /// /// ``` - /// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_numeric()).collect(); + /// let v: Vec<&str> = "abc1def2ghi".rsplitn(2, |c: char| c.is_numeric()).collect(); /// assert_eq!(v, ["ghi", "abc1def"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 041d9fba57c..9dc12aa5bd9 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -867,18 +867,18 @@ fn test_splitnator() { let xs = &[1,2,3,4,5]; let splits: &[&[_]] = &[&[1,2,3,4,5]]; - assert_eq!(xs.splitn(0, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&[_]] = &[&[1], &[3,4,5]]; - assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&[_]] = &[&[], &[], &[], &[4,5]]; - assert_eq!(xs.splitn(3, |_| true).collect::>(), + assert_eq!(xs.splitn(4, |_| true).collect::>(), splits); let xs: &[i32] = &[]; let splits: &[&[i32]] = &[&[]]; - assert_eq!(xs.splitn(1, |x| *x == 5).collect::>(), splits); + assert_eq!(xs.splitn(2, |x| *x == 5).collect::>(), splits); } #[test] @@ -886,18 +886,18 @@ fn test_splitnator_mut() { let xs = &mut [1,2,3,4,5]; let splits: &[&mut[_]] = &[&mut [1,2,3,4,5]]; - assert_eq!(xs.splitn_mut(0, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&mut[_]] = &[&mut [1], &mut [3,4,5]]; - assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&mut[_]] = &[&mut [], &mut [], &mut [], &mut [4,5]]; - assert_eq!(xs.splitn_mut(3, |_| true).collect::>(), + assert_eq!(xs.splitn_mut(4, |_| true).collect::>(), splits); let xs: &mut [i32] = &mut []; let splits: &[&mut[i32]] = &[&mut []]; - assert_eq!(xs.splitn_mut(1, |x| *x == 5).collect::>(), + assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::>(), splits); } @@ -928,18 +928,19 @@ fn test_rsplitnator() { let xs = &[1,2,3,4,5]; let splits: &[&[_]] = &[&[1,2,3,4,5]]; - assert_eq!(xs.rsplitn(0, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&[_]] = &[&[5], &[1,2,3]]; - assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&[_]] = &[&[], &[], &[], &[1,2]]; - assert_eq!(xs.rsplitn(3, |_| true).collect::>(), + assert_eq!(xs.rsplitn(4, |_| true).collect::>(), splits); let xs: &[i32] = &[]; let splits: &[&[i32]] = &[&[]]; - assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::>(), splits); + assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::>(), splits); + assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none()); } #[test] diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index ed9ee0206b7..495a961fa36 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -885,17 +885,17 @@ fn test_char_indices_revator() { fn test_splitn_char_iterator() { let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - let split: Vec<&str> = data.splitn(3, ' ').collect(); + let split: Vec<&str> = data.splitn(4, ' ').collect(); assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); - let split: Vec<&str> = data.splitn(3, |c: char| c == ' ').collect(); + let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect(); assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); // Unicode - let split: Vec<&str> = data.splitn(3, 'ä').collect(); + let split: Vec<&str> = data.splitn(4, 'ä').collect(); assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); - let split: Vec<&str> = data.splitn(3, |c: char| c == 'ä').collect(); + let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect(); assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); } @@ -928,13 +928,13 @@ fn test_rsplit() { fn test_rsplitn() { let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - let split: Vec<&str> = data.rsplitn(1, ' ').collect(); + let split: Vec<&str> = data.rsplitn(2, ' ').collect(); assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]); - let split: Vec<&str> = data.rsplitn(1, "lämb").collect(); + let split: Vec<&str> = data.rsplitn(2, "lämb").collect(); assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]); - let split: Vec<&str> = data.rsplitn(1, |c: char| c == 'ä').collect(); + let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect(); assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]); } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index d8856130fab..70e60adf64c 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1126,18 +1126,20 @@ impl> Iterator for GenericSplitN { #[inline] fn next(&mut self) -> Option { - if self.count == 0 { - self.iter.finish() - } else { - self.count -= 1; - if self.invert { self.iter.next_back() } else { self.iter.next() } + match self.count { + 0 => None, + 1 => { self.count -= 1; self.iter.finish() } + _ => { + self.count -= 1; + if self.invert {self.iter.next_back()} else {self.iter.next()} + } } } #[inline] fn size_hint(&self) -> (usize, Option) { let (lower, upper_opt) = self.iter.size_hint(); - (lower, upper_opt.map(|upper| cmp::min(self.count + 1, upper))) + (lower, upper_opt.map(|upper| cmp::min(self.count, upper))) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 934c4515614..23d6a9c1193 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -505,7 +505,7 @@ struct CharSplits<'a, P: Pattern<'a>> { /// splitting at most `count` times. struct CharSplitsN<'a, P: Pattern<'a>> { iter: CharSplits<'a, P>, - /// The number of splits remaining + /// The number of items remaining count: usize, } @@ -612,11 +612,10 @@ impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> { #[inline] fn next(&mut self) -> Option<&'a str> { - if self.count != 0 { - self.count -= 1; - self.iter.next() - } else { - self.iter.get_end() + match self.count { + 0 => None, + 1 => { self.count = 0; self.iter.get_end() } + _ => { self.count -= 1; self.iter.next() } } } } @@ -666,11 +665,10 @@ impl<'a, P: Pattern<'a>> Iterator for RCharSplitsN<'a, P> #[inline] fn next(&mut self) -> Option<&'a str> { - if self.count != 0 { - self.count -= 1; - self.iter.next() - } else { - self.iter.get_remainder() + match self.count { + 0 => None, + 1 => { self.count -= 1; self.iter.get_remainder() } + _ => { self.count -= 1; self.iter.next() } } } } diff --git a/src/libcoretest/str.rs b/src/libcoretest/str.rs index c935b554574..5fce527d979 100644 --- a/src/libcoretest/str.rs +++ b/src/libcoretest/str.rs @@ -65,20 +65,20 @@ fn test_strslice_contains() { fn test_rsplitn_char_iterator() { let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - let mut split: Vec<&str> = data.rsplitn(3, ' ').collect(); + let mut split: Vec<&str> = data.rsplitn(4, ' ').collect(); split.reverse(); assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); - let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == ' ').collect(); + let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect(); split.reverse(); assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); // Unicode - let mut split: Vec<&str> = data.rsplitn(3, 'ä').collect(); + let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect(); split.reverse(); assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); - let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == 'ä').collect(); + let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect(); split.reverse(); assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index c67819ab7e3..5a598921195 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -304,7 +304,7 @@ macro_rules! options { { let mut op = $defaultfn(); for option in matches.opt_strs($prefix) { - let mut iter = option.splitn(1, '='); + let mut iter = option.splitn(2, '='); let key = iter.next().unwrap(); let value = iter.next(); let option_to_lookup = key.replace("-", "_"); @@ -958,7 +958,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } let libs = matches.opt_strs("l").into_iter().map(|s| { - let mut parts = s.splitn(1, '='); + let mut parts = s.splitn(2, '='); let kind = parts.next().unwrap(); let (name, kind) = match (parts.next(), kind) { (None, name) | @@ -1010,7 +1010,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let mut externs = HashMap::new(); for arg in &matches.opt_strs("extern") { - let mut parts = arg.splitn(1, '='); + let mut parts = arg.splitn(2, '='); let name = match parts.next() { Some(s) => s, None => early_error("--extern value must not be empty"), diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index fe55ca3b73b..605b486841f 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -74,7 +74,7 @@ pub enum PpMode { pub fn parse_pretty(sess: &Session, name: &str, extended: bool) -> (PpMode, Option) { - let mut split = name.splitn(1, '='); + let mut split = name.splitn(2, '='); let first = split.next().unwrap(); let opt_second = split.next(); let first = match (first, extended) { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 1ff3411f8fc..d1dcfc26008 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -333,7 +333,7 @@ fn acquire_input(input: &str, fn parse_externs(matches: &getopts::Matches) -> Result { let mut externs = HashMap::new(); for arg in &matches.opt_strs("extern") { - let mut parts = arg.splitn(1, '='); + let mut parts = arg.splitn(2, '='); let name = match parts.next() { Some(s) => s, None => { diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index c45230e91ba..886f252fb19 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -441,7 +441,7 @@ impl ToSocketAddrs for str { } // split the string by ':' and convert the second part to u16 - let mut parts_iter = self.rsplitn(1, ':'); + let mut parts_iter = self.rsplitn(2, ':'); let port_str = try_opt!(parts_iter.next(), "invalid socket address"); let host = try_opt!(parts_iter.next(), "invalid socket address"); let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 9006ed33654..ee4b572335b 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -406,7 +406,7 @@ fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { // contents of the encoding and (2) new &OsStr values are produced // only from ASCII-bounded slices of existing &OsStr values. - let mut iter = os_str_as_u8_slice(file).rsplitn(1, |b| *b == b'.'); + let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); let after = iter.next(); let before = iter.next(); if before == Some(b"") { diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 7b13e951b9b..d2220bdec32 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -409,7 +409,7 @@ pub fn env() -> Env { }; fn parse(input: &[u8]) -> (OsString, OsString) { - let mut it = input.splitn(1, |b| *b == b'='); + let mut it = input.splitn(2, |b| *b == b'='); let key = it.next().unwrap().to_vec(); let default: &[u8] = &[]; let val = it.next().unwrap_or(default).to_vec(); -- cgit 1.4.1-3-g733a5 From 371277fb0d210152eb8c79e30bd7f7749c5af63c Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 1 Apr 2015 12:20:57 -0700 Subject: Stabilize basic timeout functionality This commit renames and stabilizes: * `Condvar::wait_timeout_ms` (renamed from `wait_timeout`) * `thread::park_timeout_ms` (renamed from `park_timeout`) * `thread::sleep_ms` (renamed from `sleep`) In each case, the timeout is taken as a `u32` number of milliseconds, rather than a `Duration`. These functions are likely to be deprecated once a stable form of `Duration` is available, but there is little cost to having these named variants around, and it's crucial functionality for 1.0. [breaking-change] --- src/libstd/sync/condvar.rs | 50 ++++++++++++++++++++++++++++------------------ src/libstd/thread/mod.rs | 32 ++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 28 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 69c5267ab69..a7d8b287a64 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -140,33 +140,43 @@ impl Condvar { /// Wait on this condition variable for a notification, timing out after a /// specified duration. /// - /// The semantics of this function are equivalent to `wait()` except that - /// the thread will be blocked for roughly no longer than `dur`. This method - /// should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum amount - /// of time waited to be precisely `dur`. + /// The semantics of this function are equivalent to `wait()` + /// except that the thread will be blocked for roughly no longer + /// than `ms` milliseconds. This method should not be used for + /// precise timing due to anomalies such as preemption or platform + /// differences that may not cause the maximum amount of time + /// waited to be precisely `ms`. /// - /// If the wait timed out, then `false` will be returned. Otherwise if a - /// notification was received then `true` will be returned. + /// The returned boolean is `false` only if the timeout is known + /// to have elapsed. /// /// Like `wait`, the lock specified will be re-acquired when this function /// returns, regardless of whether the timeout elapsed or not. - #[unstable(feature = "std_misc")] - pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration) - -> LockResult<(MutexGuard<'a, T>, bool)> { + #[stable(feature = "rust1", since = "1.0.0")] + pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32) + -> LockResult<(MutexGuard<'a, T>, bool)> { unsafe { let me: &'static Condvar = &*(self as *const _); - me.inner.wait_timeout(guard, dur) + me.inner.wait_timeout_ms(guard, ms) } } + /// Deprecated: use `wait_timeout_ms` instead. + #[unstable(feature = "std_misc")] + #[deprecated(since = "1.0.0", reason = "use wait_timeout_ms instead")] + pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration) + -> LockResult<(MutexGuard<'a, T>, bool)> { + self.wait_timeout_ms(guard, dur.num_milliseconds() as u32) + } + /// Wait on this condition variable for a notification, timing out after a /// specified duration. /// /// The semantics of this function are equivalent to `wait_timeout` except /// that the implementation will repeatedly wait while the duration has not /// passed and the provided function returns `false`. - #[unstable(feature = "std_misc")] + #[unstable(feature = "wait_timeout_with", + reason = "unsure if this API is broadly needed or what form it should take")] pub fn wait_timeout_with<'a, T, F>(&self, guard: MutexGuard<'a, T>, dur: Duration, @@ -235,12 +245,12 @@ impl StaticCondvar { /// See `Condvar::wait_timeout`. #[unstable(feature = "std_misc", reason = "may be merged with Condvar in the future")] - pub fn wait_timeout<'a, T>(&'static self, guard: MutexGuard<'a, T>, dur: Duration) - -> LockResult<(MutexGuard<'a, T>, bool)> { + pub fn wait_timeout_ms<'a, T>(&'static self, guard: MutexGuard<'a, T>, ms: u32) + -> LockResult<(MutexGuard<'a, T>, bool)> { let (poisoned, success) = unsafe { let lock = mutex::guard_lock(&guard); self.verify(lock); - let success = self.inner.wait_timeout(lock, dur); + let success = self.inner.wait_timeout(lock, Duration::milliseconds(ms as i64)); (mutex::guard_poison(&guard).get(), success) }; if poisoned { @@ -275,7 +285,8 @@ impl StaticCondvar { let now = SteadyTime::now(); let consumed = &now - &start; let guard = guard_result.unwrap_or_else(|e| e.into_inner()); - let (new_guard_result, no_timeout) = match self.wait_timeout(guard, dur - consumed) { + let res = self.wait_timeout_ms(guard, (dur - consumed).num_milliseconds() as u32); + let (new_guard_result, no_timeout) = match res { Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout), Err(err) => { let (new_guard, no_timeout) = err.into_inner(); @@ -350,6 +361,7 @@ mod tests { use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use thread; use time::Duration; + use u32; #[test] fn smoke() { @@ -418,19 +430,19 @@ mod tests { } #[test] - fn wait_timeout() { + fn wait_timeout_ms() { static C: StaticCondvar = CONDVAR_INIT; static M: StaticMutex = MUTEX_INIT; let g = M.lock().unwrap(); - let (g, _no_timeout) = C.wait_timeout(g, Duration::nanoseconds(1000)).unwrap(); + let (g, _no_timeout) = C.wait_timeout_ms(g, 1).unwrap(); // spurious wakeups mean this isn't necessarily true // assert!(!no_timeout); let _t = thread::spawn(move || { let _g = M.lock().unwrap(); C.notify_one(); }); - let (g, no_timeout) = C.wait_timeout(g, Duration::days(1)).unwrap(); + let (g, no_timeout) = C.wait_timeout_ms(g, u32::MAX).unwrap(); assert!(no_timeout); drop(g); unsafe { C.destroy(); M.destroy(); } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 1202b353317..c06d89e498d 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -465,9 +465,16 @@ pub fn catch_panic(f: F) -> Result /// specifics or platform-dependent functionality. Note that on unix platforms /// this function will not return early due to a signal being received or a /// spurious wakeup. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn sleep_ms(ms: u32) { + imp::sleep(Duration::milliseconds(ms as i64)) +} + +/// Deprecated: use `sleep_ms` instead. #[unstable(feature = "thread_sleep", reason = "recently added, needs an RFC, and `Duration` itself is \ unstable")] +#[deprecated(since = "1.0.0", reason = "use sleep_ms instead")] pub fn sleep(dur: Duration) { imp::sleep(dur) } @@ -501,17 +508,24 @@ pub fn park() { /// amount of time waited to be precisely *duration* long. /// /// See the module doc for more detail. -#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")] -pub fn park_timeout(duration: Duration) { +#[stable(feature = "rust1", since = "1.0.0")] +pub fn park_timeout_ms(ms: u32) { let thread = current(); let mut guard = thread.inner.lock.lock().unwrap(); if !*guard { - let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap(); + let (g, _) = thread.inner.cvar.wait_timeout_ms(guard, ms).unwrap(); guard = g; } *guard = false; } +/// Deprecated: use `park_timeout_ms` +#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")] +#[deprecated(since = "1.0.0", reason = "use park_timeout_ms instead")] +pub fn park_timeout(duration: Duration) { + park_timeout_ms(duration.num_milliseconds() as u32) +} + //////////////////////////////////////////////////////////////////////////////// // Thread //////////////////////////////////////////////////////////////////////////////// @@ -716,6 +730,7 @@ mod test { use thread; use thunk::Thunk; use time::Duration; + use u32; // !!! These tests are dangerous. If something is buggy, they will hang, !!! // !!! instead of exiting cleanly. This might wedge the buildbots. !!! @@ -936,14 +951,14 @@ mod test { fn test_park_timeout_unpark_before() { for _ in 0..10 { thread::current().unpark(); - thread::park_timeout(Duration::seconds(10_000_000)); + thread::park_timeout_ms(u32::MAX); } } #[test] fn test_park_timeout_unpark_not_called() { for _ in 0..10 { - thread::park_timeout(Duration::milliseconds(10)); + thread::park_timeout_ms(10); } } @@ -959,14 +974,13 @@ mod test { th.unpark(); }); - thread::park_timeout(Duration::seconds(10_000_000)); + thread::park_timeout_ms(u32::MAX); } } #[test] - fn sleep_smoke() { - thread::sleep(Duration::milliseconds(2)); - thread::sleep(Duration::milliseconds(-2)); + fn sleep_ms_smoke() { + thread::sleep_ms(2); } // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due -- cgit 1.4.1-3-g733a5