std: Stabilize the std::fmt module

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`)

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.

Closes #20661
[breaking-change]
This commit is contained in:
Alex Crichton 2015-01-13 15:42:53 -08:00
parent 52c74e63da
commit 6227357513
21 changed files with 379 additions and 349 deletions

View File

@ -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
//!
@ -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;

View File

@ -1730,6 +1730,7 @@ impl BitvSet {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for BitvSet {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
try!(write!(fmt, "BitvSet {{"));

View File

@ -31,6 +31,7 @@ pub struct EnumSet<E> {
impl<E> Copy for EnumSet<E> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<E:CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
try!(write!(fmt, "EnumSet {{"));

View File

@ -938,11 +938,14 @@ impl FromStr for String {
}
/// A generic trait for converting a value to a string
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ToString {
/// Converts the value of `self` to an owned string
#[stable(feature = "rust1", since = "1.0.0")]
fn to_string(&self) -> String;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Display + ?Sized> ToString for T {
#[inline]
fn to_string(&self) -> String {
@ -979,6 +982,7 @@ impl<'a> Str for CowString<'a> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Writer for String {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {

View File

@ -1546,13 +1546,6 @@ impl<T: fmt::Debug> fmt::Debug for Vec<T> {
}
}
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
////////////////////////////////////////////////////////////////////////////////

View File

@ -10,7 +10,6 @@
//! Utilities for formatting and printing strings
#![allow(unused_variables)]
#![stable(feature = "rust1", since = "1.0.0")]
use any;
@ -27,6 +26,7 @@ use result;
use slice::SliceExt;
use slice;
use str::{self, StrExt};
use self::rt::v1::Alignment;
pub use self::num::radix;
pub use self::num::Radix;
@ -34,10 +34,15 @@ pub use self::num::RadixFmt;
mod num;
mod float;
pub mod rt;
#[unstable(feature = "core",
reason = "core and I/O reconciliation may alter this definition")]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(hidden)]
pub mod rt {
#[cfg(stage0)] pub use self::v1::*;
pub mod v1;
}
#[stable(feature = "rust1", since = "1.0.0")]
/// The type returned by formatter methods.
pub type Result = result::Result<(), Error>;
@ -46,8 +51,7 @@ pub type Result = result::Result<(), Error>;
/// This type does not support transmission of an error other than that an error
/// occurred. Any extra information must be arranged to be transmitted through
/// some other means.
#[unstable(feature = "core",
reason = "core and I/O reconciliation may alter this definition")]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Copy, Debug)]
pub struct Error;
@ -60,8 +64,7 @@ pub struct Error;
/// This trait should generally not be implemented by consumers of the standard
/// library. The `write!` macro accepts an instance of `io::Writer`, and the
/// `io::Writer` trait is favored over implementing this trait.
#[unstable(feature = "core",
reason = "waiting for core and I/O reconciliation")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Writer {
/// Writes a slice of bytes into this writer, returning whether the write
/// succeeded.
@ -73,12 +76,14 @@ pub trait Writer {
/// # Errors
///
/// This function will return an instance of `FormatError` on error.
#[stable(feature = "rust1", since = "1.0.0")]
fn write_str(&mut self, s: &str) -> Result;
/// Glue for usage of the `write!` macro with implementers of this trait.
///
/// This method should generally not be invoked manually, but rather through
/// the `write!` macro itself.
#[stable(feature = "rust1", since = "1.0.0")]
fn write_fmt(&mut self, args: Arguments) -> Result {
// This Adapter is needed to allow `self` (of type `&mut
// Self`) to be cast to a FormatWriter (below) without
@ -104,18 +109,17 @@ pub trait Writer {
/// A struct to represent both where to emit formatting strings to and how they
/// should be formatted. A mutable version of this is passed to all formatting
/// traits.
#[unstable(feature = "core",
reason = "name may change and implemented traits are also unstable")]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Formatter<'a> {
flags: uint,
fill: char,
align: rt::Alignment,
align: rt::v1::Alignment,
width: Option<uint>,
precision: Option<uint>,
buf: &'a mut (Writer+'a),
curarg: slice::Iter<'a, Argument<'a>>,
args: &'a [Argument<'a>],
curarg: slice::Iter<'a, ArgumentV1<'a>>,
args: &'a [ArgumentV1<'a>],
}
// NB. Argument is essentially an optimized partially applied formatting function,
@ -127,35 +131,40 @@ enum Void {}
/// family of functions. It contains a function to format the given value. At
/// compile time it is ensured that the function and the value have the correct
/// types, and then this struct is used to canonicalize arguments to one type.
#[unstable(feature = "core",
reason = "implementation detail of the `format_args!` macro")]
#[derive(Copy)]
pub struct Argument<'a> {
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(hidden)]
pub struct ArgumentV1<'a> {
value: &'a Void,
formatter: fn(&Void, &mut Formatter) -> Result,
}
impl<'a> Argument<'a> {
impl<'a> ArgumentV1<'a> {
#[inline(never)]
fn show_uint(x: &uint, f: &mut Formatter) -> Result {
Display::fmt(x, f)
}
fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter) -> Result) -> Argument<'b> {
#[doc(hidden)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<'b, T>(x: &'b T,
f: fn(&T, &mut Formatter) -> Result) -> ArgumentV1<'b> {
unsafe {
Argument {
ArgumentV1 {
formatter: mem::transmute(f),
value: mem::transmute(x)
}
}
}
fn from_uint(x: &uint) -> Argument {
Argument::new(x, Argument::show_uint)
#[doc(hidden)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_uint(x: &uint) -> ArgumentV1 {
ArgumentV1::new(x, ArgumentV1::show_uint)
}
fn as_uint(&self) -> Option<uint> {
if self.formatter as uint == Argument::show_uint as uint {
if self.formatter as uint == ArgumentV1::show_uint as uint {
Some(unsafe { *(self.value as *const _ as *const uint) })
} else {
None
@ -163,14 +172,32 @@ impl<'a> Argument<'a> {
}
}
// flags available in the v1 format of format_args
#[derive(Copy)]
#[allow(dead_code)] // SignMinus isn't currently used
enum FlagV1 { SignPlus, SignMinus, Alternate, SignAwareZeroPad, }
impl<'a> Arguments<'a> {
/// When using the format_args!() macro, this function is used to generate the
/// Arguments structure.
#[doc(hidden)] #[inline]
#[unstable(feature = "core",
reason = "implementation detail of the `format_args!` macro")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new_v1(pieces: &'a [&'a str],
args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
Arguments {
pieces: pieces,
fmt: None,
args: args
}
}
/// When using the format_args!() macro, this function is used to generate the
/// Arguments structure.
#[doc(hidden)] #[inline]
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(pieces: &'a [&'a str],
args: &'a [Argument<'a>]) -> Arguments<'a> {
args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
Arguments {
pieces: pieces,
fmt: None,
@ -185,11 +212,28 @@ impl<'a> Arguments<'a> {
/// created with `argumentuint`. However, failing to do so doesn't cause
/// unsafety, but will ignore invalid .
#[doc(hidden)] #[inline]
#[unstable(feature = "core",
reason = "implementation detail of the `format_args!` macro")]
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_placeholders(pieces: &'a [&'a str],
fmt: &'a [rt::Argument],
args: &'a [Argument<'a>]) -> Arguments<'a> {
fmt: &'a [rt::v1::Argument],
args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
Arguments {
pieces: pieces,
fmt: Some(fmt),
args: args
}
}
/// This function is used to specify nonstandard formatting parameters.
/// The `pieces` array must be at least as long as `fmt` to construct
/// a valid Arguments structure. Also, any `Count` within `fmt` that is
/// `CountIsParam` or `CountIsNextParam` has to point to an argument
/// created with `argumentuint`. However, failing to do so doesn't cause
/// unsafety, but will ignore invalid .
#[doc(hidden)] #[inline]
#[cfg(not(stage0))]
pub fn new_v1_formatted(pieces: &'a [&'a str],
args: &'a [ArgumentV1<'a>],
fmt: &'a [rt::v1::Argument]) -> Arguments<'a> {
Arguments {
pieces: pieces,
fmt: Some(fmt),
@ -214,11 +258,11 @@ pub struct Arguments<'a> {
pieces: &'a [&'a str],
// Placeholder specs, or `None` if all specs are default (as in "{}{}").
fmt: Option<&'a [rt::Argument]>,
fmt: Option<&'a [rt::v1::Argument]>,
// Dynamic arguments for interpolation, to be interleaved with string
// pieces. (Every argument is preceded by a string piece.)
args: &'a [Argument<'a>],
args: &'a [ArgumentV1<'a>],
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -237,20 +281,20 @@ impl<'a> Display for Arguments<'a> {
/// Format trait for the `:?` format. Useful for debugging, all types
/// should implement this.
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[deprecated(since = "1.0.0", reason = "renamed to Debug")]
#[unstable(feature = "old_fmt")]
pub trait Show {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
/// Format trait for the `:?` format. Useful for debugging, all types
/// should implement this.
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is defined in your \
crate, add `#[derive(Debug)]` or manually implement it"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \
defined in your crate, add `#[derive(Debug)]` or \
manually implement it"]
#[lang = "debug_trait"]
pub trait Debug {
/// Formats the value using the given formatter.
@ -264,19 +308,20 @@ impl<T: Show + ?Sized> Debug for T {
/// When a value can be semantically expressed as a String, this trait may be
/// used. It corresponds to the default format, `{}`.
#[unstable(feature = "core")]
#[deprecated(since = "1.0.0", reason = "renamed to Display")]
#[unstable(feature = "old_fmt")]
pub trait String {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
/// When a value can be semantically expressed as a String, this trait may be
/// used. It corresponds to the default format, `{}`.
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[rustc_on_unimplemented = "`{Self}` cannot be formatted with the default formatter; try using \
`:?` instead if you are using a format string"]
#[rustc_on_unimplemented = "`{Self}` cannot be formatted with the default \
formatter; try using `:?` instead if you are using \
a format string"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Display {
/// Formats the value using the given formatter.
fn fmt(&self, &mut Formatter) -> Result;
@ -288,58 +333,58 @@ impl<T: String + ?Sized> Display for T {
}
/// Format trait for the `o` character
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Octal {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
/// Format trait for the `b` character
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Binary {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
/// Format trait for the `x` character
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait LowerHex {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
/// Format trait for the `X` character
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait UpperHex {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
/// Format trait for the `p` character
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Pointer {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
/// Format trait for the `e` character
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait LowerExp {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
/// Format trait for the `E` character
#[unstable(feature = "core",
reason = "I/O and core have yet to be reconciled")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait UpperExp {
/// Formats the value using the given formatter.
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, &mut Formatter) -> Result;
}
@ -351,16 +396,14 @@ pub trait UpperExp {
///
/// * output - the buffer to write output to
/// * args - the precompiled arguments generated by `format_args!`
#[unstable(feature = "core",
reason = "libcore and I/O have yet to be reconciled, and this is an \
implementation detail which should not otherwise be exported")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write(output: &mut Writer, args: Arguments) -> Result {
let mut formatter = Formatter {
flags: 0,
width: None,
precision: None,
buf: output,
align: rt::AlignUnknown,
align: Alignment::Unknown,
fill: ' ',
args: args.args,
curarg: args.args.iter(),
@ -402,7 +445,7 @@ impl<'a> Formatter<'a> {
// First up is the collection of functions used to execute a format string
// at runtime. This consumes all of the compile-time statics generated by
// the format! syntax extension.
fn run(&mut self, arg: &rt::Argument) -> Result {
fn run(&mut self, arg: &rt::v1::Argument) -> Result {
// Fill in the format parameters into the formatter
self.fill = arg.format.fill;
self.align = arg.format.align;
@ -412,22 +455,22 @@ impl<'a> Formatter<'a> {
// Extract the correct argument
let value = match arg.position {
rt::ArgumentNext => { *self.curarg.next().unwrap() }
rt::ArgumentIs(i) => self.args[i],
rt::v1::Position::Next => { *self.curarg.next().unwrap() }
rt::v1::Position::At(i) => self.args[i],
};
// Then actually do some printing
(value.formatter)(value.value, self)
}
fn getcount(&mut self, cnt: &rt::Count) -> Option<uint> {
fn getcount(&mut self, cnt: &rt::v1::Count) -> Option<uint> {
match *cnt {
rt::CountIs(n) => Some(n),
rt::CountImplied => None,
rt::CountIsParam(i) => {
rt::v1::Count::Is(n) => Some(n),
rt::v1::Count::Implied => None,
rt::v1::Count::Param(i) => {
self.args[i].as_uint()
}
rt::CountIsNextParam => {
rt::v1::Count::NextParam => {
self.curarg.next().and_then(|arg| arg.as_uint())
}
}
@ -437,8 +480,8 @@ impl<'a> Formatter<'a> {
// all formatting traits can use.
/// Performs the correct padding for an integer which has already been
/// emitted into a byte-array. The byte-array should *not* contain the sign
/// for the integer, that will be added by this method.
/// emitted into a str. The str should *not* contain the sign for the
/// integer, that will be added by this method.
///
/// # Arguments
///
@ -449,27 +492,25 @@ impl<'a> Formatter<'a> {
///
/// This function will correctly account for the flags provided as well as
/// the minimum width. It will not take precision into account.
#[unstable(feature = "core",
reason = "definition may change slightly over time")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn pad_integral(&mut self,
is_positive: bool,
prefix: &str,
buf: &str)
-> Result {
use char::CharExt;
use fmt::rt::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
let mut width = buf.len();
let mut sign = None;
if !is_positive {
sign = Some('-'); width += 1;
} else if self.flags & (1 << (FlagSignPlus as uint)) != 0 {
} else if self.flags & (1 << (FlagV1::SignPlus as uint)) != 0 {
sign = Some('+'); width += 1;
}
let mut prefixed = false;
if self.flags & (1 << (FlagAlternate as uint)) != 0 {
if self.flags & (1 << (FlagV1::Alternate as uint)) != 0 {
prefixed = true; width += prefix.char_len();
}
@ -499,16 +540,16 @@ impl<'a> Formatter<'a> {
}
// The sign and prefix goes before the padding if the fill character
// is zero
Some(min) if self.flags & (1 << (FlagSignAwareZeroPad as uint)) != 0 => {
Some(min) if self.flags & (1 << (FlagV1::SignAwareZeroPad as uint)) != 0 => {
self.fill = '0';
try!(write_prefix(self));
self.with_padding(min - width, rt::AlignRight, |f| {
self.with_padding(min - width, Alignment::Right, |f| {
f.buf.write_str(buf)
})
}
// Otherwise, the sign and prefix goes after the padding
Some(min) => {
self.with_padding(min - width, rt::AlignRight, |f| {
self.with_padding(min - width, Alignment::Right, |f| {
try!(write_prefix(f)); f.buf.write_str(buf)
})
}
@ -526,8 +567,7 @@ impl<'a> Formatter<'a> {
/// is longer than this length
///
/// Notably this function ignored the `flag` parameters
#[unstable(feature = "core",
reason = "definition may change slightly over time")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn pad(&mut self, s: &str) -> Result {
// Make sure there's a fast path up front
if self.width.is_none() && self.precision.is_none() {
@ -561,7 +601,7 @@ impl<'a> Formatter<'a> {
// If we're under both the maximum and the minimum width, then fill
// up the minimum width with the specified string + some alignment.
Some(width) => {
self.with_padding(width - s.char_len(), rt::AlignLeft, |me| {
self.with_padding(width - s.char_len(), Alignment::Left, |me| {
me.buf.write_str(s)
})
}
@ -570,19 +610,20 @@ impl<'a> Formatter<'a> {
/// Runs a callback, emitting the correct padding either before or
/// afterwards depending on whether right or left alignment is requested.
fn with_padding<F>(&mut self, padding: uint, default: rt::Alignment, f: F) -> Result where
F: FnOnce(&mut Formatter) -> Result,
fn with_padding<F>(&mut self, padding: uint, default: Alignment,
f: F) -> Result
where F: FnOnce(&mut Formatter) -> Result,
{
use char::CharExt;
let align = match self.align {
rt::AlignUnknown => default,
Alignment::Unknown => default,
_ => self.align
};
let (pre_pad, post_pad) = match align {
rt::AlignLeft => (0, padding),
rt::AlignRight | rt::AlignUnknown => (padding, 0),
rt::AlignCenter => (padding / 2, (padding + 1) / 2),
Alignment::Left => (0, padding),
Alignment::Right | Alignment::Unknown => (padding, 0),
Alignment::Center => (padding / 2, (padding + 1) / 2),
};
let mut fill = [0u8; 4];
@ -604,23 +645,20 @@ impl<'a> Formatter<'a> {
/// Writes some data to the underlying buffer contained within this
/// formatter.
#[unstable(feature = "core",
reason = "reconciling core and I/O may alter this definition")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write_str(&mut self, data: &str) -> Result {
self.buf.write_str(data)
}
/// Writes some formatted information into this instance
#[unstable(feature = "core",
reason = "reconciling core and I/O may alter this definition")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write_fmt(&mut self, fmt: Arguments) -> Result {
write(self.buf, fmt)
}
/// Flags for formatting (packed version of rt::Flag)
#[unstable(feature = "core",
reason = "return type may change and method was just created")]
pub fn flags(&self) -> uint { self.flags }
#[stable(feature = "rust1", since = "1.0.0")]
pub fn flags(&self) -> usize { self.flags }
/// Character used as 'fill' whenever there is alignment
#[unstable(feature = "core", reason = "method was just created")]
@ -628,7 +666,7 @@ impl<'a> Formatter<'a> {
/// Flag indicating what form of alignment was requested
#[unstable(feature = "core", reason = "method was just created")]
pub fn align(&self) -> rt::Alignment { self.align }
pub fn align(&self) -> Alignment { self.align }
/// Optionally specified integer width that the output should be
#[unstable(feature = "core", reason = "method was just created")]
@ -649,20 +687,20 @@ impl Display for Error {
/// This is a function which calls are emitted to by the compiler itself to
/// create the Argument structures that are passed into the `format` function.
#[doc(hidden)] #[inline]
#[unstable(feature = "core",
reason = "implementation detail of the `format_args!` macro")]
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn argument<'a, T>(f: fn(&T, &mut Formatter) -> Result,
t: &'a T) -> Argument<'a> {
Argument::new(t, f)
t: &'a T) -> ArgumentV1<'a> {
ArgumentV1::new(t, f)
}
/// When the compiler determines that the type of an argument *must* be a uint
/// (such as for width and precision), then it invokes this method.
#[doc(hidden)] #[inline]
#[unstable(feature = "core",
reason = "implementation detail of the `format_args!` macro")]
pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
Argument::from_uint(s)
#[cfg(stage0)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn argumentuint<'a>(s: &'a uint) -> ArgumentV1<'a> {
ArgumentV1::from_uint(s)
}
// Implementations of the core formatting traits
@ -741,9 +779,9 @@ impl Display for char {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Pointer for *const T {
fn fmt(&self, f: &mut Formatter) -> Result {
f.flags |= 1 << (rt::FlagAlternate as uint);
f.flags |= 1 << (FlagV1::Alternate as uint);
let ret = LowerHex::fmt(&(*self as uint), f);
f.flags &= !(1 << (rt::FlagAlternate as uint));
f.flags &= !(1 << (FlagV1::Alternate as uint));
ret
}
}
@ -899,7 +937,7 @@ impl<'a> Debug for &'a (any::Any+'a) {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for [T] {
fn fmt(&self, f: &mut Formatter) -> Result {
if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
if f.flags & (1 << (FlagV1::Alternate as uint)) == 0 {
try!(write!(f, "["));
}
let mut is_first = true;
@ -911,7 +949,7 @@ impl<T: Debug> Debug for [T] {
}
try!(write!(f, "{:?}", *x))
}
if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
if f.flags & (1 << (FlagV1::Alternate as uint)) == 0 {
try!(write!(f, "]"));
}
Ok(())

View File

@ -1,86 +0,0 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! This is an internal module used by the ifmt! runtime. These structures are
//! emitted to static arrays to precompile format strings ahead of time.
//!
//! These definitions are similar to their `ct` equivalents, but differ in that
//! these can be statically allocated and are slightly optimized for the runtime
#![unstable(feature = "core",
reason = "implementation detail of the `format_args!` macro")]
pub use self::Alignment::*;
pub use self::Count::*;
pub use self::Position::*;
pub use self::Flag::*;
#[doc(hidden)]
#[derive(Copy)]
pub struct Argument {
pub position: Position,
pub format: FormatSpec,
}
#[doc(hidden)]
#[derive(Copy)]
pub struct FormatSpec {
pub fill: char,
pub align: Alignment,
pub flags: uint,
pub precision: Count,
pub width: Count,
}
/// Possible alignments that can be requested as part of a formatting directive.
#[derive(Copy, PartialEq)]
pub enum Alignment {
/// Indication that contents should be left-aligned.
AlignLeft,
/// Indication that contents should be right-aligned.
AlignRight,
/// Indication that contents should be center-aligned.
AlignCenter,
/// No alignment was requested.
AlignUnknown,
}
#[doc(hidden)]
#[derive(Copy)]
pub enum Count {
CountIs(uint), CountIsParam(uint), CountIsNextParam, CountImplied,
}
#[doc(hidden)]
#[derive(Copy)]
pub enum Position {
ArgumentNext, ArgumentIs(uint)
}
/// Flags which can be passed to formatting via a directive.
///
/// These flags are discovered through the `flags` field of the `Formatter`
/// structure. The flag in that structure is a union of these flags into a
/// `uint` where each flag's discriminant is the corresponding bit.
#[derive(Copy)]
pub enum Flag {
/// A flag which enables number formatting to always print the sign of a
/// number.
FlagSignPlus,
/// Currently not a used flag
FlagSignMinus,
/// Indicates that the "alternate formatting" for a type should be used.
///
/// The meaning of this flag is type-specific.
FlagAlternate,
/// Indicates that padding should be done with a `0` character as well as
/// being aware of the sign to be printed.
FlagSignAwareZeroPad,
}

94
src/libcore/fmt/rt/v1.rs Normal file
View File

@ -0,0 +1,94 @@
// Copyright 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! This is an internal module used by the ifmt! runtime. These structures are
//! emitted to static arrays to precompile format strings ahead of time.
//!
//! These definitions are similar to their `ct` equivalents, but differ in that
//! these can be statically allocated and are slightly optimized for the runtime
#![stable(feature = "rust1", since = "1.0.0")]
#[cfg(stage0)] pub use self::Position::*;
#[cfg(stage0)] pub use self::Alignment::Left as AlignLeft;
#[cfg(stage0)] pub use self::Alignment::Right as AlignRight;
#[cfg(stage0)] pub use self::Alignment::Center as AlignCenter;
#[cfg(stage0)] pub use self::Alignment::Unknown as AlignUnknown;
#[cfg(stage0)] pub use self::Count::Is as CountIs;
#[cfg(stage0)] pub use self::Count::Implied as CountImplied;
#[cfg(stage0)] pub use self::Count::Param as CountIsParam;
#[cfg(stage0)] pub use self::Count::NextParam as CountIsNextParam;
#[cfg(stage0)] pub use self::Position::Next as ArgumentNext;
#[cfg(stage0)] pub use self::Position::At as ArgumentIs;
#[derive(Copy)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Argument {
#[stable(feature = "rust1", since = "1.0.0")]
pub position: Position,
#[stable(feature = "rust1", since = "1.0.0")]
pub format: FormatSpec,
}
#[derive(Copy)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FormatSpec {
#[stable(feature = "rust1", since = "1.0.0")]
pub fill: char,
#[stable(feature = "rust1", since = "1.0.0")]
pub align: Alignment,
#[stable(feature = "rust1", since = "1.0.0")]
pub flags: uint,
#[stable(feature = "rust1", since = "1.0.0")]
pub precision: Count,
#[stable(feature = "rust1", since = "1.0.0")]
pub width: Count,
}
/// Possible alignments that can be requested as part of a formatting directive.
#[derive(Copy, PartialEq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Alignment {
/// Indication that contents should be left-aligned.
#[stable(feature = "rust1", since = "1.0.0")]
Left,
/// Indication that contents should be right-aligned.
#[stable(feature = "rust1", since = "1.0.0")]
Right,
/// Indication that contents should be center-aligned.
#[stable(feature = "rust1", since = "1.0.0")]
Center,
/// No alignment was requested.
#[stable(feature = "rust1", since = "1.0.0")]
Unknown,
}
#[derive(Copy)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Count {
#[stable(feature = "rust1", since = "1.0.0")]
Is(usize),
#[stable(feature = "rust1", since = "1.0.0")]
Param(usize),
#[stable(feature = "rust1", since = "1.0.0")]
NextParam,
#[stable(feature = "rust1", since = "1.0.0")]
Implied,
}
#[derive(Copy)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Position {
#[stable(feature = "rust1", since = "1.0.0")]
Next,
#[stable(feature = "rust1", since = "1.0.0")]
At(usize)
}

View File

@ -229,7 +229,7 @@
use self::Result::{Ok, Err};
use clone::Clone;
use fmt::Debug;
use fmt;
use iter::{Iterator, IteratorExt, DoubleEndedIterator, FromIterator, ExactSizeIterator};
use ops::{FnMut, FnOnce};
use option::Option::{self, None, Some};
@ -715,7 +715,7 @@ impl<T, E> Result<T, E> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, E: Debug> Result<T, E> {
impl<T, E: fmt::Debug> Result<T, E> {
/// Unwraps a result, yielding the content of an `Ok`.
///
/// # Panics
@ -746,7 +746,7 @@ impl<T, E: Debug> Result<T, E> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug, E> Result<T, E> {
impl<T: fmt::Debug, E> Result<T, E> {
/// Unwraps a result, yielding the content of an `Err`.
///
/// # Panics

View File

@ -362,19 +362,19 @@ impl<'a> Id<'a> {
///
/// Passing an invalid string (containing spaces, brackets,
/// quotes, ...) will return an empty `Err` value.
pub fn new<Name: IntoCow<'a, String, str>>(name: Name) -> Option<Id<'a>> {
pub fn new<Name: IntoCow<'a, String, str>>(name: Name) -> Result<Id<'a>, ()> {
let name = name.into_cow();
{
let mut chars = name.chars();
match chars.next() {
Some(c) if is_letter_or_underscore(c) => { ; },
_ => return None
_ => return Err(())
}
if !chars.all(is_constituent) {
return None
return Err(())
}
}
return Some(Id{ name: name });
return Ok(Id{ name: name });
fn is_letter_or_underscore(c: char) -> bool {
in_range('a', c, 'z') || in_range('A', c, 'Z') || c == '_'
@ -878,8 +878,8 @@ r#"digraph syntax_tree {
fn simple_id_construction() {
let id1 = Id::new("hello");
match id1 {
Some(_) => {;},
None => panic!("'hello' is not a valid value for id anymore")
Ok(_) => {;},
Err(..) => panic!("'hello' is not a valid value for id anymore")
}
}
@ -887,8 +887,8 @@ r#"digraph syntax_tree {
fn badly_formatted_id() {
let id2 = Id::new("Weird { struct : ure } !!!");
match id2 {
Some(_) => panic!("graphviz id suddenly allows spaces, brackets and stuff"),
None => {;}
Ok(_) => panic!("graphviz id suddenly allows spaces, brackets and stuff"),
Err(..) => {;}
}
}
}

View File

@ -54,10 +54,10 @@ fn replace_newline_with_backslash_l(s: String) -> String {
}
impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(&self.name[]).unwrap() }
fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(&self.name[]).ok().unwrap() }
fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> {
dot::Id::new(format!("N{}", i.node_id())).unwrap()
dot::Id::new(format!("N{}", i.node_id())).ok().unwrap()
}
fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> {

View File

@ -157,10 +157,10 @@ impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> {
impl<'a, 'tcx> dot::Labeller<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> {
fn graph_id(&self) -> dot::Id {
dot::Id::new(self.graph_name.as_slice()).unwrap()
dot::Id::new(self.graph_name.as_slice()).ok().unwrap()
}
fn node_id(&self, n: &Node) -> dot::Id {
dot::Id::new(format!("node_{}", self.node_ids.get(n).unwrap())).unwrap()
dot::Id::new(format!("node_{}", self.node_ids.get(n).unwrap())).ok().unwrap()
}
fn node_label(&self, n: &Node) -> dot::LabelText {
match *n {

View File

@ -3951,8 +3951,8 @@ mod tests {
struct ArbitraryType(uint);
let mut hm: HashMap<ArbitraryType, bool> = HashMap::new();
hm.insert(ArbitraryType(1), true);
let mut mem_buf = Vec::new();
let mut encoder = Encoder::new(&mut mem_buf as &mut fmt::Writer);
let mut mem_buf = string::String::new();
let mut encoder = Encoder::new(&mut mem_buf);
let result = hm.encode(&mut encoder);
match result.err().unwrap() {
EncoderError::BadHashmapKey => (),

View File

@ -122,7 +122,7 @@ impl Deref for CString {
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for CString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
String::from_utf8_lossy(self.as_bytes()).fmt(f)
fmt::Debug::fmt(&String::from_utf8_lossy(self.as_bytes()), f)
}
}

View File

@ -411,9 +411,10 @@ pub use core::fmt::{Display, Debug};
pub use core::fmt::{LowerHex, UpperHex, Pointer};
pub use core::fmt::{LowerExp, UpperExp};
pub use core::fmt::Error;
pub use core::fmt::{Argument, Arguments, write, radix, Radix, RadixFmt};
pub use core::fmt::{ArgumentV1, Arguments, write, radix, Radix, RadixFmt};
#[doc(hidden)]
#[cfg(stage0)]
pub use core::fmt::{argument, argumentuint};
/// The format function takes a precompiled format string and a list of
@ -431,9 +432,7 @@ pub use core::fmt::{argument, argumentuint};
/// let s = fmt::format(format_args!("Hello, {}!", "world"));
/// assert_eq!(s, "Hello, world!".to_string());
/// ```
#[unstable(feature = "std_misc",
reason = "this is an implementation detail of format! and should not \
be called directly")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn format(args: Arguments) -> string::String {
let mut output = string::String::new();
let _ = write!(&mut output, "{}", args);

View File

@ -393,14 +393,15 @@ impl Command {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for Command {
/// Format the program and arguments of a Command for display. Any
/// non-utf8 data is lossily converted using the utf8 replacement
/// character.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{}", String::from_utf8_lossy(self.program.as_bytes())));
try!(write!(f, "{:?}", self.program));
for arg in self.args.iter() {
try!(write!(f, " '{}'", String::from_utf8_lossy(arg.as_bytes())));
try!(write!(f, " '{:?}'", arg));
}
Ok(())
}

View File

@ -382,8 +382,8 @@ impl<T> !Sync for SyncSender<T> {}
/// A `send` operation can only fail if the receiving end of a channel is
/// disconnected, implying that the data could never be received. The error
/// contains the data being sent as a payload so it can be recovered.
#[derive(PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct SendError<T>(pub T);
/// An error returned from the `recv` function on a `Receiver`.
@ -396,7 +396,7 @@ pub struct RecvError;
/// This enumeration is the list of the possible reasons that try_recv could not
/// return data when called.
#[derive(PartialEq, Clone, Copy, Debug)]
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum TryRecvError {
/// This channel is currently empty, but the sender(s) have not yet
@ -412,8 +412,8 @@ pub enum TryRecvError {
/// This enumeration is the list of the possible error outcomes for the
/// `SyncSender::try_send` method.
#[derive(PartialEq, Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum TrySendError<T> {
/// The data could not be sent on the channel because it would require that
/// the callee block to send the data.

View File

@ -17,7 +17,7 @@ use ext::base::*;
use ext::base;
use ext::build::AstBuilder;
use fmt_macros as parse;
use parse::token::{InternedString, special_idents};
use parse::token::special_idents;
use parse::token;
use ptr::P;
@ -300,56 +300,35 @@ impl<'a, 'b> Context<'a, 'b> {
}
}
/// These attributes are applied to all statics that this syntax extension
/// will generate.
fn static_attrs(ecx: &ExtCtxt, fmtsp: Span) -> Vec<ast::Attribute> {
// Flag statics as `inline` so LLVM can merge duplicate globals as much
// as possible (which we're generating a whole lot of).
let unnamed = ecx.meta_word(fmtsp, InternedString::new("inline"));
let unnamed = ecx.attribute(fmtsp, unnamed);
// Do not warn format string as dead code
let dead_code = ecx.meta_word(fmtsp, InternedString::new("dead_code"));
let allow_dead_code = ecx.meta_list(fmtsp,
InternedString::new("allow"),
vec![dead_code]);
let allow_dead_code = ecx.attribute(fmtsp, allow_dead_code);
vec![unnamed, allow_dead_code]
}
fn rtpath(ecx: &ExtCtxt, s: &str) -> Vec<ast::Ident> {
vec![ecx.ident_of("std"), ecx.ident_of("fmt"), ecx.ident_of("rt"), ecx.ident_of(s)]
vec![ecx.ident_of("std"), ecx.ident_of("fmt"), ecx.ident_of("rt"),
ecx.ident_of("v1"), ecx.ident_of(s)]
}
fn trans_count(&self, c: parse::Count) -> P<ast::Expr> {
let sp = self.fmtsp;
let count = |: c, arg| {
let mut path = Context::rtpath(self.ecx, "Count");
path.push(self.ecx.ident_of(c));
match arg {
Some(arg) => self.ecx.expr_call_global(sp, path, vec![arg]),
None => self.ecx.expr_path(self.ecx.path_global(sp, path)),
}
};
match c {
parse::CountIs(i) => {
self.ecx.expr_call_global(sp, Context::rtpath(self.ecx, "CountIs"),
vec!(self.ecx.expr_usize(sp, i)))
}
parse::CountIs(i) => count("Is", Some(self.ecx.expr_usize(sp, i))),
parse::CountIsParam(i) => {
self.ecx.expr_call_global(sp, Context::rtpath(self.ecx, "CountIsParam"),
vec!(self.ecx.expr_usize(sp, i)))
}
parse::CountImplied => {
let path = self.ecx.path_global(sp, Context::rtpath(self.ecx,
"CountImplied"));
self.ecx.expr_path(path)
}
parse::CountIsNextParam => {
let path = self.ecx.path_global(sp, Context::rtpath(self.ecx,
"CountIsNextParam"));
self.ecx.expr_path(path)
count("Param", Some(self.ecx.expr_usize(sp, i)))
}
parse::CountImplied => count("Implied", None),
parse::CountIsNextParam => count("NextParam", None),
parse::CountIsName(n) => {
let i = match self.name_positions.get(n) {
Some(&i) => i,
None => 0, // error already emitted elsewhere
};
let i = i + self.args.len();
self.ecx.expr_call_global(sp, Context::rtpath(self.ecx, "CountIsParam"),
vec!(self.ecx.expr_usize(sp, i)))
count("Param", Some(self.ecx.expr_usize(sp, i)))
}
}
}
@ -373,27 +352,35 @@ impl<'a, 'b> Context<'a, 'b> {
}
parse::NextArgument(ref arg) => {
// Translate the position
let pos = match arg.position {
// These two have a direct mapping
parse::ArgumentNext => {
let path = self.ecx.path_global(sp, Context::rtpath(self.ecx,
"ArgumentNext"));
self.ecx.expr_path(path)
}
parse::ArgumentIs(i) => {
self.ecx.expr_call_global(sp, Context::rtpath(self.ecx, "ArgumentIs"),
vec!(self.ecx.expr_usize(sp, i)))
}
// Named arguments are converted to positional arguments at
// the end of the list of arguments
parse::ArgumentNamed(n) => {
let i = match self.name_positions.get(n) {
Some(&i) => i,
None => 0, // error already emitted elsewhere
};
let i = i + self.args.len();
self.ecx.expr_call_global(sp, Context::rtpath(self.ecx, "ArgumentIs"),
vec!(self.ecx.expr_usize(sp, i)))
let pos = {
let pos = |: c, arg| {
let mut path = Context::rtpath(self.ecx, "Position");
path.push(self.ecx.ident_of(c));
match arg {
Some(i) => {
let arg = self.ecx.expr_usize(sp, i);
self.ecx.expr_call_global(sp, path, vec![arg])
}
None => {
self.ecx.expr_path(self.ecx.path_global(sp, path))
}
}
};
match arg.position {
// These two have a direct mapping
parse::ArgumentNext => pos("Next", None),
parse::ArgumentIs(i) => pos("At", Some(i)),
// Named arguments are converted to positional arguments
// at the end of the list of arguments
parse::ArgumentNamed(n) => {
let i = match self.name_positions.get(n) {
Some(&i) => i,
None => 0, // error already emitted elsewhere
};
let i = i + self.args.len();
pos("At", Some(i))
}
}
};
@ -417,19 +404,16 @@ impl<'a, 'b> Context<'a, 'b> {
// Translate the format
let fill = self.ecx.expr_lit(sp, ast::LitChar(fill));
let align = |:name| {
let mut p = Context::rtpath(self.ecx, "Alignment");
p.push(self.ecx.ident_of(name));
self.ecx.path_global(sp, p)
};
let align = match arg.format.align {
parse::AlignLeft => {
self.ecx.path_global(sp, Context::rtpath(self.ecx, "AlignLeft"))
}
parse::AlignRight => {
self.ecx.path_global(sp, Context::rtpath(self.ecx, "AlignRight"))
}
parse::AlignCenter => {
self.ecx.path_global(sp, Context::rtpath(self.ecx, "AlignCenter"))
}
parse::AlignUnknown => {
self.ecx.path_global(sp, Context::rtpath(self.ecx, "AlignUnknown"))
}
parse::AlignLeft => align("Left"),
parse::AlignRight => align("Right"),
parse::AlignCenter => align("Center"),
parse::AlignUnknown => align("Unknown"),
};
let align = self.ecx.expr_path(align);
let flags = self.ecx.expr_usize(sp, arg.format.flags);
@ -465,7 +449,7 @@ impl<'a, 'b> Context<'a, 'b> {
let st = ast::ItemStatic(ty, ast::MutImmutable, slice);
let name = ecx.ident_of(name);
let item = ecx.item(fmtsp, name, Context::static_attrs(ecx, fmtsp), st);
let item = ecx.item(fmtsp, name, vec![], st);
let decl = respan(fmtsp, ast::DeclItem(item));
// Wrap the declaration in a block so that it forms a single expression.
@ -575,7 +559,7 @@ impl<'a, 'b> Context<'a, 'b> {
// Now create the fmt::Arguments struct with all our locals we created.
let (fn_name, fn_args) = if self.all_pieces_simple {
("new", vec![pieces, args_slice])
("new_v1", vec![pieces, args_slice])
} else {
// Build up the static array which will store our precompiled
// nonstandard placeholders, if there are any.
@ -587,7 +571,7 @@ impl<'a, 'b> Context<'a, 'b> {
piece_ty,
self.pieces);
("with_placeholders", vec![pieces, fmt, args_slice])
("new_v1_formatted", vec![pieces, args_slice, fmt])
};
self.ecx.expr_call_global(self.fmtsp, vec!(
@ -624,7 +608,8 @@ impl<'a, 'b> Context<'a, 'b> {
return ecx.expr_call_global(sp, vec![
ecx.ident_of("std"),
ecx.ident_of("fmt"),
ecx.ident_of("argumentuint")], vec![arg])
ecx.ident_of("ArgumentV1"),
ecx.ident_of("from_uint")], vec![arg])
}
};
@ -636,7 +621,8 @@ impl<'a, 'b> Context<'a, 'b> {
ecx.expr_call_global(sp, vec![
ecx.ident_of("std"),
ecx.ident_of("fmt"),
ecx.ident_of("argument")], vec![ecx.expr_path(format_fn), arg])
ecx.ident_of("ArgumentV1"),
ecx.ident_of("new")], vec![arg, ecx.expr_path(format_fn)])
}
}

View File

@ -13,7 +13,6 @@
#![deny(dead_code)]
#![feature(libc)]
#![feature(core)]
#![feature(collections)]
extern crate libc;

View File

@ -11,7 +11,6 @@
// compile-flags: --crate-type lib
#![deny(missing_debug_implementations)]
#![allow(unused, missing_copy_implementations)]
#![feature(core)]
use std::fmt;

View File

@ -41,41 +41,39 @@ pub fn bar() {
((::std::fmt::format as
fn(core::fmt::Arguments<'_>) -> collections::string::String {std::fmt::format})(((::std::fmt::Arguments::new
fn(core::fmt::Arguments<'_>) -> collections::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1
as
fn(&[&str], &[core::fmt::Argument<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a>::new})(({
#[inline]
#[allow(dead_code)]
static __STATIC_FMTSTR:
&'static [&'static str]
=
(&([("test"
as
&'static str)]
as
[&'static str; 1])
as
&'static [&'static str; 1]);
(__STATIC_FMTSTR
fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a>::new_v1})(({
static __STATIC_FMTSTR:
&'static [&'static str]
=
(&([("test"
as
&'static str)]
as
[&'static str; 1])
as
&'static [&'static str; 1]);
(__STATIC_FMTSTR
as
&'static [&'static str])
}
as
&'static [&'static str])
}
as
&[&str]),
(&(match (()
as
())
{
()
=>
([]
&[&str]),
(&(match (()
as
())
{
()
=>
([]
as
[core::fmt::ArgumentV1<'_>; 0]),
}
as
[core::fmt::Argument<'_>; 0]),
}
as
[core::fmt::Argument<'_>; 0])
as
&[core::fmt::Argument<'_>; 0]))
[core::fmt::ArgumentV1<'_>; 0])
as
&[core::fmt::ArgumentV1<'_>; 0]))
as
core::fmt::Arguments<'_>))
as collections::string::String);