Skip to content

Commit

Permalink
std: Stabilize the std::fmt module
Browse files Browse the repository at this point in the history
This commit performs a final stabilization pass over the std::fmt module,
marking all necessary APIs as stable. One of the more interesting aspects of
this module is that it exposes a good deal of its runtime representation to the
outside world in order for `format_args!` to be able to construct the format
strings. Instead of hacking the compiler to assume that these items are stable,
this commit instead lays out a story for the stabilization and evolution of
these APIs.

There are three primary details used by the `format_args!` macro:

1. `Arguments` - an opaque package of a "compiled format string". This structure
   is passed around and the `write` function is the source of truth for
   transforming a compiled format string into a string at runtime. This must be
   able to be constructed in stable code.

2. `Argument` - an opaque structure representing an argument to a format string.
   This is *almost* a trait object as it's just a pointer/function pair, but due
   to the function originating from one of many traits, it's not actually a
   trait object. Like `Arguments`, this must be constructed from stable code.

3. `fmt::rt` - this module contains the runtime type definitions primarily for
   the `rt::Argument` structure. Whenever an argument is formatted with
   nonstandard flags, a corresponding `rt::Argument` is generated describing how
   the argument is being formatted. This can be used to construct an
   `Arguments`.

The primary interface to `std::fmt` is the `Arguments` structure, and as such
this type name is stabilize as-is today. It is expected for libraries to pass
around an `Arguments` structure to represent a pending formatted computation.

The remaining portions are largely "cruft" which would rather not be stabilized,
but due to the stability checks they must be. As a result, almost all pieces
have been renamed to represent that they are "version 1" of the formatting
representation. The theory is that at a later date if we change the
representation of these types we can add new definitions called "version 2" and
corresponding constructors for `Arguments`.

One of the other remaining large questions about the fmt module were how the
pending I/O reform would affect the signatures of methods in the module. Due to
[RFC 526][rfc], however, the writers of fmt are now incompatible with the
writers of io, so this question has largely been solved. As a result the
interfaces are largely stabilized as-is today.

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md

Specifically, the following changes were made:

* The contents of `fmt::rt` were all moved under `fmt::rt::v1`
* `fmt::rt` is stable
* `fmt::rt::v1` is stable
* `Error` is stable
* `Writer` is stable
* `Writer::write_str` is stable
* `Writer::write_fmt` is stable
* `Formatter` is stable
* `Argument` has been renamed to `ArgumentV1` and is stable
* `ArgumentV1::new` is stable
* `ArgumentV1::from_uint` is stable
* `Arguments::new_v1` is stable (renamed from `new`)
* `Arguments::new_v1_formatted` is stable (renamed from `with_placeholders`)
* All formatting traits are now stable, as well as the `fmt` method.
* `fmt::write` is stable
* `fmt::format` is stable
* `Formatter::pad_integral` is stable
* `Formatter::pad` is stable
* `Formatter::write_str` is stable
* `Formatter::write_fmt` is stable
* Some assorted top level items which were only used by `format_args!` were
  removed in favor of static functions on `ArgumentV1` as well.
* The formatting-flag-accessing methods remain unstable

Within the contents of the `fmt::rt::v1` module, the following actions were
taken:

* Reexports of all enum variants were removed
* All prefixes on enum variants were removed
* A few miscellaneous enum variants were renamed
* Otherwise all structs, fields, and variants were marked stable.

In addition to these actions in the `std::fmt` module, many implementations of
`Show` and `String` were stabilized as well.

In some other modules:

* `ToString` is now stable
* `ToString::to_string` is now stable
* `Vec` no longer implements `fmt::Writer` (this has moved to `String`)

While stabilize the formatting traits, the following change was also made to the
`result` module:

* `Result::unwrap` now requires `String` instead of `Show`
* `Result::unwrap_err` now requires `String` instead of `Show`

This is a breaking change due to all of the changes to the `fmt::rt` module, but
this likely will not have much impact on existing programs. It is also a
breaking change due to the usage of `String` for `unwrap()` on `Result` instead
of `Show`. Error types should implement `String` for human readable errors and
`Show` for inspecting their representation.

Closes rust-lang#20661
[breaking-change]
  • Loading branch information
alexcrichton committed Jan 14, 2015
1 parent c366e43 commit 92a341a
Show file tree
Hide file tree
Showing 39 changed files with 385 additions and 271 deletions.
30 changes: 17 additions & 13 deletions src/liballoc/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,22 @@

