From 769d49a8b7d00c2e3b85a139206516764ce23a84 Mon Sep 17 00:00:00 2001 From: Ian Connolly Date: Thu, 13 Nov 2014 19:47:59 +0000 Subject: [PATCH 01/23] Don't use rust keyword for fake code --- src/doc/guide-pointers.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/doc/guide-pointers.md b/src/doc/guide-pointers.md index 87eb91d3ec7..2c6388a6180 100644 --- a/src/doc/guide-pointers.md +++ b/src/doc/guide-pointers.md @@ -133,11 +133,11 @@ pass-by-reference. Basically, languages can make two choices (this is made up syntax, it's not Rust): ```{notrust,ignore} -fn foo(x) { +func foo(x) { x = 5 } -fn main() { +func main() { i = 1 foo(i) // what is the value of i here? @@ -153,11 +153,11 @@ So what do pointers have to do with this? Well, since pointers point to a location in memory... ```{notrust,ignore} -fn foo(&int x) { +func foo(&int x) { *x = 5 } -fn main() { +func main() { i = 1 foo(&i) // what is the value of i here? @@ -192,13 +192,13 @@ When you combine pointers and functions, it's easy to accidentally invalidate the memory the pointer is pointing to. For example: ```{notrust,ignore} -fn make_pointer(): &int { +func make_pointer(): &int { x = 5; return &x; } -fn main() { +func main() { &int i = make_pointer(); *i = 5; // uh oh! } @@ -214,11 +214,11 @@ issue. Two pointers are said to alias when they point at the same location in memory. Like this: ```{notrust,ignore} -fn mutate(&int i, int j) { +func mutate(&int i, int j) { *i = j; } -fn main() { +func main() { x = 5; y = &x; z = &x; //y and z are aliased From fb954a1578f84ad9a8a42548eb3ec77069d13847 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Thu, 13 Nov 2014 17:14:46 -0500 Subject: [PATCH 02/23] src/etc/snapshot: support triples lacking a vendor --- src/etc/snapshot.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/etc/snapshot.py b/src/etc/snapshot.py index e0610bfbdfe..cb99da8092d 100644 --- a/src/etc/snapshot.py +++ b/src/etc/snapshot.py @@ -75,7 +75,11 @@ def full_snapshot_name(date, rev, platform, hsh): def get_kernel(triple): - os_name = triple.split('-')[2] + t = triple.split('-') + if len(t) == 2: + os_name = t[1] + else: + os_name = t[2] if os_name == "windows": return "winnt" if os_name == "darwin": From 643edeade99bd130b9079ffcc9dfc913abcb5698 Mon Sep 17 00:00:00 2001 From: Joseph Crail Date: Thu, 13 Nov 2014 22:17:22 -0500 Subject: [PATCH 03/23] Remove BTreeSet from all examples. --- src/libcollections/tree/set.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcollections/tree/set.rs b/src/libcollections/tree/set.rs index 45904259c66..1005732a1e2 100644 --- a/src/libcollections/tree/set.rs +++ b/src/libcollections/tree/set.rs @@ -504,9 +504,9 @@ impl TreeSet { /// # Example /// /// ``` - /// use std::collections::BTreeSet; + /// use std::collections::TreeSet; /// - /// let mut set = BTreeSet::new(); + /// let mut set = TreeSet::new(); /// /// assert_eq!(set.insert(2i), true); /// assert_eq!(set.insert(2i), false); @@ -522,9 +522,9 @@ impl TreeSet { /// # Example /// /// ``` - /// use std::collections::BTreeSet; + /// use std::collections::TreeSet; /// - /// let mut set = BTreeSet::new(); + /// let mut set = TreeSet::new(); /// /// set.insert(2i); /// assert_eq!(set.remove(&2), true); From 93c4942690753e982cbb4bf6667940da71c5d286 Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Thu, 13 Nov 2014 18:04:28 -0800 Subject: [PATCH 04/23] Rewrite std::sync::TaskPool to be load balancing and panic-resistant The previous implementation was very likely to cause panics during unwinding through this process: - child panics, drops its receiver - taskpool comes back around and sends another job over to that child - the child receiver has hung up, so the taskpool panics on send - during unwinding, the taskpool attempts to send a quit message to the child, causing a panic during unwinding - panic during unwinding causes a process abort This meant that TaskPool upgraded any child panic to a full process abort. This came up in Iron when it caused crashes in long-running servers. This implementation uses a single channel to communicate between spawned tasks and the TaskPool, which significantly reduces the complexity of the implementation and cuts down on allocation. The TaskPool uses the channel as a single-producer-multiple-consumer queue. Additionally, through the use of send_opt and recv_opt instead of send and recv, this TaskPool is robust on the face of child panics, both before, during, and after the TaskPool itself is dropped. Due to the TaskPool no longer using an `init_fn_factory`, this is a [breaking-change] otherwise, the API has not changed. If you used `init_fn_factory` in your code, and this change breaks for you, you can instead use an `AtomicUint` counter and a channel to move information into child tasks. --- src/libstd/sync/task_pool.rs | 230 +++++++++++++++++++++++++---------- 1 file changed, 167 insertions(+), 63 deletions(-) diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs index d4a60fb5844..2682582d708 100644 --- a/src/libstd/sync/task_pool.rs +++ b/src/libstd/sync/task_pool.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -12,91 +12,195 @@ use core::prelude::*; -use task; use task::spawn; -use vec::Vec; -use comm::{channel, Sender}; +use comm::{channel, Sender, Receiver}; +use sync::{Arc, Mutex}; -enum Msg { - Execute(proc(&T):Send), - Quit +struct Sentinel<'a> { + jobs: &'a Arc>>, + active: bool } -/// A task pool used to execute functions in parallel. -pub struct TaskPool { - channels: Vec>>, - next_index: uint, +impl<'a> Sentinel<'a> { + fn new(jobs: &Arc>>) -> Sentinel { + Sentinel { + jobs: jobs, + active: true + } + } + + // Cancel and destroy this sentinel. + fn cancel(mut self) { + self.active = false; + } } #[unsafe_destructor] -impl Drop for TaskPool { +impl<'a> Drop for Sentinel<'a> { fn drop(&mut self) { - for channel in self.channels.iter_mut() { - channel.send(Quit); + if self.active { + spawn_in_pool(self.jobs.clone()) } } } -impl TaskPool { - /// Spawns a new task pool with `n_tasks` tasks. The provided - /// `init_fn_factory` returns a function which, given the index of the - /// task, should return local data to be kept around in that task. +/// A task pool used to execute functions in parallel. +/// +/// Spawns `n` worker tasks and replenishes the pool if any worker tasks +/// panic. +/// +/// # Example +/// +/// ```rust +/// # use sync::TaskPool; +/// # use iter::AdditiveIterator; +/// +/// let pool = TaskPool::new(4u); +/// +/// let (tx, rx) = channel(); +/// for _ in range(0, 8u) { +/// let tx = tx.clone(); +/// pool.execute(proc() { +/// tx.send(1u); +/// }); +/// } +/// +/// assert_eq!(rx.iter().take(8u).sum(), 8u); +/// ``` +pub struct TaskPool { + // How the taskpool communicates with subtasks. + // + // This is the only such Sender, so when it is dropped all subtasks will + // quit. + jobs: Sender +} + +impl TaskPool { + /// Spawns a new task pool with `tasks` tasks. /// /// # Panics /// - /// This function will panic if `n_tasks` is less than 1. - pub fn new(n_tasks: uint, - init_fn_factory: || -> proc(uint):Send -> T) - -> TaskPool { - assert!(n_tasks >= 1); + /// This function will panic if `tasks` is 0. + pub fn new(tasks: uint) -> TaskPool { + assert!(tasks >= 1); - let channels = Vec::from_fn(n_tasks, |i| { - let (tx, rx) = channel::>(); - let init_fn = init_fn_factory(); + let (tx, rx) = channel::(); + let rx = Arc::new(Mutex::new(rx)); - let task_body = proc() { - let local_data = init_fn(i); - loop { - match rx.recv() { - Execute(f) => f(&local_data), - Quit => break - } - } + // Taskpool tasks. + for _ in range(0, tasks) { + spawn_in_pool(rx.clone()); + } + + TaskPool { jobs: tx } + } + + /// Executes the function `job` on a task in the pool. + pub fn execute(&self, job: proc():Send) { + self.jobs.send(job); + } +} + +fn spawn_in_pool(jobs: Arc>>) { + spawn(proc() { + // Will spawn a new task on panic unless it is cancelled. + let sentinel = Sentinel::new(&jobs); + + loop { + let message = { + // Only lock jobs for the time it takes + // to get a job, not run it. + let lock = jobs.lock(); + lock.recv_opt() }; - // Run on this scheduler. - task::spawn(task_body); + match message { + Ok(job) => job(), - tx - }); + // The Taskpool was dropped. + Err(..) => break + } + } - return TaskPool { - channels: channels, - next_index: 0, - }; + sentinel.cancel(); + }) +} + +#[cfg(test)] +mod test { + use core::prelude::*; + use super::*; + use comm::channel; + use iter::range; + + const TEST_TASKS: uint = 4u; + + #[test] + fn test_works() { + use iter::AdditiveIterator; + + let pool = TaskPool::new(TEST_TASKS); + + let (tx, rx) = channel(); + for _ in range(0, TEST_TASKS) { + let tx = tx.clone(); + pool.execute(proc() { + tx.send(1u); + }); + } + + assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS); } - /// Executes the function `f` on a task in the pool. The function - /// receives a reference to the local data returned by the `init_fn`. - pub fn execute(&mut self, f: proc(&T):Send) { - self.channels[self.next_index].send(Execute(f)); - self.next_index += 1; - if self.next_index == self.channels.len() { self.next_index = 0; } + #[test] + #[should_fail] + fn test_zero_tasks_panic() { + TaskPool::new(0); + } + + #[test] + fn test_recovery_from_subtask_panic() { + use iter::AdditiveIterator; + + let pool = TaskPool::new(TEST_TASKS); + + // Panic all the existing tasks. + for _ in range(0, TEST_TASKS) { + pool.execute(proc() { panic!() }); + } + + // Ensure new tasks were spawned to compensate. + let (tx, rx) = channel(); + for _ in range(0, TEST_TASKS) { + let tx = tx.clone(); + pool.execute(proc() { + tx.send(1u); + }); + } + + assert_eq!(rx.iter().take(TEST_TASKS).sum(), TEST_TASKS); + } + + #[test] + fn test_should_not_panic_on_drop_if_subtasks_panic_after_drop() { + use sync::{Arc, Barrier}; + + let pool = TaskPool::new(TEST_TASKS); + let waiter = Arc::new(Barrier::new(TEST_TASKS + 1)); + + // Panic all the existing tasks in a bit. + for _ in range(0, TEST_TASKS) { + let waiter = waiter.clone(); + pool.execute(proc() { + waiter.wait(); + panic!(); + }); + } + + drop(pool); + + // Kick off the failure. + waiter.wait(); } } -#[test] -fn test_task_pool() { - let f: || -> proc(uint):Send -> uint = || { proc(i) i }; - let mut pool = TaskPool::new(4, f); - for _ in range(0u, 8) { - pool.execute(proc(i) println!("Hello from thread {}!", *i)); - } -} - -#[test] -#[should_fail] -fn test_zero_tasks_panic() { - let f: || -> proc(uint):Send -> uint = || { proc(i) i }; - TaskPool::new(0, f); -} From 0053fbb891316aa80f9dd25d911d46359b4952c8 Mon Sep 17 00:00:00 2001 From: Tom Jakubowski Date: Fri, 14 Nov 2014 00:38:55 -0800 Subject: [PATCH 05/23] serialize: Add ToJson impl for str --- src/libserialize/json.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 524638155ac..3018d7d8523 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2315,6 +2315,10 @@ impl ToJson for bool { fn to_json(&self) -> Json { Boolean(*self) } } +impl ToJson for str { + fn to_json(&self) -> Json { String(self.into_string()) } +} + impl ToJson for string::String { fn to_json(&self) -> Json { String((*self).clone()) } } @@ -3714,7 +3718,8 @@ mod tests { assert_eq!(f64::NAN.to_json(), Null); assert_eq!(true.to_json(), Boolean(true)); assert_eq!(false.to_json(), Boolean(false)); - assert_eq!("abc".to_string().to_json(), String("abc".to_string())); + assert_eq!("abc".to_json(), String("abc".into_string())); + assert_eq!("abc".into_string().to_json(), String("abc".into_string())); assert_eq!((1u, 2u).to_json(), list2); assert_eq!((1u, 2u, 3u).to_json(), list3); assert_eq!([1u, 2].to_json(), list2); From 94169353eca74c3683b06cea2609a4350ed36c45 Mon Sep 17 00:00:00 2001 From: Barosl Lee Date: Fri, 14 Nov 2014 17:14:44 +0900 Subject: [PATCH 06/23] Improve examples for syntax::ext::deriving::encodable The examples in the documentation for syntax::ext::deriving::encodable are outdated, and do not work. To fix this, the following changes are applied: - emit_field() -> emit_struct_field() - read_field() -> read_struct_field() - Use Result to report errors - Add the mut keyword to Encoder/Decoder - Prefer Encodable::encode() to emit_uint --- src/libsyntax/ext/deriving/encodable.rs | 71 ++++++++++++++----------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 103253560df..69eb260b8c4 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -22,19 +22,23 @@ //! would generate two implementations like: //! //! ```ignore -//! impl Encodable for Node { -//! fn encode(&self, s: &S) { -//! s.emit_struct("Node", 1, || { -//! s.emit_field("id", 0, || s.emit_uint(self.id)) +//! impl, E> Encodable for Node { +//! fn encode(&self, s: &mut S) -> Result<(), E> { +//! s.emit_struct("Node", 1, |this| { +//! this.emit_struct_field("id", 0, |this| { +//! Encodable::encode(&self.id, this) +//! /* this.emit_uint(self.id) can also be used */ +//! }) //! }) //! } //! } //! -//! impl Decodable for node_id { -//! fn decode(d: &D) -> Node { -//! d.read_struct("Node", 1, || { -//! Node { -//! id: d.read_field("x".to_string(), 0, || decode(d)) +//! impl, E> Decodable for Node { +//! fn decode(d: &mut D) -> Result { +//! d.read_struct("Node", 1, |this| { +//! match this.read_struct_field("id", 0, |this| Decodable::decode(this)) { +//! Ok(id) => Ok(Node { id: id }), +//! Err(e) => Err(e), //! } //! }) //! } @@ -46,37 +50,42 @@ //! //! ```ignore //! #[deriving(Encodable, Decodable)] -//! struct spanned { node: T, span: Span } +//! struct Spanned { node: T, span: Span } //! ``` //! //! would yield functions like: //! //! ```ignore -//! impl< -//! S: Encoder, -//! T: Encodable -//! > spanned: Encodable { -//! fn encode(s: &S) { -//! s.emit_rec(|| { -//! s.emit_field("node", 0, || self.node.encode(s)); -//! s.emit_field("span", 1, || self.span.encode(s)); -//! }) -//! } +//! impl< +//! S: Encoder, +//! E, +//! T: Encodable +//! > Encodable for Spanned { +//! fn encode(&self, s: &mut S) -> Result<(), E> { +//! s.emit_struct("Spanned", 2, |this| { +//! this.emit_struct_field("node", 0, |this| self.node.encode(this)) +//! .ok().unwrap(); +//! this.emit_struct_field("span", 1, |this| self.span.encode(this)) +//! }) //! } +//! } //! -//! impl< -//! D: Decoder, -//! T: Decodable -//! > spanned: Decodable { -//! fn decode(d: &D) -> spanned { -//! d.read_rec(|| { -//! { -//! node: d.read_field("node".to_string(), 0, || decode(d)), -//! span: d.read_field("span".to_string(), 1, || decode(d)), -//! } +//! impl< +//! D: Decoder, +//! E, +//! T: Decodable +//! > Decodable for Spanned { +//! fn decode(d: &mut D) -> Result, E> { +//! d.read_struct("Spanned", 2, |this| { +//! Ok(Spanned { +//! node: this.read_struct_field("node", 0, |this| Decodable::decode(this)) +//! .ok().unwrap(), +//! span: this.read_struct_field("span", 1, |this| Decodable::decode(this)) +//! .ok().unwrap(), //! }) -//! } +//! }) //! } +//! } //! ``` use ast::{MetaItem, Item, Expr, ExprRet, MutMutable, LitNil}; From 7eae5b458993b8a030ed9bb6e65c12babc4bbe4b Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 14 Nov 2014 22:22:42 +0300 Subject: [PATCH 07/23] impl Default for Cell and RefCell It is necessary to have #[deriving(Default)] for struct containing cells like Cell. --- src/libcore/cell.rs | 15 +++++++++++++++ src/libcoretest/cell.rs | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 9d3fa9deed7..24f841acbe9 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -157,6 +157,7 @@ use clone::Clone; use cmp::PartialEq; +use default::Default; use kinds::{marker, Copy}; use ops::{Deref, DerefMut, Drop}; use option::{None, Option, Some}; @@ -211,6 +212,13 @@ impl Clone for Cell { } } +#[unstable] +impl Default for Cell { + fn default() -> Cell { + Cell::new(Default::default()) + } +} + #[unstable = "waiting for `PartialEq` trait to become stable"] impl PartialEq for Cell { fn eq(&self, other: &Cell) -> bool { @@ -337,6 +345,13 @@ impl Clone for RefCell { } } +#[unstable] +impl Default for RefCell { + fn default() -> RefCell { + RefCell::new(Default::default()) + } +} + #[unstable = "waiting for `PartialEq` to become stable"] impl PartialEq for RefCell { fn eq(&self, other: &RefCell) -> bool { diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index 59365045f43..6444cf7ee0e 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -9,6 +9,7 @@ // except according to those terms. use core::cell::*; +use core::default::Default; use std::mem::drop; #[test] @@ -146,3 +147,15 @@ fn as_unsafe_cell() { unsafe { *r2.as_unsafe_cell().get() = 1u; } assert_eq!(1u, *r2.borrow()); } + +#[test] +fn cell_default() { + let cell: Cell = Default::default(); + assert_eq!(0, cell.get()); +} + +#[test] +fn refcell_default() { + let cell: RefCell = Default::default(); + assert_eq!(0, *cell.borrow()); +} From ccbda288d266cc3bd4f6b47b3be6020544fb1b68 Mon Sep 17 00:00:00 2001 From: Corey Ford Date: Fri, 14 Nov 2014 11:44:40 -0800 Subject: [PATCH 08/23] Hide interactive elements when printing rustdoc Hide the search form and expand/collapse buttons, since they aren't useful when printed. --- src/librustdoc/html/static/main.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index 7cc34798f99..b28da098a57 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -584,3 +584,9 @@ pre.rust { position: relative; } height: 1.5em; } } + +@media print { + nav.sub, .content .out-of-band, .collapse-toggle { + display: none; + } +} From 5416901ccad4550b6f7a6145de5dbbe94b98e309 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Fri, 14 Nov 2014 19:26:25 -0500 Subject: [PATCH 09/23] librustc: use type parameters less vigorously when giving the IR type names --- src/librustc/middle/trans/type_of.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index a597325015c..9530c86a94c 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -455,7 +455,12 @@ pub fn llvm_type_name(cx: &CrateContext, let base = ty::item_path_str(cx.tcx(), did); let strings: Vec = tps.iter().map(|t| t.repr(cx.tcx())).collect(); - let tstr = format!("{}<{}>", base, strings); + let tstr = if strings.is_empty() { + base + } else { + format!("{}<{}>", base, strings) + }; + if did.krate == 0 { format!("{}.{}", name, tstr) } else { From 4caffa8526b2d359aff853964b08aebb9683bcdb Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Nov 2014 20:39:41 -0800 Subject: [PATCH 10/23] libs: fix #[stable] inheritance fallout A recent change turned off inheritance for the #[stable] by default, but failed to catch all the cases where this was being used in std. This patch fixes that problem. --- src/liballoc/rc.rs | 4 +-- src/libcollections/vec.rs | 1 - src/libcore/any.rs | 4 +-- src/libcore/atomic.rs | 52 ++++++++++++++++++++++++++++++++++++--- src/libcore/cell.rs | 4 ++- src/libcore/option.rs | 5 ++-- src/libcore/result.rs | 7 +++++- 7 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 049bf4eb1b0..501f915461a 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -179,9 +179,9 @@ pub struct Rc { _noshare: marker::NoSync } -#[stable] impl Rc { /// Constructs a new reference-counted pointer. + #[stable] pub fn new(value: T) -> Rc { unsafe { Rc { @@ -200,9 +200,7 @@ impl Rc { } } } -} -impl Rc { /// Downgrades the reference-counted pointer to a weak reference. #[experimental = "Weak pointers may not belong in this module"] pub fn downgrade(&self) -> Weak { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index ca9a44a15f2..15e1031f69d 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -645,7 +645,6 @@ impl Vec { /// assert!(vec.capacity() >= 3); /// ``` #[stable] - #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn shrink_to_fit(&mut self) { if mem::size_of::() == 0 { return } diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 021f575b0ac..5511266b4cd 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -88,6 +88,7 @@ use intrinsics::TypeId; #[stable] pub trait Any: 'static { /// Get the `TypeId` of `self` + #[stable] fn get_type_id(&self) -> TypeId; } @@ -117,7 +118,6 @@ pub trait AnyRefExt<'a> { #[stable] impl<'a> AnyRefExt<'a> for &'a Any { #[inline] - #[stable] fn is(self) -> bool { // Get TypeId of the type this function is instantiated with let t = TypeId::of::(); @@ -130,7 +130,6 @@ impl<'a> AnyRefExt<'a> for &'a Any { } #[inline] - #[unstable = "naming conventions around acquiring references may change"] fn downcast_ref(self) -> Option<&'a T> { if self.is::() { unsafe { @@ -159,7 +158,6 @@ pub trait AnyMutRefExt<'a> { #[stable] impl<'a> AnyMutRefExt<'a> for &'a mut Any { #[inline] - #[unstable = "naming conventions around acquiring references may change"] fn downcast_mut(self) -> Option<&'a mut T> { if self.is::() { unsafe { diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index 0b1e08a5f43..d25a43ee2fe 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -58,20 +58,25 @@ pub struct AtomicPtr { #[stable] pub enum Ordering { /// No ordering constraints, only atomic operations + #[stable] Relaxed, /// When coupled with a store, all previous writes become visible /// to another thread that performs a load with `Acquire` ordering /// on the same value + #[stable] Release, /// When coupled with a load, all subsequent loads will see data /// written before a store with `Release` ordering on the same value /// in another thread + #[stable] Acquire, /// When coupled with a load, uses `Acquire` ordering, and with a store /// `Release` ordering + #[stable] AcqRel, /// Like `AcqRel` with the additional guarantee that all threads see all /// sequentially consistent operations in the same order. + #[stable] SeqCst } @@ -91,10 +96,10 @@ pub const INIT_ATOMIC_UINT: AtomicUint = // NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly const UINT_TRUE: uint = -1; -#[stable] impl AtomicBool { /// Create a new `AtomicBool` #[inline] + #[stable] pub fn new(v: bool) -> AtomicBool { let val = if v { UINT_TRUE } else { 0 }; AtomicBool { v: UnsafeCell::new(val), nocopy: marker::NoCopy } @@ -106,6 +111,7 @@ impl AtomicBool { /// /// Fails if `order` is `Release` or `AcqRel`. #[inline] + #[stable] pub fn load(&self, order: Ordering) -> bool { unsafe { atomic_load(self.v.get() as *const uint, order) > 0 } } @@ -116,6 +122,7 @@ impl AtomicBool { /// /// Fails if `order` is `Acquire` or `AcqRel`. #[inline] + #[stable] pub fn store(&self, val: bool, order: Ordering) { let val = if val { UINT_TRUE } else { 0 }; @@ -124,6 +131,7 @@ impl AtomicBool { /// Store a value, returning the old value #[inline] + #[stable] pub fn swap(&self, val: bool, order: Ordering) -> bool { let val = if val { UINT_TRUE } else { 0 }; @@ -174,6 +182,7 @@ impl AtomicBool { /// } /// ``` #[inline] + #[stable] pub fn compare_and_swap(&self, old: bool, new: bool, order: Ordering) -> bool { let old = if old { UINT_TRUE } else { 0 }; let new = if new { UINT_TRUE } else { 0 }; @@ -205,6 +214,7 @@ impl AtomicBool { /// assert_eq!(false, foo.load(SeqCst)); /// ``` #[inline] + #[stable] pub fn fetch_and(&self, val: bool, order: Ordering) -> bool { let val = if val { UINT_TRUE } else { 0 }; @@ -236,6 +246,7 @@ impl AtomicBool { /// assert_eq!(true, foo.load(SeqCst)); /// ``` #[inline] + #[stable] pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool { let val = if val { UINT_TRUE } else { 0 }; @@ -266,6 +277,7 @@ impl AtomicBool { /// assert_eq!(false, foo.load(SeqCst)); /// ``` #[inline] + #[stable] pub fn fetch_or(&self, val: bool, order: Ordering) -> bool { let val = if val { UINT_TRUE } else { 0 }; @@ -296,6 +308,7 @@ impl AtomicBool { /// assert_eq!(false, foo.load(SeqCst)); /// ``` #[inline] + #[stable] pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { let val = if val { UINT_TRUE } else { 0 }; @@ -303,10 +316,10 @@ impl AtomicBool { } } -#[stable] impl AtomicInt { /// Create a new `AtomicInt` #[inline] + #[stable] pub fn new(v: int) -> AtomicInt { AtomicInt {v: UnsafeCell::new(v), nocopy: marker::NoCopy} } @@ -317,6 +330,7 @@ impl AtomicInt { /// /// Fails if `order` is `Release` or `AcqRel`. #[inline] + #[stable] pub fn load(&self, order: Ordering) -> int { unsafe { atomic_load(self.v.get() as *const int, order) } } @@ -327,12 +341,14 @@ impl AtomicInt { /// /// Fails if `order` is `Acquire` or `AcqRel`. #[inline] + #[stable] pub fn store(&self, val: int, order: Ordering) { unsafe { atomic_store(self.v.get(), val, order); } } /// Store a value, returning the old value #[inline] + #[stable] pub fn swap(&self, val: int, order: Ordering) -> int { unsafe { atomic_swap(self.v.get(), val, order) } } @@ -343,6 +359,7 @@ impl AtomicInt { /// replace the current value with `new`. Return the previous value. /// If the return value is equal to `old` then the value was updated. #[inline] + #[stable] pub fn compare_and_swap(&self, old: int, new: int, order: Ordering) -> int { unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) } } @@ -359,6 +376,7 @@ impl AtomicInt { /// assert_eq!(10, foo.load(SeqCst)); /// ``` #[inline] + #[stable] pub fn fetch_add(&self, val: int, order: Ordering) -> int { unsafe { atomic_add(self.v.get(), val, order) } } @@ -375,6 +393,7 @@ impl AtomicInt { /// assert_eq!(-10, foo.load(SeqCst)); /// ``` #[inline] + #[stable] pub fn fetch_sub(&self, val: int, order: Ordering) -> int { unsafe { atomic_sub(self.v.get(), val, order) } } @@ -390,6 +409,7 @@ impl AtomicInt { /// assert_eq!(0b101101, foo.fetch_and(0b110011, SeqCst)); /// assert_eq!(0b100001, foo.load(SeqCst)); #[inline] + #[stable] pub fn fetch_and(&self, val: int, order: Ordering) -> int { unsafe { atomic_and(self.v.get(), val, order) } } @@ -405,6 +425,7 @@ impl AtomicInt { /// assert_eq!(0b101101, foo.fetch_or(0b110011, SeqCst)); /// assert_eq!(0b111111, foo.load(SeqCst)); #[inline] + #[stable] pub fn fetch_or(&self, val: int, order: Ordering) -> int { unsafe { atomic_or(self.v.get(), val, order) } } @@ -420,15 +441,16 @@ impl AtomicInt { /// assert_eq!(0b101101, foo.fetch_xor(0b110011, SeqCst)); /// assert_eq!(0b011110, foo.load(SeqCst)); #[inline] + #[stable] pub fn fetch_xor(&self, val: int, order: Ordering) -> int { unsafe { atomic_xor(self.v.get(), val, order) } } } -#[stable] impl AtomicUint { /// Create a new `AtomicUint` #[inline] + #[stable] pub fn new(v: uint) -> AtomicUint { AtomicUint { v: UnsafeCell::new(v), nocopy: marker::NoCopy } } @@ -439,6 +461,7 @@ impl AtomicUint { /// /// Fails if `order` is `Release` or `AcqRel`. #[inline] + #[stable] pub fn load(&self, order: Ordering) -> uint { unsafe { atomic_load(self.v.get() as *const uint, order) } } @@ -449,12 +472,14 @@ impl AtomicUint { /// /// Fails if `order` is `Acquire` or `AcqRel`. #[inline] + #[stable] pub fn store(&self, val: uint, order: Ordering) { unsafe { atomic_store(self.v.get(), val, order); } } /// Store a value, returning the old value #[inline] + #[stable] pub fn swap(&self, val: uint, order: Ordering) -> uint { unsafe { atomic_swap(self.v.get(), val, order) } } @@ -465,6 +490,7 @@ impl AtomicUint { /// replace the current value with `new`. Return the previous value. /// If the return value is equal to `old` then the value was updated. #[inline] + #[stable] pub fn compare_and_swap(&self, old: uint, new: uint, order: Ordering) -> uint { unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) } } @@ -481,6 +507,7 @@ impl AtomicUint { /// assert_eq!(10, foo.load(SeqCst)); /// ``` #[inline] + #[stable] pub fn fetch_add(&self, val: uint, order: Ordering) -> uint { unsafe { atomic_add(self.v.get(), val, order) } } @@ -497,6 +524,7 @@ impl AtomicUint { /// assert_eq!(0, foo.load(SeqCst)); /// ``` #[inline] + #[stable] pub fn fetch_sub(&self, val: uint, order: Ordering) -> uint { unsafe { atomic_sub(self.v.get(), val, order) } } @@ -512,6 +540,7 @@ impl AtomicUint { /// assert_eq!(0b101101, foo.fetch_and(0b110011, SeqCst)); /// assert_eq!(0b100001, foo.load(SeqCst)); #[inline] + #[stable] pub fn fetch_and(&self, val: uint, order: Ordering) -> uint { unsafe { atomic_and(self.v.get(), val, order) } } @@ -527,6 +556,7 @@ impl AtomicUint { /// assert_eq!(0b101101, foo.fetch_or(0b110011, SeqCst)); /// assert_eq!(0b111111, foo.load(SeqCst)); #[inline] + #[stable] pub fn fetch_or(&self, val: uint, order: Ordering) -> uint { unsafe { atomic_or(self.v.get(), val, order) } } @@ -542,15 +572,16 @@ impl AtomicUint { /// assert_eq!(0b101101, foo.fetch_xor(0b110011, SeqCst)); /// assert_eq!(0b011110, foo.load(SeqCst)); #[inline] + #[stable] pub fn fetch_xor(&self, val: uint, order: Ordering) -> uint { unsafe { atomic_xor(self.v.get(), val, order) } } } -#[stable] impl AtomicPtr { /// Create a new `AtomicPtr` #[inline] + #[stable] pub fn new(p: *mut T) -> AtomicPtr { AtomicPtr { p: UnsafeCell::new(p as uint), nocopy: marker::NoCopy } } @@ -561,6 +592,7 @@ impl AtomicPtr { /// /// Fails if `order` is `Release` or `AcqRel`. #[inline] + #[stable] pub fn load(&self, order: Ordering) -> *mut T { unsafe { atomic_load(self.p.get() as *const *mut T, order) as *mut T @@ -573,12 +605,14 @@ impl AtomicPtr { /// /// Fails if `order` is `Acquire` or `AcqRel`. #[inline] + #[stable] pub fn store(&self, ptr: *mut T, order: Ordering) { unsafe { atomic_store(self.p.get(), ptr as uint, order); } } /// Store a value, returning the old value #[inline] + #[stable] pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { unsafe { atomic_swap(self.p.get(), ptr as uint, order) as *mut T } } @@ -589,6 +623,7 @@ impl AtomicPtr { /// replace the current value with `new`. Return the previous value. /// If the return value is equal to `old` then the value was updated. #[inline] + #[stable] pub fn compare_and_swap(&self, old: *mut T, new: *mut T, order: Ordering) -> *mut T { unsafe { atomic_compare_and_swap(self.p.get(), old as uint, @@ -609,6 +644,7 @@ unsafe fn atomic_store(dst: *mut T, val: T, order:Ordering) { } #[inline] +#[stable] unsafe fn atomic_load(dst: *const T, order:Ordering) -> T { match order { Acquire => intrinsics::atomic_load_acq(dst), @@ -620,6 +656,7 @@ unsafe fn atomic_load(dst: *const T, order:Ordering) -> T { } #[inline] +#[stable] unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xchg_acq(dst, val), @@ -632,6 +669,7 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the old value (like __sync_fetch_and_add). #[inline] +#[stable] unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xadd_acq(dst, val), @@ -644,6 +682,7 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the old value (like __sync_fetch_and_sub). #[inline] +#[stable] unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xsub_acq(dst, val), @@ -655,6 +694,7 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] +#[stable] unsafe fn atomic_compare_and_swap(dst: *mut T, old:T, new:T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_cxchg_acq(dst, old, new), @@ -666,6 +706,7 @@ unsafe fn atomic_compare_and_swap(dst: *mut T, old:T, new:T, order: Ordering) } #[inline] +#[stable] unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_and_acq(dst, val), @@ -677,6 +718,7 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] +#[stable] unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_nand_acq(dst, val), @@ -689,6 +731,7 @@ unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { #[inline] +#[stable] unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_or_acq(dst, val), @@ -701,6 +744,7 @@ unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { #[inline] +#[stable] unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xor_acq(dst, val), diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 9d3fa9deed7..dfef079d100 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -168,9 +168,9 @@ pub struct Cell { noshare: marker::NoSync, } -#[stable] impl Cell { /// Creates a new `Cell` containing the given value. + #[stable] pub fn new(value: T) -> Cell { Cell { value: UnsafeCell::new(value), @@ -180,12 +180,14 @@ impl Cell { /// Returns a copy of the contained value. #[inline] + #[stable] pub fn get(&self) -> T { unsafe{ *self.value.get() } } /// Sets the contained value. #[inline] + #[stable] pub fn set(&self, value: T) { unsafe { *self.value.get() = value; diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 2964a6b6853..d41dbb11adb 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -716,7 +716,6 @@ impl Option { impl AsSlice for Option { /// Convert from `Option` to `&[T]` (without copying) #[inline] - #[stable] fn as_slice<'a>(&'a self) -> &'a [T] { match *self { Some(ref x) => slice::ref_slice(x), @@ -728,6 +727,7 @@ impl AsSlice for Option { } } +#[stable] impl Default for Option { #[inline] fn default() -> Option { None } @@ -772,9 +772,10 @@ impl DoubleEndedIterator for Item { impl ExactSize for Item {} ///////////////////////////////////////////////////////////////////////////// -// Free functions +// FromIterator ///////////////////////////////////////////////////////////////////////////// +#[stable] impl> FromIterator> for Option { /// Takes each element in the `Iterator`: if it is `None`, no further /// elements are taken, and the `None` is returned. Should no `None` occur, a diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c4cb2987241..6c591fbcc38 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -878,9 +878,10 @@ impl DoubleEndedIterator for Item { impl ExactSize for Item {} ///////////////////////////////////////////////////////////////////////////// -// Free functions +// FromIterator ///////////////////////////////////////////////////////////////////////////// +#[stable] impl> FromIterator> for Result { /// Takes each element in the `Iterator`: if it is an `Err`, no further /// elements are taken, and the `Err` is returned. Should no `Err` occur, a @@ -933,6 +934,10 @@ impl> FromIterator> for Result { } } +///////////////////////////////////////////////////////////////////////////// +// FromIterator +///////////////////////////////////////////////////////////////////////////// + /// Perform a fold operation over the result values from an iterator. /// /// If an `Err` is encountered, it is immediately returned. From 60741e0fa0948c75040d0d554b46027021185600 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Nov 2014 20:54:27 -0800 Subject: [PATCH 11/23] rustdoc: tweak stability summary counting This commit slightly tweaks the counting of impl blocks and structs for the stability summary (so that the block itself isn't counted for inherent impls, and the fields aren't counted for structs). --- src/librustdoc/stability_summary.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustdoc/stability_summary.rs b/src/librustdoc/stability_summary.rs index b0e1aeea3a1..058d8b81f7a 100644 --- a/src/librustdoc/stability_summary.rs +++ b/src/librustdoc/stability_summary.rs @@ -146,13 +146,12 @@ fn summarize_item(item: &Item) -> (Counts, Option) { // considered to have no children. match item.inner { // Require explicit `pub` to be visible - StructItem(Struct { fields: ref subitems, .. }) | ImplItem(Impl { items: ref subitems, trait_: None, .. }) => { let subcounts = subitems.iter().filter(|i| visible(*i)) .map(summarize_item) .map(|s| s.val0()) .fold(Counts::zero(), |acc, x| acc + x); - (item_counts + subcounts, None) + (subcounts, None) } // `pub` automatically EnumItem(Enum { variants: ref subitems, .. }) => { From 3391ddda114f4b01440b028aa677af152a8675c8 Mon Sep 17 00:00:00 2001 From: inrustwetrust Date: Sat, 15 Nov 2014 14:51:22 +0100 Subject: [PATCH 12/23] Slightly improved rustc error messages for invalid -C arguments --- src/librustc/driver/config.rs | 35 ++++++++++++++----- src/librustc/driver/mod.rs | 12 +++---- .../run-make/codegen-options-parsing/Makefile | 24 +++++++++++++ .../run-make/codegen-options-parsing/dummy.rs | 11 ++++++ 4 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 src/test/run-make/codegen-options-parsing/Makefile create mode 100644 src/test/run-make/codegen-options-parsing/dummy.rs diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index 8c1d7c839ac..b60676eb4c3 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -268,8 +268,21 @@ macro_rules! cgoptions( pub type CodegenSetter = fn(&mut CodegenOptions, v: Option<&str>) -> bool; pub const CG_OPTIONS: &'static [(&'static str, CodegenSetter, - &'static str)] = - &[ $( (stringify!($opt), cgsetters::$opt, $desc) ),* ]; + Option<&'static str>, &'static str)] = + &[ $( (stringify!($opt), cgsetters::$opt, cg_type_descs::$parse, $desc) ),* ]; + + #[allow(non_upper_case_globals)] + mod cg_type_descs { + pub const parse_bool: Option<&'static str> = None; + pub const parse_opt_bool: Option<&'static str> = None; + pub const parse_string: Option<&'static str> = Some("a string"); + pub const parse_opt_string: Option<&'static str> = Some("a string"); + pub const parse_list: Option<&'static str> = Some("a space-separated list of strings"); + pub const parse_opt_list: Option<&'static str> = Some("a space-separated list of strings"); + pub const parse_uint: Option<&'static str> = Some("a number"); + pub const parse_passes: Option<&'static str> = + Some("a space-separated list of passes, or `all`"); + } mod cgsetters { use super::{CodegenOptions, Passes, SomePasses, AllPasses}; @@ -421,19 +434,25 @@ pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions let value = iter.next(); let option_to_lookup = key.replace("-", "_"); let mut found = false; - for &(candidate, setter, _) in CG_OPTIONS.iter() { + for &(candidate, setter, opt_type_desc, _) in CG_OPTIONS.iter() { if option_to_lookup.as_slice() != candidate { continue } if !setter(&mut cg, value) { - match value { - Some(..) => { + match (value, opt_type_desc) { + (Some(..), None) => { early_error(format!("codegen option `{}` takes no \ value", key).as_slice()) } - None => { + (None, Some(type_desc)) => { early_error(format!("codegen option `{0}` requires \ - a value (-C {0}=)", - key).as_slice()) + {1} (-C {0}=)", + key, type_desc).as_slice()) } + (Some(value), Some(type_desc)) => { + early_error(format!("incorrect value `{}` for codegen \ + option `{}` - {} was expected", + value, key, type_desc).as_slice()) + } + (None, None) => unreachable!() } } found = true; diff --git a/src/librustc/driver/mod.rs b/src/librustc/driver/mod.rs index edd82b42876..546469c3c0e 100644 --- a/src/librustc/driver/mod.rs +++ b/src/librustc/driver/mod.rs @@ -299,14 +299,10 @@ fn describe_debug_flags() { fn describe_codegen_flags() { println!("\nAvailable codegen options:\n"); - let mut cg = config::basic_codegen_options(); - for &(name, parser, desc) in config::CG_OPTIONS.iter() { - // we invoke the parser function on `None` to see if this option needs - // an argument or not. - let (width, extra) = if parser(&mut cg, None) { - (25, "") - } else { - (21, "=val") + for &(name, _, opt_type_desc, desc) in config::CG_OPTIONS.iter() { + let (width, extra) = match opt_type_desc { + Some(..) => (21, "=val"), + None => (25, "") }; println!(" -C {:>width$s}{} -- {}", name.replace("_", "-"), extra, desc, width=width); diff --git a/src/test/run-make/codegen-options-parsing/Makefile b/src/test/run-make/codegen-options-parsing/Makefile new file mode 100644 index 00000000000..e439b27a190 --- /dev/null +++ b/src/test/run-make/codegen-options-parsing/Makefile @@ -0,0 +1,24 @@ +-include ../tools.mk + +all: + #Option taking a number + $(RUSTC) -C codegen-units dummy.rs 2>&1 | \ + grep 'codegen option `codegen-units` requires a number' + $(RUSTC) -C codegen-units= dummy.rs 2>&1 | \ + grep 'incorrect value `` for codegen option `codegen-units` - a number was expected' + $(RUSTC) -C codegen-units=foo dummy.rs 2>&1 | \ + grep 'incorrect value `foo` for codegen option `codegen-units` - a number was expected' + $(RUSTC) -C codegen-units=1 dummy.rs + #Option taking a string + $(RUSTC) -C extra-filename dummy.rs 2>&1 | \ + grep 'codegen option `extra-filename` requires a string' + $(RUSTC) -C extra-filename= dummy.rs 2>&1 + $(RUSTC) -C extra-filename=foo dummy.rs 2>&1 + #Option taking no argument + $(RUSTC) -C lto= dummy.rs 2>&1 | \ + grep 'codegen option `lto` takes no value' + $(RUSTC) -C lto=1 dummy.rs 2>&1 | \ + grep 'codegen option `lto` takes no value' + $(RUSTC) -C lto=foo dummy.rs 2>&1 | \ + grep 'codegen option `lto` takes no value' + $(RUSTC) -C lto dummy.rs diff --git a/src/test/run-make/codegen-options-parsing/dummy.rs b/src/test/run-make/codegen-options-parsing/dummy.rs new file mode 100644 index 00000000000..8ae3d072362 --- /dev/null +++ b/src/test/run-make/codegen-options-parsing/dummy.rs @@ -0,0 +1,11 @@ +// 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. + +fn main() {} From 3e0368e621047892352d1ec02d9fa6124ca28e77 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 15 Nov 2014 11:23:40 -0800 Subject: [PATCH 13/23] std: Fix a flaky test on OSX 10.10 This test was somewhat sketchy already with a `loop` around `write`, so this just adds some explicit synchronization to only call `write` once and guarantee that the error happens. Closes #18900 --- src/libstd/io/net/tcp.rs | 46 +++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 2545e07cbb5..24fc2998ee6 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -661,23 +661,22 @@ mod test { let addr = next_test_ip4(); let mut acceptor = TcpListener::bind(addr).listen(); + let (tx, rx) = channel(); spawn(proc() { - let _stream = TcpStream::connect(addr); - // Close + drop(TcpStream::connect(addr)); + tx.send(()); }); let mut stream = acceptor.accept(); + rx.recv(); let buf = [0]; - loop { - match stream.write(buf) { - Ok(..) => {} - Err(e) => { - assert!(e.kind == ConnectionReset || - e.kind == BrokenPipe || - e.kind == ConnectionAborted, - "unknown error: {}", e); - break; - } + match stream.write(buf) { + Ok(..) => {} + Err(e) => { + assert!(e.kind == ConnectionReset || + e.kind == BrokenPipe || + e.kind == ConnectionAborted, + "unknown error: {}", e); } } } @@ -687,23 +686,22 @@ mod test { let addr = next_test_ip6(); let mut acceptor = TcpListener::bind(addr).listen(); + let (tx, rx) = channel(); spawn(proc() { - let _stream = TcpStream::connect(addr); - // Close + drop(TcpStream::connect(addr)); + tx.send(()); }); let mut stream = acceptor.accept(); + rx.recv(); let buf = [0]; - loop { - match stream.write(buf) { - Ok(..) => {} - Err(e) => { - assert!(e.kind == ConnectionReset || - e.kind == BrokenPipe || - e.kind == ConnectionAborted, - "unknown error: {}", e); - break; - } + match stream.write(buf) { + Ok(..) => {} + Err(e) => { + assert!(e.kind == ConnectionReset || + e.kind == BrokenPipe || + e.kind == ConnectionAborted, + "unknown error: {}", e); } } } From e94cd40f7ebb8fccf84cebdf050c57426eed0158 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 15 Nov 2014 15:00:47 -0800 Subject: [PATCH 14/23] Fixed several typos --- src/doc/guide-strings.md | 2 +- src/doc/reference.md | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/guide-strings.md b/src/doc/guide-strings.md index 1c7cb1a3b4e..071c9ff013c 100644 --- a/src/doc/guide-strings.md +++ b/src/doc/guide-strings.md @@ -155,7 +155,7 @@ println!("{}", s[0]); This does not compile. This is on purpose. In the world of UTF-8, direct indexing is basically never what you want to do. The reason is that each character can be a variable number of bytes. This means that you have to iterate -through the characters anyway, which is a O(n) operation. +through the characters anyway, which is an O(n) operation. There's 3 basic levels of unicode (and its encodings): diff --git a/src/doc/reference.md b/src/doc/reference.md index d05705562d2..58d8476d4f9 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2526,7 +2526,7 @@ The currently implemented features of the reference compiler are: * `plugin_registrar` - Indicates that a crate has [compiler plugins][plugin] that it wants to load. As with `phase`, the implementation is - in need of a overhaul, and it is not clear that plugins + in need of an overhaul, and it is not clear that plugins defined using this will continue to work. * `quote` - Allows use of the `quote_*!` family of macros, which are @@ -2583,7 +2583,7 @@ there isn't a parser error first). The directive in this case is no longer necessary, and it's likely that existing code will break if the feature isn't removed. -If a unknown feature is found in a directive, it results in a compiler error. +If an unknown feature is found in a directive, it results in a compiler error. An unknown feature is one which has never been recognized by the compiler. # Statements and expressions @@ -2685,7 +2685,7 @@ When an lvalue is evaluated in an _lvalue context_, it denotes a memory location; when evaluated in an _rvalue context_, it denotes the value held _in_ that memory location. -When an rvalue is used in lvalue context, a temporary un-named lvalue is +When an rvalue is used in an lvalue context, a temporary un-named lvalue is created and used instead. A temporary's lifetime equals the largest lifetime of any reference that points to it. @@ -2833,7 +2833,7 @@ foo().x; ``` A field access is an [lvalue](#lvalues,-rvalues-and-temporaries) referring to -the value of that field. When the type providing the field inherits mutabilty, +the value of that field. When the type providing the field inherits mutability, it can be [assigned](#assignment-expressions) to. Also, if the type of the expression to the left of the dot is a pointer, it is @@ -3321,7 +3321,7 @@ between `_` and `..` is that the pattern `C(_)` is only type-correct if `C` has exactly one argument, while the pattern `C(..)` is type-correct for any enum variant `C`, regardless of how many arguments `C` has. -Used inside a array pattern, `..` stands for any number of elements, when the +Used inside an array pattern, `..` stands for any number of elements, when the `advanced_slice_patterns` feature gate is turned on. This wildcard can be used at most once for a given array, which implies that it cannot be used to specifically match elements that are at an unknown distance from both ends of a @@ -3584,7 +3584,7 @@ is not a surrogate), represented as a 32-bit unsigned word in the 0x0000 to 0xD7FF or 0xE000 to 0x10FFFF range. A `[char]` array is effectively an UCS-4 / UTF-32 string. -A value of type `str` is a Unicode string, represented as a array of 8-bit +A value of type `str` is a Unicode string, represented as an array of 8-bit unsigned bytes holding a sequence of UTF-8 codepoints. Since `str` is of unknown size, it is not a _first class_ type, but can only be instantiated through a pointer type, such as `&str` or `String`. From c5232615b6669431b70720d25f68b5c1bc9662e2 Mon Sep 17 00:00:00 2001 From: Alfie John Date: Sat, 15 Nov 2014 23:17:36 +0000 Subject: [PATCH 15/23] doc: small grammar fix --- src/doc/complement-design-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/complement-design-faq.md b/src/doc/complement-design-faq.md index 9a2531f094c..e57953db3a2 100644 --- a/src/doc/complement-design-faq.md +++ b/src/doc/complement-design-faq.md @@ -95,7 +95,7 @@ code should need to run is a stack. `match` being exhaustive has some useful properties. First, if every possibility is covered by the `match`, adding further variants to the `enum` in the future will prompt a compilation failure, rather than runtime panic. -Second, it makes cost explicit. In general, only safe way to have a +Second, it makes cost explicit. In general, the only safe way to have a non-exhaustive match would be to panic the task if nothing is matched, though it could fall through if the type of the `match` expression is `()`. This sort of hidden cost and special casing is against the language's philosophy. It's From 29bc9c632eda71c6b4a8b35db637971953b58d03 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 15 Nov 2014 15:52:00 +1100 Subject: [PATCH 16/23] Move FromStr to core::str --- src/compiletest/common.rs | 2 +- src/compiletest/compiletest.rs | 2 +- src/compiletest/header.rs | 8 +- src/doc/reference.md | 3 +- src/libcollections/str.rs | 1 + src/libcollections/string.rs | 9 +- src/libcore/num/f32.rs | 67 +++++++- src/libcore/num/f64.rs | 62 ++++++- src/libcore/num/int_macros.rs | 16 ++ src/libcore/num/mod.rs | 14 ++ src/libcore/num/strconv.rs | 259 +++++++++++++++++++++++++++++ src/libcore/num/uint_macros.rs | 16 ++ src/libcore/prelude.rs | 1 + src/libcore/str.rs | 36 +++++ src/libcoretest/num/int_macros.rs | 46 +++++- src/libcoretest/num/mod.rs | 70 ++++++++ src/libcoretest/str.rs | 7 + src/libregex/re.rs | 1 - src/librustc/driver/config.rs | 3 +- src/librustc/driver/pretty.rs | 2 +- src/libserialize/json.rs | 10 +- src/libstd/from_str.rs | 71 -------- src/libstd/io/net/ip.rs | 5 +- src/libstd/lib.rs | 3 +- src/libstd/num/f32.rs | 64 -------- src/libstd/num/f64.rs | 59 ------- src/libstd/num/i16.rs | 5 - src/libstd/num/i32.rs | 5 - src/libstd/num/i64.rs | 5 - src/libstd/num/i8.rs | 5 - src/libstd/num/int.rs | 5 - src/libstd/num/int_macros.rs | 127 --------------- src/libstd/num/mod.rs | 15 +- src/libstd/num/strconv.rs | 261 +++--------------------------- src/libstd/num/u16.rs | 5 - src/libstd/num/u32.rs | 5 - src/libstd/num/u64.rs | 5 - src/libstd/num/u8.rs | 5 - src/libstd/num/uint.rs | 5 - src/libstd/num/uint_macros.rs | 16 -- src/libstd/path/posix.rs | 3 +- src/libstd/path/windows.rs | 3 +- src/libstd/prelude.rs | 2 +- src/libstd/rt/backtrace.rs | 3 +- src/libstd/rt/util.rs | 4 +- src/libtest/lib.rs | 2 +- 46 files changed, 648 insertions(+), 675 deletions(-) create mode 100644 src/libcore/num/strconv.rs delete mode 100644 src/libstd/from_str.rs diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index 2c917f7aefe..b7d4596b0fe 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::from_str::FromStr; use std::fmt; +use std::str::FromStr; use regex::Regex; #[deriving(Clone, PartialEq)] diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index caf1c8c314d..d49ff0258ab 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -22,7 +22,7 @@ extern crate regex; use std::os; use std::io; use std::io::fs; -use std::from_str::FromStr; +use std::str::FromStr; use getopts::{optopt, optflag, reqopt}; use common::Config; use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen}; diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index b7b94ca6d0d..60ef76528e8 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -12,8 +12,6 @@ use common::Config; use common; use util; -use std::from_str::FromStr; - pub struct TestProps { // Lines that should be expected, in order, on standard out pub error_patterns: Vec , @@ -353,8 +351,8 @@ pub fn gdb_version_to_int(version_string: &str) -> int { panic!("{}", error_string); } - let major: int = FromStr::from_str(components[0]).expect(error_string); - let minor: int = FromStr::from_str(components[1]).expect(error_string); + let major: int = from_str(components[0]).expect(error_string); + let minor: int = from_str(components[1]).expect(error_string); return major * 1000 + minor; } @@ -364,6 +362,6 @@ pub fn lldb_version_to_int(version_string: &str) -> int { "Encountered LLDB version string with unexpected format: {}", version_string); let error_string = error_string.as_slice(); - let major: int = FromStr::from_str(version_string).expect(error_string); + let major: int = from_str(version_string).expect(error_string); return major; } diff --git a/src/doc/reference.md b/src/doc/reference.md index d05705562d2..b3bf554f30c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3108,11 +3108,10 @@ then the expression completes. Some examples of call expressions: ``` -# use std::from_str::FromStr; # fn add(x: int, y: int) -> int { 0 } let x: int = add(1, 2); -let pi: Option = FromStr::from_str("3.14"); +let pi: Option = from_str("3.14"); ``` ### Lambda expressions diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 20aa29fbb3d..a2f89dfecbc 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -73,6 +73,7 @@ pub use core::str::{CharSplitsN, AnyLines, MatchIndices, StrSplits}; pub use core::str::{Utf16CodeUnits, eq_slice, is_utf8, is_utf16, Utf16Items}; pub use core::str::{Utf16Item, ScalarValue, LoneSurrogate, utf16_items}; pub use core::str::{truncate_utf16_at_nul, utf8_char_width, CharRange}; +pub use core::str::{FromStr, from_str}; pub use core::str::{Str, StrPrelude}; pub use unicode::str::{UnicodeStrPrelude, Words, Graphemes, GraphemeIndices}; diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 5872afc6fde..c1e093436c3 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -25,7 +25,7 @@ use core::raw::Slice as RawSlice; use hash; use slice::CloneSliceAllocPrelude; use str; -use str::{CharRange, StrAllocating, MaybeOwned, Owned}; +use str::{CharRange, FromStr, StrAllocating, MaybeOwned, Owned}; use str::Slice as MaybeOwnedSlice; // So many `Slice`s... use vec::{DerefVec, Vec, as_vec}; @@ -795,6 +795,13 @@ pub fn as_string<'a>(x: &'a str) -> DerefString<'a> { DerefString { x: as_vec(x.as_bytes()) } } +impl FromStr for String { + #[inline] + fn from_str(s: &str) -> Option { + Some(String::from_str(s)) + } +} + /// Unsafe operations #[unstable = "waiting on raw module conventions"] pub mod raw { diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index ba03bb8f3d5..c674a806836 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -17,7 +17,9 @@ use intrinsics; use mem; use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; -use num::Float; +use num::{Float, FromStrRadix}; +use num::strconv; +use str::FromStr; use option::Option; pub const RADIX: uint = 2u; @@ -424,3 +426,66 @@ impl Float for f32 { self * (value / 180.0f32) } } + +#[inline] +#[allow(missing_docs)] +#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] +pub fn from_str_hex(src: &str) -> Option { + strconv::from_str_radix_float(src, 16) +} + +impl FromStr for f32 { + /// Convert a string in base 10 to a float. + /// Accepts an optional decimal exponent. + /// + /// This function accepts strings such as + /// + /// * '3.14' + /// * '+3.14', equivalent to '3.14' + /// * '-3.14' + /// * '2.5E10', or equivalently, '2.5e10' + /// * '2.5E-10' + /// * '.' (understood as 0) + /// * '5.' + /// * '.5', or, equivalently, '0.5' + /// * '+inf', 'inf', '-inf', 'NaN' + /// + /// Leading and trailing whitespace represent an error. + /// + /// # Arguments + /// + /// * src - A string + /// + /// # Return value + /// + /// `None` if the string did not represent a valid number. Otherwise, + /// `Some(n)` where `n` is the floating-point number represented by `src`. + #[inline] + fn from_str(src: &str) -> Option { + strconv::from_str_radix_float(src, 10u) + } +} + +impl FromStrRadix for f32 { + /// Convert a string in a given base to a float. + /// + /// Due to possible conflicts, this function does **not** accept + /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** + /// does it recognize exponents of any kind. + /// + /// Leading and trailing whitespace represent an error. + /// + /// # Arguments + /// + /// * src - A string + /// * radix - The base to use. Must lie in the range [2 .. 36] + /// + /// # Return value + /// + /// `None` if the string did not represent a valid number. Otherwise, + /// `Some(n)` where `n` is the floating-point number represented by `src`. + #[inline] + fn from_str_radix(src: &str, radix: uint) -> Option { + strconv::from_str_radix_float(src, radix) + } +} diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index f1af4f0272c..2abd6c237c8 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -17,7 +17,9 @@ use intrinsics; use mem; use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; -use num::Float; +use num::{Float, FromStrRadix}; +use num::strconv; +use str::FromStr; use option::Option; // FIXME(#5527): These constants should be deprecated once associated @@ -430,3 +432,61 @@ impl Float for f64 { self * (value / 180.0) } } + +#[inline] +#[allow(missing_docs)] +#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] +pub fn from_str_hex(src: &str) -> Option { + strconv::from_str_radix_float(src, 16) +} + +impl FromStr for f64 { + /// Convert a string in base 10 to a float. + /// Accepts an optional decimal exponent. + /// + /// This function accepts strings such as: + /// + /// * '3.14' + /// * '-3.14' + /// * '2.5E10', or equivalently, '2.5e10' + /// * '2.5E-10' + /// * '.' (understood as 0) + /// * '5.' + /// * '.5', or, equivalently, '0.5' + /// * inf', '-inf', 'NaN' + /// + /// Leading and trailing whitespace represent an error. + /// + /// # Arguments + /// + /// * src - A string + /// + /// # Return value + /// + /// `none` if the string did not represent a valid number. Otherwise, + /// `Some(n)` where `n` is the floating-point number represented by `src`. + #[inline] + fn from_str(src: &str) -> Option { + strconv::from_str_radix_float(src, 10u) + } +} + +impl FromStrRadix for f64 { + /// Convert a string in a given base to a float. + /// + /// Leading and trailing whitespace represent an error. + /// + /// # Arguments + /// + /// * src - A string + /// * radix - The base to use. Must lie in the range [2 .. 36] + /// + /// # Return value + /// + /// `None` if the string did not represent a valid number. Otherwise, + /// `Some(n)` where `n` is the floating-point number represented by `src`. + #[inline] + fn from_str_radix(src: &str, radix: uint) -> Option { + strconv::from_str_radix_float(src, radix) + } +} diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index 0f8950344c8..dc60a0c9764 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -32,4 +32,20 @@ pub const MIN: $T = (-1 as $T) << (BITS - 1); #[unstable] pub const MAX: $T = !MIN; +#[experimental = "might need to return Result"] +impl ::str::FromStr for $T { + #[inline] + fn from_str(s: &str) -> ::option::Option<$T> { + ::num::strconv::from_str_radix_int(s, 10) + } +} + +#[experimental = "might need to return Result"] +impl ::num::FromStrRadix for $T { + #[inline] + fn from_str_radix(s: &str, radix: uint) -> ::option::Option<$T> { + ::num::strconv::from_str_radix_int(s, radix) + } +} + )) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 216d140ac48..391ccce568b 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -27,6 +27,8 @@ use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::{Option, Some, None}; +pub mod strconv; + /// Simultaneous division and remainder #[inline] pub fn div_rem + Rem>(x: T, y: T) -> (T, T) { @@ -1372,6 +1374,18 @@ pub trait Float fn to_radians(self) -> Self; } +/// A generic trait for converting a string with a radix (base) to a value +#[experimental = "might need to return Result"] +pub trait FromStrRadix { + fn from_str_radix(str: &str, radix: uint) -> Option; +} + +/// A utility function that just calls FromStrRadix::from_str_radix. +#[experimental = "might need to return Result"] +pub fn from_str_radix(str: &str, radix: uint) -> Option { + FromStrRadix::from_str_radix(str, radix) +} + // DEPRECATED macro_rules! trait_impl { diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs new file mode 100644 index 00000000000..daa2a8e2343 --- /dev/null +++ b/src/libcore/num/strconv.rs @@ -0,0 +1,259 @@ +// Copyright 2013-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. +// +// ignore-lexer-test FIXME #15679 + +#![allow(missing_docs)] + +use char::Char; +use iter::Iterator; +use num; +use num::{Int, Float}; +use option::{None, Option, Some}; +use str::{from_str, StrPrelude}; + +pub fn from_str_radix_float(src: &str, radix: uint) -> Option { + assert!(radix >= 2 && radix <= 36, + "from_str_radix_float: must lie in the range `[2, 36]` - found {}", + radix); + + let _0: T = Float::zero(); + let _1: T = Float::one(); + let radix_t: T = num::cast(radix as int).unwrap(); + + // Special values + match src { + "inf" => return Some(Float::infinity()), + "-inf" => return Some(Float::neg_infinity()), + "NaN" => return Some(Float::nan()), + _ => {}, + } + + let (is_positive, src) = match src.slice_shift_char() { + (None, _) => return None, + (Some('-'), "") => return None, + (Some('-'), src) => (false, src), + (Some(_), _) => (true, src), + }; + + // The significand to accumulate + let mut sig = if is_positive { _0 } else { -_0 }; + // Necessary to detect overflow + let mut prev_sig = sig; + let mut cs = src.chars().enumerate(); + // Exponent prefix and exponent index offset + let mut exp_info = None::<(char, uint)>; + + // Parse the integer part of the significand + for (i, c) in cs { + match c.to_digit(radix) { + Some(digit) => { + // shift significand one digit left + sig = sig * radix_t; + + // add/subtract current digit depending on sign + if is_positive { + sig = sig + num::cast(digit as int).unwrap(); + } else { + sig = sig - num::cast(digit as int).unwrap(); + } + + // Detect overflow by comparing to last value, except + // if we've not seen any non-zero digits. + if prev_sig != _0 { + if is_positive && sig <= prev_sig + { return Some(Float::infinity()); } + if !is_positive && sig >= prev_sig + { return Some(Float::neg_infinity()); } + + // Detect overflow by reversing the shift-and-add process + let digit: T = num::cast(digit as int).unwrap(); + if is_positive && (prev_sig != ((sig - digit) / radix_t)) + { return Some(Float::infinity()); } + if !is_positive && (prev_sig != ((sig + digit) / radix_t)) + { return Some(Float::neg_infinity()); } + } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + '.' => { + break; // start of fractional part + }, + _ => { + return None; + }, + }, + } + } + + // If we are not yet at the exponent parse the fractional + // part of the significand + if exp_info.is_none() { + let mut power = _1; + for (i, c) in cs { + match c.to_digit(radix) { + Some(digit) => { + let digit: T = num::cast(digit).unwrap(); + // Decrease power one order of magnitude + power = power / radix_t; + // add/subtract current digit depending on sign + sig = if is_positive { + sig + digit * power + } else { + sig - digit * power + }; + // Detect overflow by comparing to last value + if is_positive && sig < prev_sig + { return Some(Float::infinity()); } + if !is_positive && sig > prev_sig + { return Some(Float::neg_infinity()); } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + _ => { + return None; // invalid number + }, + }, + } + } + } + + // Parse and calculate the exponent + let exp = match exp_info { + Some((c, offset)) => { + let base: T = match c { + 'E' | 'e' if radix == 10 => num::cast(10u).unwrap(), + 'P' | 'p' if radix == 16 => num::cast(2u).unwrap(), + _ => return None, + }; + + // Parse the exponent as decimal integer + let src = src[offset..]; + let (is_positive, exp) = match src.slice_shift_char() { + (Some('-'), src) => (false, from_str::(src)), + (Some('+'), src) => (true, from_str::(src)), + (Some(_), _) => (true, from_str::(src)), + (None, _) => return None, + }; + + match (is_positive, exp) { + (true, Some(exp)) => base.powi(exp as i32), + (false, Some(exp)) => _1 / base.powi(exp as i32), + (_, None) => return None, + } + }, + None => _1, // no exponent + }; + + Some(sig * exp) +} + +pub fn from_str_radix_int(src: &str, radix: uint) -> Option { + assert!(radix >= 2 && radix <= 36, + "from_str_radix_int: must lie in the range `[2, 36]` - found {}", + radix); + + fn cast(x: uint) -> T { + num::cast(x).unwrap() + } + + let _0: T = Int::zero(); + let _1: T = Int::one(); + let is_signed = _0 > Int::min_value(); + + let (is_positive, src) = match src.slice_shift_char() { + (Some('-'), src) if is_signed => (false, src), + (Some(_), _) => (true, src), + (None, _) => return None, + }; + + let mut xs = src.chars().map(|c| { + c.to_digit(radix).map(cast) + }); + let radix = cast(radix); + let mut result = _0; + + if is_positive { + for x in xs { + let x = match x { + Some(x) => x, + None => return None, + }; + result = match result.checked_mul(radix) { + Some(result) => result, + None => return None, + }; + result = match result.checked_add(x) { + Some(result) => result, + None => return None, + }; + } + } else { + for x in xs { + let x = match x { + Some(x) => x, + None => return None, + }; + result = match result.checked_mul(radix) { + Some(result) => result, + None => return None, + }; + result = match result.checked_sub(x) { + Some(result) => result, + None => return None, + }; + } + } + + Some(result) +} + +#[cfg(test)] +mod test { + use super::*; + use option::*; + use num::Float; + + #[test] + fn from_str_issue7588() { + let u : Option = from_str_radix_int("1000", 10); + assert_eq!(u, None); + let s : Option = from_str_radix_int("80000", 10); + assert_eq!(s, None); + let f : Option = from_str_radix_float("10000000000000000000000000000000000000000", 10); + assert_eq!(f, Some(Float::infinity())) + let fe : Option = from_str_radix_float("1e40", 10); + assert_eq!(fe, Some(Float::infinity())) + } + + #[test] + fn test_from_str_radix_float() { + let x1 : Option = from_str_radix_float("-123.456", 10); + assert_eq!(x1, Some(-123.456)); + let x2 : Option = from_str_radix_float("123.456", 10); + assert_eq!(x2, Some(123.456)); + let x3 : Option = from_str_radix_float("-0.0", 10); + assert_eq!(x3, Some(-0.0)); + let x4 : Option = from_str_radix_float("0.0", 10); + assert_eq!(x4, Some(0.0)); + let x4 : Option = from_str_radix_float("1.0", 10); + assert_eq!(x4, Some(1.0)); + let x5 : Option = from_str_radix_float("-1.0", 10); + assert_eq!(x5, Some(-1.0)); + } +} diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 2a94f851646..4977e5d6680 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -23,4 +23,20 @@ pub const MIN: $T = 0 as $T; #[unstable] pub const MAX: $T = 0 as $T - 1 as $T; +#[experimental = "might need to return Result"] +impl ::str::FromStr for $T { + #[inline] + fn from_str(s: &str) -> ::option::Option<$T> { + ::num::strconv::from_str_radix_int(s, 10) + } +} + +#[experimental = "might need to return Result"] +impl ::num::FromStrRadix for $T { + #[inline] + fn from_str_radix(s: &str, radix: uint) -> ::option::Option<$T> { + ::num::strconv::from_str_radix_int(s, radix) + } +} + )) diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 60012ab149f..101eb7ac74c 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -41,6 +41,7 @@ pub use ops::{Fn, FnMut, FnOnce}; // Reexported functions pub use iter::{range, repeat}; pub use mem::drop; +pub use str::from_str; // Reexported types and traits diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 745de5f179e..ab4e50c58d9 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -31,6 +31,42 @@ use raw::Repr; use slice::{mod, SlicePrelude}; use uint; +/// A trait to abstract the idea of creating a new instance of a type from a +/// string. +#[experimental = "might need to return Result"] +pub trait FromStr { + /// Parses a string `s` to return an optional value of this type. If the + /// string is ill-formatted, the None is returned. + fn from_str(s: &str) -> Option; +} + +/// A utility function that just calls FromStr::from_str +pub fn from_str(s: &str) -> Option { + FromStr::from_str(s) +} + +impl FromStr for bool { + /// Parse a `bool` from a string. + /// + /// Yields an `Option`, because `s` may or may not actually be parseable. + /// + /// # Examples + /// + /// ```rust + /// assert_eq!(from_str::("true"), Some(true)); + /// assert_eq!(from_str::("false"), Some(false)); + /// assert_eq!(from_str::("not even a boolean"), None); + /// ``` + #[inline] + fn from_str(s: &str) -> Option { + match s { + "true" => Some(true), + "false" => Some(false), + _ => None, + } + } +} + /* Section: Creating a string */ diff --git a/src/libcoretest/num/int_macros.rs b/src/libcoretest/num/int_macros.rs index 5e2530ef2a9..e25f10bd0da 100644 --- a/src/libcoretest/num/int_macros.rs +++ b/src/libcoretest/num/int_macros.rs @@ -15,7 +15,8 @@ macro_rules! int_module (($T:ty, $T_i:ident) => ( mod tests { use core::$T_i::*; use core::int; - use core::num::{Int, SignedInt}; + use core::num::{FromStrRadix, Int, SignedInt}; + use core::str::from_str; use num; #[test] @@ -156,6 +157,49 @@ mod tests { assert!(5i.checked_div(0) == None); assert!(int::MIN.checked_div(-1) == None); } + + #[test] + fn test_from_str() { + assert_eq!(from_str::<$T>("0"), Some(0 as $T)); + assert_eq!(from_str::<$T>("3"), Some(3 as $T)); + assert_eq!(from_str::<$T>("10"), Some(10 as $T)); + assert_eq!(from_str::("123456789"), Some(123456789 as i32)); + assert_eq!(from_str::<$T>("00100"), Some(100 as $T)); + + assert_eq!(from_str::<$T>("-1"), Some(-1 as $T)); + assert_eq!(from_str::<$T>("-3"), Some(-3 as $T)); + assert_eq!(from_str::<$T>("-10"), Some(-10 as $T)); + assert_eq!(from_str::("-123456789"), Some(-123456789 as i32)); + assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T)); + + assert_eq!(from_str::<$T>(""), None); + assert_eq!(from_str::<$T>(" "), None); + assert_eq!(from_str::<$T>("x"), None); + } + + #[test] + fn test_from_str_radix() { + assert_eq!(FromStrRadix::from_str_radix("123", 10), Some(123 as $T)); + assert_eq!(FromStrRadix::from_str_radix("1001", 2), Some(9 as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 8), Some(83 as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 16), Some(291 as i32)); + assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Some(65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("FFFF", 16), Some(65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("z", 36), Some(35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("Z", 36), Some(35 as $T)); + + assert_eq!(FromStrRadix::from_str_radix("-123", 10), Some(-123 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-1001", 2), Some(-9 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-123", 8), Some(-83 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-123", 16), Some(-291 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-ffff", 16), Some(-65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-FFFF", 16), Some(-65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-z", 36), Some(-35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-Z", 36), Some(-35 as $T)); + + assert_eq!(FromStrRadix::from_str_radix("Z", 35), None::<$T>); + assert_eq!(FromStrRadix::from_str_radix("-9", 2), None::<$T>); + } } )) diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 38502321c1d..0cd1ded21d6 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -45,3 +45,73 @@ pub fn test_num(ten: T, two: T) where assert_eq!(ten.div(&two), ten / two); assert_eq!(ten.rem(&two), ten % two); } + +#[cfg(test)] +mod test { + use core::option::{Option, Some, None}; + use core::num::Float; + use core::num::from_str_radix; + + #[test] + fn from_str_issue7588() { + let u : Option = from_str_radix("1000", 10); + assert_eq!(u, None); + let s : Option = from_str_radix("80000", 10); + assert_eq!(s, None); + let f : Option = from_str_radix("10000000000000000000000000000000000000000", 10); + assert_eq!(f, Some(Float::infinity())) + let fe : Option = from_str_radix("1e40", 10); + assert_eq!(fe, Some(Float::infinity())) + } + + #[test] + fn test_from_str_radix_float() { + let x1 : Option = from_str_radix("-123.456", 10); + assert_eq!(x1, Some(-123.456)); + let x2 : Option = from_str_radix("123.456", 10); + assert_eq!(x2, Some(123.456)); + let x3 : Option = from_str_radix("-0.0", 10); + assert_eq!(x3, Some(-0.0)); + let x4 : Option = from_str_radix("0.0", 10); + assert_eq!(x4, Some(0.0)); + let x4 : Option = from_str_radix("1.0", 10); + assert_eq!(x4, Some(1.0)); + let x5 : Option = from_str_radix("-1.0", 10); + assert_eq!(x5, Some(-1.0)); + } + + #[test] + fn test_int_from_str_overflow() { + let mut i8_val: i8 = 127_i8; + assert_eq!(from_str::("127"), Some(i8_val)); + assert_eq!(from_str::("128"), None); + + i8_val += 1 as i8; + assert_eq!(from_str::("-128"), Some(i8_val)); + assert_eq!(from_str::("-129"), None); + + let mut i16_val: i16 = 32_767_i16; + assert_eq!(from_str::("32767"), Some(i16_val)); + assert_eq!(from_str::("32768"), None); + + i16_val += 1 as i16; + assert_eq!(from_str::("-32768"), Some(i16_val)); + assert_eq!(from_str::("-32769"), None); + + let mut i32_val: i32 = 2_147_483_647_i32; + assert_eq!(from_str::("2147483647"), Some(i32_val)); + assert_eq!(from_str::("2147483648"), None); + + i32_val += 1 as i32; + assert_eq!(from_str::("-2147483648"), Some(i32_val)); + assert_eq!(from_str::("-2147483649"), None); + + let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; + assert_eq!(from_str::("9223372036854775807"), Some(i64_val)); + assert_eq!(from_str::("9223372036854775808"), None); + + i64_val += 1 as i64; + assert_eq!(from_str::("-9223372036854775808"), Some(i64_val)); + assert_eq!(from_str::("-9223372036854775809"), None); + } +} diff --git a/src/libcoretest/str.rs b/src/libcoretest/str.rs index d3f77c47c44..5f44fd807cc 100644 --- a/src/libcoretest/str.rs +++ b/src/libcoretest/str.rs @@ -8,6 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[test] +fn test_bool_from_str() { + assert_eq!(from_str::("true"), Some(true)); + assert_eq!(from_str::("false"), Some(false)); + assert_eq!(from_str::("not even a boolean"), None); +} + fn check_contains_all_substrings(s: &str) { assert!(s.contains("")); for i in range(0, s.len()) { diff --git a/src/libregex/re.rs b/src/libregex/re.rs index df5bfccd18d..c7540852970 100644 --- a/src/libregex/re.rs +++ b/src/libregex/re.rs @@ -10,7 +10,6 @@ use std::collections::HashMap; use std::fmt; -use std::from_str::from_str; use std::str::{MaybeOwned, Owned, Slice}; use compile::Program; diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index 8c1d7c839ac..10cf92e32c3 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -334,8 +334,7 @@ macro_rules! cgoptions( } fn parse_uint(slot: &mut uint, v: Option<&str>) -> bool { - use std::from_str::FromStr; - match v.and_then(FromStr::from_str) { + match v.and_then(from_str) { Some(i) => { *slot = i; true }, None => false } diff --git a/src/librustc/driver/pretty.rs b/src/librustc/driver/pretty.rs index 0a7cfdeeadc..7b6de088319 100644 --- a/src/librustc/driver/pretty.rs +++ b/src/librustc/driver/pretty.rs @@ -31,8 +31,8 @@ use syntax::print::{pp, pprust}; use graphviz as dot; use std::io::{mod, MemReader}; -use std::from_str::FromStr; use std::option; +use std::str::FromStr; use arena::TypedArena; #[deriving(PartialEq, Show)] diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 524638155ac..56e90da533c 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -200,7 +200,7 @@ use std::{char, f64, fmt, io, num, str}; use std::io::MemWriter; use std::mem::{swap, transmute}; use std::num::{Float, FPNaN, FPInfinite, Int}; -use std::str::ScalarValue; +use std::str::{FromStr, ScalarValue}; use std::string; use std::vec::Vec; use std::ops; @@ -1988,7 +1988,7 @@ macro_rules! read_primitive { String(s) => { // re: #12967.. a type w/ numeric keys (ie HashMap etc) // is going to have a string here, as per JSON spec. - match std::from_str::from_str(s.as_slice()) { + match std::str::from_str(s.as_slice()) { Some(f) => Ok(f), None => Err(ExpectedError("Number".to_string(), s)), } @@ -2027,7 +2027,7 @@ impl ::Decoder for Decoder { String(s) => { // re: #12967.. a type w/ numeric keys (ie HashMap etc) // is going to have a string here, as per JSON spec. - match std::from_str::from_str(s.as_slice()) { + match std::str::from_str(s.as_slice()) { Some(f) => Ok(f), None => Err(ExpectedError("Number".to_string(), s)), } @@ -2395,7 +2395,7 @@ impl fmt::Show for Json { } } -impl std::from_str::FromStr for Json { +impl FromStr for Json { fn from_str(s: &str) -> Option { from_str(s).ok() } @@ -2480,7 +2480,7 @@ mod tests { #[test] fn test_from_str_trait() { let s = "null"; - assert!(::std::from_str::from_str::(s).unwrap() == from_str(s).unwrap()); + assert!(::std::str::from_str::(s).unwrap() == from_str(s).unwrap()); } #[test] diff --git a/src/libstd/from_str.rs b/src/libstd/from_str.rs deleted file mode 100644 index 21b1e0560a5..00000000000 --- a/src/libstd/from_str.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The `FromStr` trait for types that can be created from strings - -#![experimental] - -use option::{Option, Some, None}; -use string::String; - -/// A trait to abstract the idea of creating a new instance of a type from a -/// string. -#[experimental = "might need to return Result"] -pub trait FromStr { - /// Parses a string `s` to return an optional value of this type. If the - /// string is ill-formatted, the None is returned. - fn from_str(s: &str) -> Option; -} - -/// A utility function that just calls FromStr::from_str -pub fn from_str(s: &str) -> Option { - FromStr::from_str(s) -} - -impl FromStr for bool { - /// Parse a `bool` from a string. - /// - /// Yields an `Option`, because `s` may or may not actually be parseable. - /// - /// # Examples - /// - /// ```rust - /// assert_eq!(from_str::("true"), Some(true)); - /// assert_eq!(from_str::("false"), Some(false)); - /// assert_eq!(from_str::("not even a boolean"), None); - /// ``` - #[inline] - fn from_str(s: &str) -> Option { - match s { - "true" => Some(true), - "false" => Some(false), - _ => None, - } - } -} - -impl FromStr for String { - #[inline] - fn from_str(s: &str) -> Option { - Some(String::from_str(s)) - } -} - -#[cfg(test)] -mod test { - use prelude::*; - - #[test] - fn test_bool_from_str() { - assert_eq!(from_str::("true"), Some(true)); - assert_eq!(from_str::("false"), Some(false)); - assert_eq!(from_str::("not even a boolean"), None); - } -} diff --git a/src/libstd/io/net/ip.rs b/src/libstd/io/net/ip.rs index 2a2d978ef49..7ba5e173182 100644 --- a/src/libstd/io/net/ip.rs +++ b/src/libstd/io/net/ip.rs @@ -16,13 +16,12 @@ #![allow(missing_docs)] use fmt; -use from_str::FromStr; use io::{mod, IoResult, IoError}; use io::net; use iter::Iterator; use option::{Option, None, Some}; use result::{Ok, Err}; -use str::StrPrelude; +use str::{FromStr, StrPrelude}; use slice::{CloneSlicePrelude, SlicePrelude}; use vec::Vec; @@ -540,7 +539,7 @@ impl<'a> ToSocketAddr for &'a str { mod test { use prelude::*; use super::*; - use from_str::FromStr; + use str::FromStr; #[test] fn test_from_str_ipv4() { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3940d7db66e..4e063223329 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -54,7 +54,7 @@ //! //! For converting to strings use the [`format!`](fmt/index.html) //! macro, and for converting from strings use the -//! [`FromStr`](from_str/index.html) trait. +//! [`FromStr`](str/trait.FromStr.html) trait. //! //! ## Platform abstractions //! @@ -219,7 +219,6 @@ pub mod time; /* Common traits */ pub mod error; -pub mod from_str; pub mod num; pub mod to_string; diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 3f46cc8af50..207fa649930 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -17,12 +17,10 @@ use prelude::*; -use from_str::FromStr; use intrinsics; use libc::c_int; use num::{Float, FloatMath}; use num::strconv; -use num; pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE}; pub use core::f32::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP}; @@ -339,68 +337,6 @@ pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> String { r } -#[inline] -#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] -pub fn from_str_hex(src: &str) -> Option { - strconv::from_str_radix_float(src, 16) -} - -impl FromStr for f32 { - /// Convert a string in base 10 to a float. - /// Accepts an optional decimal exponent. - /// - /// This function accepts strings such as - /// - /// * '3.14' - /// * '+3.14', equivalent to '3.14' - /// * '-3.14' - /// * '2.5E10', or equivalently, '2.5e10' - /// * '2.5E-10' - /// * '.' (understood as 0) - /// * '5.' - /// * '.5', or, equivalently, '0.5' - /// * '+inf', 'inf', '-inf', 'NaN' - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Arguments - /// - /// * src - A string - /// - /// # Return value - /// - /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. - #[inline] - fn from_str(src: &str) -> Option { - strconv::from_str_radix_float(src, 10u) - } -} - -impl num::FromStrRadix for f32 { - /// Convert a string in a given base to a float. - /// - /// Due to possible conflicts, this function does **not** accept - /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** - /// does it recognize exponents of any kind. - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Arguments - /// - /// * src - A string - /// * radix - The base to use. Must lie in the range [2 .. 36] - /// - /// # Return value - /// - /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. - #[inline] - fn from_str_radix(src: &str, radix: uint) -> Option { - strconv::from_str_radix_float(src, radix) - } -} - #[cfg(test)] mod tests { use f32::*; diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 4d691fc9676..543d50596e8 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -16,12 +16,10 @@ use prelude::*; -use from_str::FromStr; use intrinsics; use libc::c_int; use num::{Float, FloatMath}; use num::strconv; -use num; pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE}; pub use core::f64::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP}; @@ -347,63 +345,6 @@ pub fn to_str_exp_digits(num: f64, dig: uint, upper: bool) -> String { r } -#[inline] -#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] -pub fn from_str_hex(src: &str) -> Option { - strconv::from_str_radix_float(src, 16) -} - -impl FromStr for f64 { - /// Convert a string in base 10 to a float. - /// Accepts an optional decimal exponent. - /// - /// This function accepts strings such as: - /// - /// * '3.14' - /// * '-3.14' - /// * '2.5E10', or equivalently, '2.5e10' - /// * '2.5E-10' - /// * '.' (understood as 0) - /// * '5.' - /// * '.5', or, equivalently, '0.5' - /// * inf', '-inf', 'NaN' - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Arguments - /// - /// * src - A string - /// - /// # Return value - /// - /// `none` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. - #[inline] - fn from_str(src: &str) -> Option { - strconv::from_str_radix_float(src, 10u) - } -} - -impl num::FromStrRadix for f64 { - /// Convert a string in a given base to a float. - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Arguments - /// - /// * src - A string - /// * radix - The base to use. Must lie in the range [2 .. 36] - /// - /// # Return value - /// - /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. - #[inline] - fn from_str_radix(src: &str, radix: uint) -> Option { - strconv::from_str_radix_float(src, radix) - } -} - #[cfg(test)] mod tests { use f64::*; diff --git a/src/libstd/num/i16.rs b/src/libstd/num/i16.rs index d7732b474db..6455c10736a 100644 --- a/src/libstd/num/i16.rs +++ b/src/libstd/num/i16.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "i16")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::i16::{BITS, BYTES, MIN, MAX}; int_module!(i16) diff --git a/src/libstd/num/i32.rs b/src/libstd/num/i32.rs index 778f1c6748c..39b179c8274 100644 --- a/src/libstd/num/i32.rs +++ b/src/libstd/num/i32.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "i32")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::i32::{BITS, BYTES, MIN, MAX}; int_module!(i32) diff --git a/src/libstd/num/i64.rs b/src/libstd/num/i64.rs index ae3d57eeac6..a0c474c479a 100644 --- a/src/libstd/num/i64.rs +++ b/src/libstd/num/i64.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "i64")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::i64::{BITS, BYTES, MIN, MAX}; int_module!(i64) diff --git a/src/libstd/num/i8.rs b/src/libstd/num/i8.rs index 8a3f379893c..e911ed1de9a 100644 --- a/src/libstd/num/i8.rs +++ b/src/libstd/num/i8.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "i8")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::i8::{BITS, BYTES, MIN, MAX}; int_module!(i8) diff --git a/src/libstd/num/int.rs b/src/libstd/num/int.rs index 51af04b32d4..36c021efe0a 100644 --- a/src/libstd/num/int.rs +++ b/src/libstd/num/int.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "int")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::int::{BITS, BYTES, MIN, MAX}; int_module!(int) diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 9ae146c840a..2f1162d28e5 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -14,131 +14,4 @@ macro_rules! int_module (($T:ty) => ( -#[experimental = "might need to return Result"] -impl FromStr for $T { - #[inline] - fn from_str(s: &str) -> Option<$T> { - strconv::from_str_radix_int(s, 10) - } -} - -#[experimental = "might need to return Result"] -impl FromStrRadix for $T { - #[inline] - fn from_str_radix(s: &str, radix: uint) -> Option<$T> { - strconv::from_str_radix_int(s, radix) - } -} - -#[cfg(test)] -mod tests { - use prelude::*; - use num::FromStrRadix; - - #[test] - fn test_from_str() { - assert_eq!(from_str::<$T>("0"), Some(0 as $T)); - assert_eq!(from_str::<$T>("3"), Some(3 as $T)); - assert_eq!(from_str::<$T>("10"), Some(10 as $T)); - assert_eq!(from_str::("123456789"), Some(123456789 as i32)); - assert_eq!(from_str::<$T>("00100"), Some(100 as $T)); - - assert_eq!(from_str::<$T>("-1"), Some(-1 as $T)); - assert_eq!(from_str::<$T>("-3"), Some(-3 as $T)); - assert_eq!(from_str::<$T>("-10"), Some(-10 as $T)); - assert_eq!(from_str::("-123456789"), Some(-123456789 as i32)); - assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T)); - - assert_eq!(from_str::<$T>(""), None); - assert_eq!(from_str::<$T>(" "), None); - assert_eq!(from_str::<$T>("x"), None); - } - - #[test] - fn test_from_str_radix() { - assert_eq!(FromStrRadix::from_str_radix("123", 10), Some(123 as $T)); - assert_eq!(FromStrRadix::from_str_radix("1001", 2), Some(9 as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 8), Some(83 as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 16), Some(291 as i32)); - assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Some(65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("FFFF", 16), Some(65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("z", 36), Some(35 as $T)); - assert_eq!(FromStrRadix::from_str_radix("Z", 36), Some(35 as $T)); - - assert_eq!(FromStrRadix::from_str_radix("-123", 10), Some(-123 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-1001", 2), Some(-9 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-123", 8), Some(-83 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-123", 16), Some(-291 as i32)); - assert_eq!(FromStrRadix::from_str_radix("-ffff", 16), Some(-65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("-FFFF", 16), Some(-65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("-z", 36), Some(-35 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-Z", 36), Some(-35 as $T)); - - assert_eq!(FromStrRadix::from_str_radix("Z", 35), None::<$T>); - assert_eq!(FromStrRadix::from_str_radix("-9", 2), None::<$T>); - } - - #[test] - fn test_int_to_str_overflow() { - let mut i8_val: i8 = 127_i8; - assert_eq!(i8_val.to_string(), "127".to_string()); - - i8_val += 1 as i8; - assert_eq!(i8_val.to_string(), "-128".to_string()); - - let mut i16_val: i16 = 32_767_i16; - assert_eq!(i16_val.to_string(), "32767".to_string()); - - i16_val += 1 as i16; - assert_eq!(i16_val.to_string(), "-32768".to_string()); - - let mut i32_val: i32 = 2_147_483_647_i32; - assert_eq!(i32_val.to_string(), "2147483647".to_string()); - - i32_val += 1 as i32; - assert_eq!(i32_val.to_string(), "-2147483648".to_string()); - - let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; - assert_eq!(i64_val.to_string(), "9223372036854775807".to_string()); - - i64_val += 1 as i64; - assert_eq!(i64_val.to_string(), "-9223372036854775808".to_string()); - } - - #[test] - fn test_int_from_str_overflow() { - let mut i8_val: i8 = 127_i8; - assert_eq!(from_str::("127"), Some(i8_val)); - assert_eq!(from_str::("128"), None); - - i8_val += 1 as i8; - assert_eq!(from_str::("-128"), Some(i8_val)); - assert_eq!(from_str::("-129"), None); - - let mut i16_val: i16 = 32_767_i16; - assert_eq!(from_str::("32767"), Some(i16_val)); - assert_eq!(from_str::("32768"), None); - - i16_val += 1 as i16; - assert_eq!(from_str::("-32768"), Some(i16_val)); - assert_eq!(from_str::("-32769"), None); - - let mut i32_val: i32 = 2_147_483_647_i32; - assert_eq!(from_str::("2147483647"), Some(i32_val)); - assert_eq!(from_str::("2147483648"), None); - - i32_val += 1 as i32; - assert_eq!(from_str::("-2147483648"), Some(i32_val)); - assert_eq!(from_str::("-2147483649"), None); - - let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; - assert_eq!(from_str::("9223372036854775807"), Some(i64_val)); - assert_eq!(from_str::("9223372036854775808"), None); - - i64_val += 1 as i64; - assert_eq!(from_str::("-9223372036854775808"), Some(i64_val)); - assert_eq!(from_str::("-9223372036854775809"), None); - } -} - )) diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 0afc8ce0452..73fd2ccd2d3 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -16,8 +16,6 @@ #![experimental] #![allow(missing_docs)] -use option::Option; - #[cfg(test)] use cmp::PartialEq; #[cfg(test)] use fmt::Show; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; @@ -31,6 +29,7 @@ pub use core::num::{checked_next_power_of_two}; pub use core::num::{from_int, from_i8, from_i16, from_i32, from_i64}; pub use core::num::{from_uint, from_u8, from_u16, from_u32, from_u64}; pub use core::num::{from_f32, from_f64}; +pub use core::num::{FromStrRadix, from_str_radix}; pub use core::num::{FPCategory, FPNaN, FPInfinite, FPZero, FPSubnormal}; pub use core::num::{FPNormal, Float}; @@ -115,18 +114,6 @@ pub trait FloatMath: Float { fn atanh(self) -> Self; } -/// A generic trait for converting a string with a radix (base) to a value -#[experimental = "might need to return Result"] -pub trait FromStrRadix { - fn from_str_radix(str: &str, radix: uint) -> Option; -} - -/// A utility function that just calls FromStrRadix::from_str_radix. -#[experimental = "might need to return Result"] -pub fn from_str_radix(str: &str, radix: uint) -> Option { - FromStrRadix::from_str_radix(str, radix) -} - // DEPRECATED #[deprecated = "Use `FloatMath::abs_sub`"] diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index fff31b332e1..31096c0aa46 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -13,12 +13,8 @@ #![allow(missing_docs)] use char; -use char::Char; -use from_str::from_str; -use iter::Iterator; use num; use num::{Int, Float, FPNaN, FPInfinite, ToPrimitive}; -use option::{None, Option, Some}; use slice::{SlicePrelude, CloneSliceAllocPrelude}; use str::StrPrelude; use string::String; @@ -425,242 +421,35 @@ pub fn float_to_str_common( static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u; static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; -pub fn from_str_radix_float(src: &str, radix: uint) -> Option { - assert!(radix >= 2 && radix <= 36, - "from_str_radix_float: must lie in the range `[2, 36]` - found {}", - radix); - - let _0: T = Float::zero(); - let _1: T = Float::one(); - let radix_t: T = num::cast(radix as int).unwrap(); - - // Special values - match src { - "inf" => return Some(Float::infinity()), - "-inf" => return Some(Float::neg_infinity()), - "NaN" => return Some(Float::nan()), - _ => {}, - } - - let (is_positive, src) = match src.slice_shift_char() { - (None, _) => return None, - (Some('-'), "") => return None, - (Some('-'), src) => (false, src), - (Some(_), _) => (true, src), - }; - - // The significand to accumulate - let mut sig = if is_positive { _0 } else { -_0 }; - // Necessary to detect overflow - let mut prev_sig = sig; - let mut cs = src.chars().enumerate(); - // Exponent prefix and exponent index offset - let mut exp_info = None::<(char, uint)>; - - // Parse the integer part of the significand - for (i, c) in cs { - match c.to_digit(radix) { - Some(digit) => { - // shift significand one digit left - sig = sig * radix_t; - - // add/subtract current digit depending on sign - if is_positive { - sig = sig + num::cast(digit as int).unwrap(); - } else { - sig = sig - num::cast(digit as int).unwrap(); - } - - // Detect overflow by comparing to last value, except - // if we've not seen any non-zero digits. - if prev_sig != _0 { - if is_positive && sig <= prev_sig - { return Some(Float::infinity()); } - if !is_positive && sig >= prev_sig - { return Some(Float::neg_infinity()); } - - // Detect overflow by reversing the shift-and-add process - let digit: T = num::cast(digit as int).unwrap(); - if is_positive && (prev_sig != ((sig - digit) / radix_t)) - { return Some(Float::infinity()); } - if !is_positive && (prev_sig != ((sig + digit) / radix_t)) - { return Some(Float::neg_infinity()); } - } - prev_sig = sig; - }, - None => match c { - 'e' | 'E' | 'p' | 'P' => { - exp_info = Some((c, i + 1)); - break; // start of exponent - }, - '.' => { - break; // start of fractional part - }, - _ => { - return None; - }, - }, - } - } - - // If we are not yet at the exponent parse the fractional - // part of the significand - if exp_info.is_none() { - let mut power = _1; - for (i, c) in cs { - match c.to_digit(radix) { - Some(digit) => { - let digit: T = num::cast(digit).unwrap(); - // Decrease power one order of magnitude - power = power / radix_t; - // add/subtract current digit depending on sign - sig = if is_positive { - sig + digit * power - } else { - sig - digit * power - }; - // Detect overflow by comparing to last value - if is_positive && sig < prev_sig - { return Some(Float::infinity()); } - if !is_positive && sig > prev_sig - { return Some(Float::neg_infinity()); } - prev_sig = sig; - }, - None => match c { - 'e' | 'E' | 'p' | 'P' => { - exp_info = Some((c, i + 1)); - break; // start of exponent - }, - _ => { - return None; // invalid number - }, - }, - } - } - } - - // Parse and calculate the exponent - let exp = match exp_info { - Some((c, offset)) => { - let base: T = match c { - 'E' | 'e' if radix == 10 => num::cast(10u).unwrap(), - 'P' | 'p' if radix == 16 => num::cast(2u).unwrap(), - _ => return None, - }; - - // Parse the exponent as decimal integer - let src = src[offset..]; - let (is_positive, exp) = match src.slice_shift_char() { - (Some('-'), src) => (false, from_str::(src)), - (Some('+'), src) => (true, from_str::(src)), - (Some(_), _) => (true, from_str::(src)), - (None, _) => return None, - }; - - match (is_positive, exp) { - (true, Some(exp)) => base.powi(exp as i32), - (false, Some(exp)) => _1 / base.powi(exp as i32), - (_, None) => return None, - } - }, - None => _1, // no exponent - }; - - Some(sig * exp) -} - -pub fn from_str_radix_int(src: &str, radix: uint) -> Option { - assert!(radix >= 2 && radix <= 36, - "from_str_radix_int: must lie in the range `[2, 36]` - found {}", - radix); - - fn cast(x: uint) -> T { - num::cast(x).unwrap() - } - - let _0: T = Int::zero(); - let _1: T = Int::one(); - let is_signed = _0 > Int::min_value(); - - let (is_positive, src) = match src.slice_shift_char() { - (Some('-'), src) if is_signed => (false, src), - (Some(_), _) => (true, src), - (None, _) => return None, - }; - - let mut xs = src.chars().map(|c| { - c.to_digit(radix).map(cast) - }); - let radix = cast(radix); - let mut result = _0; - - if is_positive { - for x in xs { - let x = match x { - Some(x) => x, - None => return None, - }; - result = match result.checked_mul(radix) { - Some(result) => result, - None => return None, - }; - result = match result.checked_add(x) { - Some(result) => result, - None => return None, - }; - } - } else { - for x in xs { - let x = match x { - Some(x) => x, - None => return None, - }; - result = match result.checked_mul(radix) { - Some(result) => result, - None => return None, - }; - result = match result.checked_sub(x) { - Some(result) => result, - None => return None, - }; - } - } - - Some(result) -} - #[cfg(test)] -mod test { - use super::*; - use option::*; - use num::Float; +mod tests { + use to_string::ToString; #[test] - fn from_str_issue7588() { - let u : Option = from_str_radix_int("1000", 10); - assert_eq!(u, None); - let s : Option = from_str_radix_int("80000", 10); - assert_eq!(s, None); - let f : Option = from_str_radix_float("10000000000000000000000000000000000000000", 10); - assert_eq!(f, Some(Float::infinity())) - let fe : Option = from_str_radix_float("1e40", 10); - assert_eq!(fe, Some(Float::infinity())) - } + fn test_int_to_str_overflow() { + let mut i8_val: i8 = 127_i8; + assert_eq!(i8_val.to_string(), "127".to_string()); - #[test] - fn test_from_str_radix_float() { - let x1 : Option = from_str_radix_float("-123.456", 10); - assert_eq!(x1, Some(-123.456)); - let x2 : Option = from_str_radix_float("123.456", 10); - assert_eq!(x2, Some(123.456)); - let x3 : Option = from_str_radix_float("-0.0", 10); - assert_eq!(x3, Some(-0.0)); - let x4 : Option = from_str_radix_float("0.0", 10); - assert_eq!(x4, Some(0.0)); - let x4 : Option = from_str_radix_float("1.0", 10); - assert_eq!(x4, Some(1.0)); - let x5 : Option = from_str_radix_float("-1.0", 10); - assert_eq!(x5, Some(-1.0)); + i8_val += 1 as i8; + assert_eq!(i8_val.to_string(), "-128".to_string()); + + let mut i16_val: i16 = 32_767_i16; + assert_eq!(i16_val.to_string(), "32767".to_string()); + + i16_val += 1 as i16; + assert_eq!(i16_val.to_string(), "-32768".to_string()); + + let mut i32_val: i32 = 2_147_483_647_i32; + assert_eq!(i32_val.to_string(), "2147483647".to_string()); + + i32_val += 1 as i32; + assert_eq!(i32_val.to_string(), "-2147483648".to_string()); + + let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; + assert_eq!(i64_val.to_string(), "9223372036854775807".to_string()); + + i64_val += 1 as i64; + assert_eq!(i64_val.to_string(), "-9223372036854775808".to_string()); } } diff --git a/src/libstd/num/u16.rs b/src/libstd/num/u16.rs index bb619b5b2f5..246224ddb2b 100644 --- a/src/libstd/num/u16.rs +++ b/src/libstd/num/u16.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "u16")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::u16::{BITS, BYTES, MIN, MAX}; uint_module!(u16) diff --git a/src/libstd/num/u32.rs b/src/libstd/num/u32.rs index 754103ba5da..143b45010c2 100644 --- a/src/libstd/num/u32.rs +++ b/src/libstd/num/u32.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "u32")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::u32::{BITS, BYTES, MIN, MAX}; uint_module!(u32) diff --git a/src/libstd/num/u64.rs b/src/libstd/num/u64.rs index da497d2cbe4..92c5380f980 100644 --- a/src/libstd/num/u64.rs +++ b/src/libstd/num/u64.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "u64")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::u64::{BITS, BYTES, MIN, MAX}; uint_module!(u64) diff --git a/src/libstd/num/u8.rs b/src/libstd/num/u8.rs index bdfcdb2c5a5..faa6d167065 100644 --- a/src/libstd/num/u8.rs +++ b/src/libstd/num/u8.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "u8")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::u8::{BITS, BYTES, MIN, MAX}; uint_module!(u8) diff --git a/src/libstd/num/uint.rs b/src/libstd/num/uint.rs index 5090219d3de..a425aab3aa1 100644 --- a/src/libstd/num/uint.rs +++ b/src/libstd/num/uint.rs @@ -13,11 +13,6 @@ #![unstable] #![doc(primitive = "uint")] -use from_str::FromStr; -use num::FromStrRadix; -use num::strconv; -use option::Option; - pub use core::uint::{BITS, BYTES, MIN, MAX}; uint_module!(uint) diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index aa8e58bab02..ef9e809ed2b 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -15,22 +15,6 @@ macro_rules! uint_module (($T:ty) => ( -#[experimental = "might need to return Result"] -impl FromStr for $T { - #[inline] - fn from_str(s: &str) -> Option<$T> { - strconv::from_str_radix_int(s, 10) - } -} - -#[experimental = "might need to return Result"] -impl FromStrRadix for $T { - #[inline] - fn from_str_radix(s: &str, radix: uint) -> Option<$T> { - strconv::from_str_radix_int(s, radix) - } -} - // String conversion functions and impl num -> str /// Convert to a string as a byte slice in a given base. diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index 794f6978642..e2ff824a7c9 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -13,12 +13,11 @@ use c_str::{CString, ToCStr}; use clone::Clone; use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; -use from_str::FromStr; use hash; use io::Writer; use iter::{DoubleEndedIterator, AdditiveIterator, Extend, Iterator, Map}; use option::{Option, None, Some}; -use str::Str; +use str::{FromStr, Str}; use str; use slice::{CloneSliceAllocPrelude, Splits, AsSlice, VectorVector, PartialEqSlicePrelude, SlicePrelude}; diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 2da2159653e..b8016e3e8f4 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -16,14 +16,13 @@ use ascii::AsciiCast; use c_str::{CString, ToCStr}; use clone::Clone; use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; -use from_str::FromStr; use hash; use io::Writer; use iter::{AdditiveIterator, DoubleEndedIterator, Extend, Iterator, Map}; use mem; use option::{Option, Some, None}; use slice::{AsSlice, SlicePrelude}; -use str::{CharSplits, Str, StrAllocating, StrVector, StrPrelude}; +use str::{CharSplits, FromStr, Str, StrAllocating, StrVector, StrPrelude}; use string::String; use unicode::char::UnicodeChar; use vec::Vec; diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 158e7a59f6d..4ab09a2a864 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -50,9 +50,9 @@ #[doc(no_inline)] pub use ops::{Fn, FnMut, FnOnce}; // Reexported functions -#[doc(no_inline)] pub use from_str::from_str; #[doc(no_inline)] pub use iter::{range, repeat}; #[doc(no_inline)] pub use mem::drop; +#[doc(no_inline)] pub use str::from_str; // Reexported types and traits diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs index b08b92b8587..8b457d1639d 100644 --- a/src/libstd/rt/backtrace.rs +++ b/src/libstd/rt/backtrace.rs @@ -12,13 +12,12 @@ #![allow(non_camel_case_types)] -use from_str::from_str; use io::{IoResult, Writer}; use iter::Iterator; use option::{Some, None}; use os; use result::{Ok, Err}; -use str::StrPrelude; +use str::{StrPrelude, from_str}; use sync::atomic; use unicode::char::UnicodeChar; diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 56f2dbf667a..92657d1b59b 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use from_str::FromStr; -use from_str::from_str; use libc::uintptr_t; use option::{Some, None, Option}; use os; -use str::Str; +use str::{FromStr, from_str, Str}; use sync::atomic; /// Dynamically inquire about whether we're running under V. diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 986f90389e7..ff96f806fac 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -53,13 +53,13 @@ use std::cmp; use std::f64; use std::fmt::Show; use std::fmt; -use std::from_str::FromStr; use std::io::fs::PathExtensions; use std::io::stdio::StdWriter; use std::io::{File, ChanReader, ChanWriter}; use std::io; use std::num::{Float, FloatMath, Int}; use std::os; +use std::str::FromStr; use std::string::String; use std::task::TaskBuilder; use std::time::Duration; From 68bd495f0b2355e390c5dc382e17d056c113d069 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 15 Nov 2014 17:02:38 +1100 Subject: [PATCH 17/23] Remove core::num::strconv --- src/libcore/num/f32.rs | 64 +------- src/libcore/num/f64.rs | 59 +------ src/libcore/num/int_macros.rs | 16 -- src/libcore/num/mod.rs | 279 ++++++++++++++++++++++++++++++++- src/libcore/num/strconv.rs | 259 ------------------------------ src/libcore/num/uint_macros.rs | 16 -- 6 files changed, 282 insertions(+), 411 deletions(-) delete mode 100644 src/libcore/num/strconv.rs diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index c674a806836..e7b0f626bf8 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -16,10 +16,8 @@ use intrinsics; use mem; -use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; -use num::{Float, FromStrRadix}; -use num::strconv; -use str::FromStr; +use num::{Float, FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; +use num::from_str_radix; use option::Option; pub const RADIX: uint = 2u; @@ -431,61 +429,5 @@ impl Float for f32 { #[allow(missing_docs)] #[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] pub fn from_str_hex(src: &str) -> Option { - strconv::from_str_radix_float(src, 16) -} - -impl FromStr for f32 { - /// Convert a string in base 10 to a float. - /// Accepts an optional decimal exponent. - /// - /// This function accepts strings such as - /// - /// * '3.14' - /// * '+3.14', equivalent to '3.14' - /// * '-3.14' - /// * '2.5E10', or equivalently, '2.5e10' - /// * '2.5E-10' - /// * '.' (understood as 0) - /// * '5.' - /// * '.5', or, equivalently, '0.5' - /// * '+inf', 'inf', '-inf', 'NaN' - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Arguments - /// - /// * src - A string - /// - /// # Return value - /// - /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. - #[inline] - fn from_str(src: &str) -> Option { - strconv::from_str_radix_float(src, 10u) - } -} - -impl FromStrRadix for f32 { - /// Convert a string in a given base to a float. - /// - /// Due to possible conflicts, this function does **not** accept - /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** - /// does it recognize exponents of any kind. - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Arguments - /// - /// * src - A string - /// * radix - The base to use. Must lie in the range [2 .. 36] - /// - /// # Return value - /// - /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. - #[inline] - fn from_str_radix(src: &str, radix: uint) -> Option { - strconv::from_str_radix_float(src, radix) - } + from_str_radix(src, 16) } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 2abd6c237c8..e82be190110 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -16,10 +16,8 @@ use intrinsics; use mem; -use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; -use num::{Float, FromStrRadix}; -use num::strconv; -use str::FromStr; +use num::{Float, FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; +use num::from_str_radix; use option::Option; // FIXME(#5527): These constants should be deprecated once associated @@ -437,56 +435,5 @@ impl Float for f64 { #[allow(missing_docs)] #[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] pub fn from_str_hex(src: &str) -> Option { - strconv::from_str_radix_float(src, 16) -} - -impl FromStr for f64 { - /// Convert a string in base 10 to a float. - /// Accepts an optional decimal exponent. - /// - /// This function accepts strings such as: - /// - /// * '3.14' - /// * '-3.14' - /// * '2.5E10', or equivalently, '2.5e10' - /// * '2.5E-10' - /// * '.' (understood as 0) - /// * '5.' - /// * '.5', or, equivalently, '0.5' - /// * inf', '-inf', 'NaN' - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Arguments - /// - /// * src - A string - /// - /// # Return value - /// - /// `none` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. - #[inline] - fn from_str(src: &str) -> Option { - strconv::from_str_radix_float(src, 10u) - } -} - -impl FromStrRadix for f64 { - /// Convert a string in a given base to a float. - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Arguments - /// - /// * src - A string - /// * radix - The base to use. Must lie in the range [2 .. 36] - /// - /// # Return value - /// - /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. - #[inline] - fn from_str_radix(src: &str, radix: uint) -> Option { - strconv::from_str_radix_float(src, radix) - } + from_str_radix(src, 16) } diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index dc60a0c9764..0f8950344c8 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -32,20 +32,4 @@ pub const MIN: $T = (-1 as $T) << (BITS - 1); #[unstable] pub const MAX: $T = !MIN; -#[experimental = "might need to return Result"] -impl ::str::FromStr for $T { - #[inline] - fn from_str(s: &str) -> ::option::Option<$T> { - ::num::strconv::from_str_radix_int(s, 10) - } -} - -#[experimental = "might need to return Result"] -impl ::num::FromStrRadix for $T { - #[inline] - fn from_str_radix(s: &str, radix: uint) -> ::option::Option<$T> { - ::num::strconv::from_str_radix_int(s, radix) - } -} - )) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 391ccce568b..f5505ff8e76 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -14,20 +14,21 @@ #![allow(missing_docs)] -use intrinsics; use {int, i8, i16, i32, i64}; use {uint, u8, u16, u32, u64}; use {f32, f64}; +use char::Char; use clone::Clone; use cmp::{PartialEq, Eq}; use cmp::{PartialOrd, Ord}; +use intrinsics; +use iter::Iterator; use kinds::Copy; use mem::size_of; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::{Option, Some, None}; - -pub mod strconv; +use str::{FromStr, from_str, StrPrelude}; /// Simultaneous division and remainder #[inline] @@ -1386,6 +1387,278 @@ pub fn from_str_radix(str: &str, radix: uint) -> Option { FromStrRadix::from_str_radix(str, radix) } +macro_rules! from_str_radix_float_impl { + ($T:ty) => { + #[experimental = "might need to return Result"] + impl FromStr for $T { + /// Convert a string in base 10 to a float. + /// Accepts an optional decimal exponent. + /// + /// This function accepts strings such as + /// + /// * '3.14' + /// * '+3.14', equivalent to '3.14' + /// * '-3.14' + /// * '2.5E10', or equivalently, '2.5e10' + /// * '2.5E-10' + /// * '.' (understood as 0) + /// * '5.' + /// * '.5', or, equivalently, '0.5' + /// * '+inf', 'inf', '-inf', 'NaN' + /// + /// Leading and trailing whitespace represent an error. + /// + /// # Arguments + /// + /// * src - A string + /// + /// # Return value + /// + /// `None` if the string did not represent a valid number. Otherwise, + /// `Some(n)` where `n` is the floating-point number represented by `src`. + #[inline] + fn from_str(src: &str) -> Option<$T> { + from_str_radix(src, 10) + } + } + + #[experimental = "might need to return Result"] + impl FromStrRadix for $T { + /// Convert a string in a given base to a float. + /// + /// Due to possible conflicts, this function does **not** accept + /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** + /// does it recognize exponents of any kind. + /// + /// Leading and trailing whitespace represent an error. + /// + /// # Arguments + /// + /// * src - A string + /// * radix - The base to use. Must lie in the range [2 .. 36] + /// + /// # Return value + /// + /// `None` if the string did not represent a valid number. Otherwise, + /// `Some(n)` where `n` is the floating-point number represented by `src`. + fn from_str_radix(src: &str, radix: uint) -> Option<$T> { + assert!(radix >= 2 && radix <= 36, + "from_str_radix_float: must lie in the range `[2, 36]` - found {}", + radix); + + // Special values + match src { + "inf" => return Some(Float::infinity()), + "-inf" => return Some(Float::neg_infinity()), + "NaN" => return Some(Float::nan()), + _ => {}, + } + + let (is_positive, src) = match src.slice_shift_char() { + (None, _) => return None, + (Some('-'), "") => return None, + (Some('-'), src) => (false, src), + (Some(_), _) => (true, src), + }; + + // The significand to accumulate + let mut sig = if is_positive { 0.0 } else { -0.0 }; + // Necessary to detect overflow + let mut prev_sig = sig; + let mut cs = src.chars().enumerate(); + // Exponent prefix and exponent index offset + let mut exp_info = None::<(char, uint)>; + + // Parse the integer part of the significand + for (i, c) in cs { + match c.to_digit(radix) { + Some(digit) => { + // shift significand one digit left + sig = sig * (radix as $T); + + // add/subtract current digit depending on sign + if is_positive { + sig = sig + ((digit as int) as $T); + } else { + sig = sig - ((digit as int) as $T); + } + + // Detect overflow by comparing to last value, except + // if we've not seen any non-zero digits. + if prev_sig != 0.0 { + if is_positive && sig <= prev_sig + { return Some(Float::infinity()); } + if !is_positive && sig >= prev_sig + { return Some(Float::neg_infinity()); } + + // Detect overflow by reversing the shift-and-add process + if is_positive && (prev_sig != (sig - digit as $T) / radix as $T) + { return Some(Float::infinity()); } + if !is_positive && (prev_sig != (sig + digit as $T) / radix as $T) + { return Some(Float::neg_infinity()); } + } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + '.' => { + break; // start of fractional part + }, + _ => { + return None; + }, + }, + } + } + + // If we are not yet at the exponent parse the fractional + // part of the significand + if exp_info.is_none() { + let mut power = 1.0; + for (i, c) in cs { + match c.to_digit(radix) { + Some(digit) => { + // Decrease power one order of magnitude + power = power / (radix as $T); + // add/subtract current digit depending on sign + sig = if is_positive { + sig + (digit as $T) * power + } else { + sig - (digit as $T) * power + }; + // Detect overflow by comparing to last value + if is_positive && sig < prev_sig + { return Some(Float::infinity()); } + if !is_positive && sig > prev_sig + { return Some(Float::neg_infinity()); } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + _ => { + return None; // invalid number + }, + }, + } + } + } + + // Parse and calculate the exponent + let exp = match exp_info { + Some((c, offset)) => { + let base = match c { + 'E' | 'e' if radix == 10 => 10u as $T, + 'P' | 'p' if radix == 16 => 2u as $T, + _ => return None, + }; + + // Parse the exponent as decimal integer + let src = src[offset..]; + let (is_positive, exp) = match src.slice_shift_char() { + (Some('-'), src) => (false, from_str::(src)), + (Some('+'), src) => (true, from_str::(src)), + (Some(_), _) => (true, from_str::(src)), + (None, _) => return None, + }; + + match (is_positive, exp) { + (true, Some(exp)) => base.powi(exp as i32), + (false, Some(exp)) => 1.0 / base.powi(exp as i32), + (_, None) => return None, + } + }, + None => 1.0, // no exponent + }; + + Some(sig * exp) + } + } + } +} +from_str_radix_float_impl!(f32) +from_str_radix_float_impl!(f64) + +macro_rules! from_str_radix_int_impl { + ($T:ty) => { + #[experimental = "might need to return Result"] + impl FromStr for $T { + #[inline] + fn from_str(src: &str) -> Option<$T> { + from_str_radix(src, 10) + } + } + + #[experimental = "might need to return Result"] + impl FromStrRadix for $T { + fn from_str_radix(src: &str, radix: uint) -> Option<$T> { + assert!(radix >= 2 && radix <= 36, + "from_str_radix_int: must lie in the range `[2, 36]` - found {}", + radix); + + let is_signed_ty = (0 as $T) > Int::min_value(); + + match src.slice_shift_char() { + (Some('-'), src) if is_signed_ty => { + // The number is negative + let mut result = 0; + for c in src.chars() { + let x = match c.to_digit(radix) { + Some(x) => x, + None => return None, + }; + result = match result.checked_mul(radix as $T) { + Some(result) => result, + None => return None, + }; + result = match result.checked_sub(x as $T) { + Some(result) => result, + None => return None, + }; + } + Some(result) + }, + (Some(_), _) => { + // The number is signed + let mut result = 0; + for c in src.chars() { + let x = match c.to_digit(radix) { + Some(x) => x, + None => return None, + }; + result = match result.checked_mul(radix as $T) { + Some(result) => result, + None => return None, + }; + result = match result.checked_add(x as $T) { + Some(result) => result, + None => return None, + }; + } + Some(result) + }, + (None, _) => None, + } + } + } + } +} +from_str_radix_int_impl!(int) +from_str_radix_int_impl!(i8) +from_str_radix_int_impl!(i16) +from_str_radix_int_impl!(i32) +from_str_radix_int_impl!(i64) +from_str_radix_int_impl!(uint) +from_str_radix_int_impl!(u8) +from_str_radix_int_impl!(u16) +from_str_radix_int_impl!(u32) +from_str_radix_int_impl!(u64) + // DEPRECATED macro_rules! trait_impl { diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs deleted file mode 100644 index daa2a8e2343..00000000000 --- a/src/libcore/num/strconv.rs +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright 2013-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. -// -// ignore-lexer-test FIXME #15679 - -#![allow(missing_docs)] - -use char::Char; -use iter::Iterator; -use num; -use num::{Int, Float}; -use option::{None, Option, Some}; -use str::{from_str, StrPrelude}; - -pub fn from_str_radix_float(src: &str, radix: uint) -> Option { - assert!(radix >= 2 && radix <= 36, - "from_str_radix_float: must lie in the range `[2, 36]` - found {}", - radix); - - let _0: T = Float::zero(); - let _1: T = Float::one(); - let radix_t: T = num::cast(radix as int).unwrap(); - - // Special values - match src { - "inf" => return Some(Float::infinity()), - "-inf" => return Some(Float::neg_infinity()), - "NaN" => return Some(Float::nan()), - _ => {}, - } - - let (is_positive, src) = match src.slice_shift_char() { - (None, _) => return None, - (Some('-'), "") => return None, - (Some('-'), src) => (false, src), - (Some(_), _) => (true, src), - }; - - // The significand to accumulate - let mut sig = if is_positive { _0 } else { -_0 }; - // Necessary to detect overflow - let mut prev_sig = sig; - let mut cs = src.chars().enumerate(); - // Exponent prefix and exponent index offset - let mut exp_info = None::<(char, uint)>; - - // Parse the integer part of the significand - for (i, c) in cs { - match c.to_digit(radix) { - Some(digit) => { - // shift significand one digit left - sig = sig * radix_t; - - // add/subtract current digit depending on sign - if is_positive { - sig = sig + num::cast(digit as int).unwrap(); - } else { - sig = sig - num::cast(digit as int).unwrap(); - } - - // Detect overflow by comparing to last value, except - // if we've not seen any non-zero digits. - if prev_sig != _0 { - if is_positive && sig <= prev_sig - { return Some(Float::infinity()); } - if !is_positive && sig >= prev_sig - { return Some(Float::neg_infinity()); } - - // Detect overflow by reversing the shift-and-add process - let digit: T = num::cast(digit as int).unwrap(); - if is_positive && (prev_sig != ((sig - digit) / radix_t)) - { return Some(Float::infinity()); } - if !is_positive && (prev_sig != ((sig + digit) / radix_t)) - { return Some(Float::neg_infinity()); } - } - prev_sig = sig; - }, - None => match c { - 'e' | 'E' | 'p' | 'P' => { - exp_info = Some((c, i + 1)); - break; // start of exponent - }, - '.' => { - break; // start of fractional part - }, - _ => { - return None; - }, - }, - } - } - - // If we are not yet at the exponent parse the fractional - // part of the significand - if exp_info.is_none() { - let mut power = _1; - for (i, c) in cs { - match c.to_digit(radix) { - Some(digit) => { - let digit: T = num::cast(digit).unwrap(); - // Decrease power one order of magnitude - power = power / radix_t; - // add/subtract current digit depending on sign - sig = if is_positive { - sig + digit * power - } else { - sig - digit * power - }; - // Detect overflow by comparing to last value - if is_positive && sig < prev_sig - { return Some(Float::infinity()); } - if !is_positive && sig > prev_sig - { return Some(Float::neg_infinity()); } - prev_sig = sig; - }, - None => match c { - 'e' | 'E' | 'p' | 'P' => { - exp_info = Some((c, i + 1)); - break; // start of exponent - }, - _ => { - return None; // invalid number - }, - }, - } - } - } - - // Parse and calculate the exponent - let exp = match exp_info { - Some((c, offset)) => { - let base: T = match c { - 'E' | 'e' if radix == 10 => num::cast(10u).unwrap(), - 'P' | 'p' if radix == 16 => num::cast(2u).unwrap(), - _ => return None, - }; - - // Parse the exponent as decimal integer - let src = src[offset..]; - let (is_positive, exp) = match src.slice_shift_char() { - (Some('-'), src) => (false, from_str::(src)), - (Some('+'), src) => (true, from_str::(src)), - (Some(_), _) => (true, from_str::(src)), - (None, _) => return None, - }; - - match (is_positive, exp) { - (true, Some(exp)) => base.powi(exp as i32), - (false, Some(exp)) => _1 / base.powi(exp as i32), - (_, None) => return None, - } - }, - None => _1, // no exponent - }; - - Some(sig * exp) -} - -pub fn from_str_radix_int(src: &str, radix: uint) -> Option { - assert!(radix >= 2 && radix <= 36, - "from_str_radix_int: must lie in the range `[2, 36]` - found {}", - radix); - - fn cast(x: uint) -> T { - num::cast(x).unwrap() - } - - let _0: T = Int::zero(); - let _1: T = Int::one(); - let is_signed = _0 > Int::min_value(); - - let (is_positive, src) = match src.slice_shift_char() { - (Some('-'), src) if is_signed => (false, src), - (Some(_), _) => (true, src), - (None, _) => return None, - }; - - let mut xs = src.chars().map(|c| { - c.to_digit(radix).map(cast) - }); - let radix = cast(radix); - let mut result = _0; - - if is_positive { - for x in xs { - let x = match x { - Some(x) => x, - None => return None, - }; - result = match result.checked_mul(radix) { - Some(result) => result, - None => return None, - }; - result = match result.checked_add(x) { - Some(result) => result, - None => return None, - }; - } - } else { - for x in xs { - let x = match x { - Some(x) => x, - None => return None, - }; - result = match result.checked_mul(radix) { - Some(result) => result, - None => return None, - }; - result = match result.checked_sub(x) { - Some(result) => result, - None => return None, - }; - } - } - - Some(result) -} - -#[cfg(test)] -mod test { - use super::*; - use option::*; - use num::Float; - - #[test] - fn from_str_issue7588() { - let u : Option = from_str_radix_int("1000", 10); - assert_eq!(u, None); - let s : Option = from_str_radix_int("80000", 10); - assert_eq!(s, None); - let f : Option = from_str_radix_float("10000000000000000000000000000000000000000", 10); - assert_eq!(f, Some(Float::infinity())) - let fe : Option = from_str_radix_float("1e40", 10); - assert_eq!(fe, Some(Float::infinity())) - } - - #[test] - fn test_from_str_radix_float() { - let x1 : Option = from_str_radix_float("-123.456", 10); - assert_eq!(x1, Some(-123.456)); - let x2 : Option = from_str_radix_float("123.456", 10); - assert_eq!(x2, Some(123.456)); - let x3 : Option = from_str_radix_float("-0.0", 10); - assert_eq!(x3, Some(-0.0)); - let x4 : Option = from_str_radix_float("0.0", 10); - assert_eq!(x4, Some(0.0)); - let x4 : Option = from_str_radix_float("1.0", 10); - assert_eq!(x4, Some(1.0)); - let x5 : Option = from_str_radix_float("-1.0", 10); - assert_eq!(x5, Some(-1.0)); - } -} diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 4977e5d6680..2a94f851646 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -23,20 +23,4 @@ pub const MIN: $T = 0 as $T; #[unstable] pub const MAX: $T = 0 as $T - 1 as $T; -#[experimental = "might need to return Result"] -impl ::str::FromStr for $T { - #[inline] - fn from_str(s: &str) -> ::option::Option<$T> { - ::num::strconv::from_str_radix_int(s, 10) - } -} - -#[experimental = "might need to return Result"] -impl ::num::FromStrRadix for $T { - #[inline] - fn from_str_radix(s: &str, radix: uint) -> ::option::Option<$T> { - ::num::strconv::from_str_radix_int(s, radix) - } -} - )) From 8b156724a3ebe9fe1f1a590dfb626a31b2680145 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 15 Nov 2014 19:44:22 +1100 Subject: [PATCH 18/23] Remove use of deprecated function --- src/libstd/num/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 73fd2ccd2d3..2ce6c0e6e71 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -751,8 +751,9 @@ mod tests { #[test] fn test_pow() { - fn naive_pow>(base: T, exp: uint) -> T { - range(0, exp).fold(one::(), |acc, _| acc * base) + fn naive_pow(base: T, exp: uint) -> T { + let one: T = Int::one(); + range(0, exp).fold(one, |acc, _| acc * base) } macro_rules! assert_pow( (($num:expr, $exp:expr) => $expected:expr) => {{ From 2d8ca045d6d143819fe386bff37ff7ecb0e380d0 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 15 Nov 2014 22:09:26 +1100 Subject: [PATCH 19/23] Rename IntoStr to IntoString For consistancy with ToString --- src/etc/vim/syntax/rust.vim | 2 +- src/libstd/ascii.rs | 4 ++-- src/libstd/prelude.rs | 2 +- src/libstd/to_string.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 710092a3e5f..1b1b65bd560 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -105,7 +105,7 @@ syn keyword rustTrait RawPtr syn keyword rustTrait Buffer Writer Reader Seek syn keyword rustTrait Str StrVector StrSlice syn keyword rustTrait IntoMaybeOwned StrAllocating UnicodeStrSlice -syn keyword rustTrait ToString IntoStr +syn keyword rustTrait ToString IntoString syn keyword rustTrait Tuple1 Tuple2 Tuple3 Tuple4 syn keyword rustTrait Tuple5 Tuple6 Tuple7 Tuple8 syn keyword rustTrait Tuple9 Tuple10 Tuple11 Tuple12 diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index ff83027d280..56b048c3187 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -22,7 +22,7 @@ use option::{Option, Some, None}; use slice::{SlicePrelude, AsSlice}; use str::{Str, StrPrelude}; use string::{mod, String}; -use to_string::IntoStr; +use to_string::IntoString; use vec::Vec; /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero. @@ -326,7 +326,7 @@ impl AsciiStr for [Ascii] { } } -impl IntoStr for Vec { +impl IntoString for Vec { #[inline] fn into_string(self) -> String { unsafe { diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 4ab09a2a864..47dd07081d0 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -76,7 +76,7 @@ #[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek}; #[doc(no_inline)] pub use str::{Str, StrVector, StrPrelude}; #[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrPrelude}; -#[doc(no_inline)] pub use to_string::{ToString, IntoStr}; +#[doc(no_inline)] pub use to_string::{ToString, IntoString}; #[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; #[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; #[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; diff --git a/src/libstd/to_string.rs b/src/libstd/to_string.rs index c19fd81b570..737e467f19c 100644 --- a/src/libstd/to_string.rs +++ b/src/libstd/to_string.rs @@ -26,7 +26,7 @@ pub trait ToString { } /// Trait for converting a type to a string, consuming it in the process. -pub trait IntoStr { +pub trait IntoString { /// Consume and convert to a string. fn into_string(self) -> String; } From 59abf75d9e810f2a88c6dd0f37cfcbd6989a6446 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 15 Nov 2014 23:57:54 +1100 Subject: [PATCH 20/23] Move IntoString to collections::string --- src/libcollections/string.rs | 6 ++++++ src/libstd/ascii.rs | 3 +-- src/libstd/prelude.rs | 4 ++-- src/libstd/to_string.rs | 6 ------ 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index c1e093436c3..b5ed7e6a077 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -802,6 +802,12 @@ impl FromStr for String { } } +/// Trait for converting a type to a string, consuming it in the process. +pub trait IntoString { + /// Consume and convert to a string. + fn into_string(self) -> String; +} + /// Unsafe operations #[unstable = "waiting on raw module conventions"] pub mod raw { diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 56b048c3187..923349b1bf7 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -21,8 +21,7 @@ use mem; use option::{Option, Some, None}; use slice::{SlicePrelude, AsSlice}; use str::{Str, StrPrelude}; -use string::{mod, String}; -use to_string::IntoString; +use string::{mod, String, IntoString}; use vec::Vec; /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero. diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 47dd07081d0..a75c51b9f9f 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -76,14 +76,14 @@ #[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek}; #[doc(no_inline)] pub use str::{Str, StrVector, StrPrelude}; #[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrPrelude}; -#[doc(no_inline)] pub use to_string::{ToString, IntoString}; +#[doc(no_inline)] pub use to_string::ToString; #[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; #[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; #[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; #[doc(no_inline)] pub use slice::{SlicePrelude, AsSlice, CloneSlicePrelude}; #[doc(no_inline)] pub use slice::{VectorVector, PartialEqSlicePrelude, OrdSlicePrelude}; #[doc(no_inline)] pub use slice::{CloneSliceAllocPrelude, OrdSliceAllocPrelude, SliceAllocPrelude}; -#[doc(no_inline)] pub use string::String; +#[doc(no_inline)] pub use string::{IntoString, String}; #[doc(no_inline)] pub use vec::Vec; // Reexported runtime types diff --git a/src/libstd/to_string.rs b/src/libstd/to_string.rs index 737e467f19c..327410b320d 100644 --- a/src/libstd/to_string.rs +++ b/src/libstd/to_string.rs @@ -25,12 +25,6 @@ pub trait ToString { fn to_string(&self) -> String; } -/// Trait for converting a type to a string, consuming it in the process. -pub trait IntoString { - /// Consume and convert to a string. - fn into_string(self) -> String; -} - impl ToString for T { fn to_string(&self) -> String { format!("{}", *self) From d82a7ea57a69954dcc9b58869907a0a070ef432d Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sun, 16 Nov 2014 12:38:03 +1100 Subject: [PATCH 21/23] Move ToString to collections::string This also impls `FormatWriter` for `Vec` --- src/libcollections/string.rs | 38 +++++++++++- src/libcollections/vec.rs | 7 +++ src/libstd/lib.rs | 1 - src/libstd/num/strconv.rs | 2 +- src/libstd/os.rs | 3 +- src/libstd/prelude.rs | 3 +- src/libstd/task.rs | 3 +- src/libstd/time/duration.rs | 2 +- src/libstd/to_string.rs | 60 ------------------- .../class-cast-to-trait-cross-crate-2.rs | 2 +- src/test/run-pass/send_str_treemap.rs | 2 +- 11 files changed, 51 insertions(+), 72 deletions(-) delete mode 100644 src/libstd/to_string.rs diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index b5ed7e6a077..3c75198a368 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -808,6 +808,20 @@ pub trait IntoString { fn into_string(self) -> String; } +/// A generic trait for converting a value to a string +pub trait ToString { + /// Converts the value of `self` to an owned string + fn to_string(&self) -> String; +} + +impl ToString for T { + fn to_string(&self) -> String { + let mut buf = Vec::::new(); + let _ = format_args!(|args| fmt::write(&mut buf, args), "{}", self); + String::from_utf8(buf).unwrap() + } +} + /// Unsafe operations #[unstable = "waiting on raw module conventions"] pub mod raw { @@ -873,7 +887,7 @@ mod tests { use str; use str::{Str, StrPrelude, Owned}; - use super::{as_string, String}; + use super::{as_string, String, ToString}; use vec::Vec; use slice::CloneSliceAllocPrelude; @@ -1177,6 +1191,28 @@ mod tests { assert_eq!("oob", s[1..4]); } + #[test] + fn test_simple_types() { + assert_eq!(1i.to_string(), "1".to_string()); + assert_eq!((-1i).to_string(), "-1".to_string()); + assert_eq!(200u.to_string(), "200".to_string()); + assert_eq!(2u8.to_string(), "2".to_string()); + assert_eq!(true.to_string(), "true".to_string()); + assert_eq!(false.to_string(), "false".to_string()); + assert_eq!(().to_string(), "()".to_string()); + assert_eq!(("hi".to_string()).to_string(), "hi".to_string()); + } + + #[test] + fn test_vectors() { + let x: Vec = vec![]; + assert_eq!(x.to_string(), "[]".to_string()); + assert_eq!((vec![1i]).to_string(), "[1]".to_string()); + assert_eq!((vec![1i, 2, 3]).to_string(), "[1, 2, 3]".to_string()); + assert!((vec![vec![], vec![1i], vec![1i, 1]]).to_string() == + "[[], [1], [1, 1]]".to_string()); + } + #[bench] fn bench_with_capacity(b: &mut Bencher) { b.iter(|| { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 2b68de932d2..b94c74f6d19 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1653,6 +1653,13 @@ impl Vec { } } +impl<'a> fmt::FormatWriter for Vec { + fn write(&mut self, buf: &[u8]) -> fmt::Result { + self.push_all(buf); + Ok(()) + } +} + #[cfg(test)] mod tests { extern crate test; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4e063223329..612613134d4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -220,7 +220,6 @@ pub mod time; pub mod error; pub mod num; -pub mod to_string; /* Common data structures */ diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 31096c0aa46..d1a89d72621 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -423,7 +423,7 @@ static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; #[cfg(test)] mod tests { - use to_string::ToString; + use string::ToString; #[test] fn test_int_to_str_overflow() { diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 1402d3a3559..23e57a028de 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -51,8 +51,7 @@ use result::{Err, Ok, Result}; use slice::{AsSlice, SlicePrelude, PartialEqSlicePrelude}; use slice::CloneSliceAllocPrelude; use str::{Str, StrPrelude, StrAllocating}; -use string::String; -use to_string::ToString; +use string::{String, ToString}; use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst}; use vec::Vec; diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index a75c51b9f9f..c0197fa53cc 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -76,14 +76,13 @@ #[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek}; #[doc(no_inline)] pub use str::{Str, StrVector, StrPrelude}; #[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrPrelude}; -#[doc(no_inline)] pub use to_string::ToString; #[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; #[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; #[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; #[doc(no_inline)] pub use slice::{SlicePrelude, AsSlice, CloneSlicePrelude}; #[doc(no_inline)] pub use slice::{VectorVector, PartialEqSlicePrelude, OrdSlicePrelude}; #[doc(no_inline)] pub use slice::{CloneSliceAllocPrelude, OrdSliceAllocPrelude, SliceAllocPrelude}; -#[doc(no_inline)] pub use string::{IntoString, String}; +#[doc(no_inline)] pub use string::{IntoString, String, ToString}; #[doc(no_inline)] pub use vec::Vec; // Reexported runtime types diff --git a/src/libstd/task.rs b/src/libstd/task.rs index f0bb8a0f4bc..c7e31dae3d4 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -105,9 +105,8 @@ use rt::local::Local; use rt::task; use rt::task::Task; use str::{Str, SendStr, IntoMaybeOwned}; -use string::String; +use string::{String, ToString}; use sync::Future; -use to_string::ToString; /// A means of spawning a task pub trait Spawner { diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 5c4e8bda84c..83340c9faac 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -388,7 +388,7 @@ mod tests { use super::{Duration, MIN, MAX}; use {i32, i64}; use option::{Some, None}; - use to_string::ToString; + use string::ToString; #[test] fn test_duration() { diff --git a/src/libstd/to_string.rs b/src/libstd/to_string.rs deleted file mode 100644 index 327410b320d..00000000000 --- a/src/libstd/to_string.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -The `ToString` trait for converting to strings - -*/ - -#![experimental] - -use fmt; -use string::String; - -/// A generic trait for converting a value to a string -pub trait ToString { - /// Converts the value of `self` to an owned string - fn to_string(&self) -> String; -} - -impl ToString for T { - fn to_string(&self) -> String { - format!("{}", *self) - } -} - -#[cfg(test)] -mod tests { - use prelude::*; - use super::*; - - #[test] - fn test_simple_types() { - assert_eq!(1i.to_string(), "1".to_string()); - assert_eq!((-1i).to_string(), "-1".to_string()); - assert_eq!(200u.to_string(), "200".to_string()); - assert_eq!(2u8.to_string(), "2".to_string()); - assert_eq!(true.to_string(), "true".to_string()); - assert_eq!(false.to_string(), "false".to_string()); - assert_eq!(().to_string(), "()".to_string()); - assert_eq!(("hi".to_string()).to_string(), "hi".to_string()); - } - - #[test] - fn test_vectors() { - let x: Vec = vec![]; - assert_eq!(x.to_string(), "[]".to_string()); - assert_eq!((vec![1i]).to_string(), "[1]".to_string()); - assert_eq!((vec![1i, 2, 3]).to_string(), "[1, 2, 3]".to_string()); - assert!((vec![vec![], vec![1i], vec![1i, 1]]).to_string() == - "[[], [1], [1, 1]]".to_string()); - } -} diff --git a/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs b/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs index cfee1a81231..a041bbfe8ad 100644 --- a/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs +++ b/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs @@ -11,7 +11,7 @@ // aux-build:cci_class_cast.rs extern crate cci_class_cast; -use std::to_string::ToString; +use std::string::ToString; use cci_class_cast::kitty::cat; fn print_out(thing: Box, expected: String) { diff --git a/src/test/run-pass/send_str_treemap.rs b/src/test/run-pass/send_str_treemap.rs index c52f9458f99..0d881419847 100644 --- a/src/test/run-pass/send_str_treemap.rs +++ b/src/test/run-pass/send_str_treemap.rs @@ -11,7 +11,7 @@ extern crate collections; use std::str::{SendStr, Owned, Slice}; -use std::to_string::ToString; +use std::string::ToString; use self::collections::TreeMap; use std::option::Some; From 3ee9f0df5482c4a99092e553c51e3c108cc850af Mon Sep 17 00:00:00 2001 From: Jakub Bukaj Date: Sun, 16 Nov 2014 10:37:31 +0100 Subject: [PATCH 22/23] Fix warnings --- src/librustdoc/stability_summary.rs | 2 +- src/libstd/io/process.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/stability_summary.rs b/src/librustdoc/stability_summary.rs index 058d8b81f7a..7ec59f0139d 100644 --- a/src/librustdoc/stability_summary.rs +++ b/src/librustdoc/stability_summary.rs @@ -19,7 +19,7 @@ use std::num::Zero; use syntax::attr::{Deprecated, Experimental, Unstable, Stable, Frozen, Locked}; use syntax::ast::Public; -use clean::{Crate, Item, ModuleItem, Module, StructItem, Struct, EnumItem, Enum}; +use clean::{Crate, Item, ModuleItem, Module, EnumItem, Enum}; use clean::{ImplItem, Impl, Trait, TraitItem, TraitMethod, ProvidedMethod, RequiredMethod}; use clean::{TypeTraitItem, ViewItemItem, PrimitiveItem, Stability}; diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index d71bab0b48f..5b5bb618151 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -1190,7 +1190,7 @@ mod tests { Path::new("/dev/null") }; - let mut fdes = match fs::open(&path, Truncate, Write) { + let fdes = match fs::open(&path, Truncate, Write) { Ok(f) => f, Err(_) => panic!("failed to open file descriptor"), }; From 892d4e28f4021ffa815649ec3a52f22f929b3708 Mon Sep 17 00:00:00 2001 From: Jakub Bukaj Date: Sun, 16 Nov 2014 12:22:40 +0100 Subject: [PATCH 23/23] Fix doctests --- src/libstd/sync/task_pool.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sync/task_pool.rs b/src/libstd/sync/task_pool.rs index 2682582d708..4ae5cd054f6 100644 --- a/src/libstd/sync/task_pool.rs +++ b/src/libstd/sync/task_pool.rs @@ -52,8 +52,8 @@ impl<'a> Drop for Sentinel<'a> { /// # Example /// /// ```rust -/// # use sync::TaskPool; -/// # use iter::AdditiveIterator; +/// # use std::sync::TaskPool; +/// # use std::iter::AdditiveIterator; /// /// let pool = TaskPool::new(4u); ///