//! Threadsafe reference-counted boxes (the `Arc<T>` type).
//!
//! The `Arc<T>` type provides shared ownership of an immutable value. Destruction is
//! deterministic, and will occur as soon as the last owner is gone. It is marked as `Send` because
//! it uses atomic reference counting.
//! The `Arc<T>` type provides shared ownership of an immutable value.
//! Destruction is deterministic, and will occur as soon as the last owner is
//! gone. It is marked as `Send` because it uses atomic reference counting.
//!
//! If you do not need thread-safety, and just need shared ownership, consider the [`Rc<T>`
//! type](../rc/struct.Rc.html). It is the same as `Arc<T>`, but does not use atomics, making it
//! both thread-unsafe as well as significantly faster when updating the reference count.
//! If you do not need thread-safety, and just need shared ownership, consider
//! the [`Rc<T>` type](../rc/struct.Rc.html). It is the same as `Arc<T>`, but
//! does not use atomics, making it both thread-unsafe as well as significantly
//! faster when updating the reference count.
//!
//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer to the box. A
//! `Weak<T>` pointer can be upgraded to an `Arc<T>` pointer, but will return `None` if the value
//! has already been dropped.
//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer
//! to the box. A `Weak<T>` pointer can be upgraded to an `Arc<T>` pointer, but
//! will return `None` if the value has already been dropped.
//!
//! For example, a tree with parent pointers can be represented by putting the nodes behind strong
//! `Arc<T>` pointers, and then storing the parent pointers as `Weak<T>` pointers.
//! For example, a tree with parent pointers can be represented by putting the
//! nodes behind strong `Arc<T>` pointers, and then storing the parent pointers
//! as `Weak<T>` pointers.
//!
//! # Examples
//!
Expand Down Expand Up @@ -87,8 +89,9 @@ use heap::deallocate;
///
/// # Example
///
/// In this example, a large vector of floats is shared between several tasks. With simple pipes,
/// without `Arc`, a copy would have to be made for each task.
/// In this example, a large vector of floats is shared between several tasks.
/// With simple pipes, without `Arc`, a copy would have to be made for each
/// task.
///
/// ```rust
/// use std::sync::Arc;
Expand Down Expand Up @@ -578,6 +581,7 @@ impl<T: Ord> Ord for Arc<T> {
#[stable]
impl<T: Eq> Eq for Arc<T> {}

#[stable]
impl<T: fmt::Show> fmt::Show for Arc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Arc({:?})", (**self))
Expand Down
1 change: 1 addition & 0 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ impl BoxAny for Box<Any> {
}
}

#[stable]
impl<T: ?Sized + fmt::Show> fmt::Show for Box<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Box({:?})", &**self)
Expand Down
2 changes: 1 addition & 1 deletion src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ impl<S: hash::Hasher, T: Hash<S>> Hash<S> for Rc<T> {
}
}

#[unstable = "Show is experimental."]
#[stable]
impl<T: fmt::Show> fmt::Show for Rc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Rc({:?})", **self)
Expand Down
1 change: 1 addition & 0 deletions src/libcollections/bit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1727,6 +1727,7 @@ impl BitvSet {
}
}

#[stable]
impl fmt::Show for BitvSet {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
try!(write!(fmt, "BitvSet {{"));
Expand Down
1 change: 1 addition & 0 deletions src/libcollections/enum_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct EnumSet<E> {

impl<E> Copy for EnumSet<E> {}

#[stable]
impl<E:CLike+fmt::Show> fmt::Show for EnumSet<E> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
try!(write!(fmt, "EnumSet {{"));
Expand Down
8 changes: 7 additions & 1 deletion src/libcollections/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ impl FromUtf8Error {
pub fn utf8_error(&self) -> Utf8Error { self.error }
}

#[stable]
impl fmt::Show for FromUtf8Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::String::fmt(self, f)
Expand All @@ -693,6 +694,7 @@ impl fmt::String for FromUtf8Error {
}
}

#[stable]
impl fmt::Show for FromUtf16Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::String::fmt(self, f)
Expand Down Expand Up @@ -821,7 +823,7 @@ impl fmt::String for String {
}
}

#[unstable = "waiting on fmt stabilization"]
#[stable]
impl fmt::Show for String {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand Down Expand Up @@ -938,11 +940,14 @@ impl FromStr for String {
}

/// A generic trait for converting a value to a string
#[stable]
pub trait ToString {
/// Converts the value of `self` to an owned string
#[stable]
fn to_string(&self) -> String;
}

#[stable]
impl<T: fmt::String + ?Sized> ToString for T {
#[inline]
fn to_string(&self) -> String {
Expand Down Expand Up @@ -979,6 +984,7 @@ impl<'a> Str for CowString<'a> {
}
}

#[stable]
impl fmt::Writer for String {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
Expand Down
9 changes: 1 addition & 8 deletions src/libcollections/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1457,20 +1457,13 @@ impl<T> Default for Vec<T> {
}
}

#[unstable = "waiting on Show stability"]
#[stable]
impl<T: fmt::Show> fmt::Show for Vec<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Show::fmt(self.as_slice(), f)
}
}

impl<'a> fmt::Writer for Vec<u8> {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.push_all(s.as_bytes());
Ok(())
}
}

////////////////////////////////////////////////////////////////////////////////
// Clone-on-write
////////////////////////////////////////////////////////////////////////////////
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ macro_rules! array_impls {
}
}

#[unstable = "waiting for Show to stabilize"]
#[stable]
impl<T:fmt::Show> fmt::Show for [T; $N] {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Show::fmt(&&self[], f)
Expand Down
Loading

0 comments on commit 92a341a

Please sign in to comment.