Skip to content

Commit 3e6b29f

Browse files
committed
auto merge of #20136 : eddyb/rust/format-args, r=alexcrichton
We have the technology: no longer do you need to write closures to use `format_args!`. This is a `[breaking-change]`, as it forces you to clean up old hacks - if you had code like this: ```rust format_args!(fmt::format, "{} {} {}", a, b, c) format_args!(|args| { w.write_fmt(args) }, "{} {} {}", x, y, z) ``` change it to this: ```rust fmt::format(format_args!("{} {} {}", a, b, c)) w.write_fmt(format_args!("{} {} {}", x, y, z)) ``` To allow them to be called with `format_args!(...)` directly, several functions were modified to take `fmt::Arguments` by value instead of by reference. Also, `fmt::Arguments` derives `Copy` now in order to preserve all usecases that were previously possible.
2 parents 070ab63 + 647e54d commit 3e6b29f

File tree

22 files changed

+726
-238
lines changed

22 files changed

+726
-238
lines changed

src/libcollections/string.rs

+9
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,15 @@ pub trait ToString {
945945
}
946946

947947
impl<T: fmt::Show> ToString for T {
948+
// NOTE(stage0): Remove cfg after a snapshot
949+
#[cfg(not(stage0))]
950+
fn to_string(&self) -> String {
951+
let mut buf = Vec::<u8>::new();
952+
let _ = fmt::write(&mut buf, format_args!("{}", *self));
953+
String::from_utf8(buf).unwrap()
954+
}
955+
// NOTE(stage0): Remove method after a snapshot
956+
#[cfg(stage0)]
948957
fn to_string(&self) -> String {
949958
let mut buf = Vec::<u8>::new();
950959
let _ = format_args!(|args| fmt::write(&mut buf, args), "{}", self);

src/libcore/fmt/float.rs

+7
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,13 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
325325

326326
let mut filler = Filler { buf: &mut buf, end: &mut end };
327327
match sign {
328+
// NOTE(stage0): Remove cfg after a snapshot
329+
#[cfg(not(stage0))]
330+
SignNeg => {
331+
let _ = fmt::write(&mut filler, format_args!("{:-}", exp));
332+
}
333+
// NOTE(stage0): Remove match arm after a snapshot
334+
#[cfg(stage0)]
328335
SignNeg => {
329336
let _ = format_args!(|args| {
330337
fmt::write(&mut filler, args)

src/libcore/fmt/mod.rs

+86
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ pub trait FormatWriter {
7070
/// This function will return an instance of `FormatError` on error.
7171
fn write(&mut self, bytes: &[u8]) -> Result;
7272

73+
// NOTE(stage0): Remove cfg after a snapshot
74+
#[cfg(not(stage0))]
75+
/// Glue for usage of the `write!` macro with implementers of this trait.
76+
///
77+
/// This method should generally not be invoked manually, but rather through
78+
/// the `write!` macro itself.
79+
fn write_fmt(&mut self, args: Arguments) -> Result { write(self, args) }
80+
81+
// NOTE(stage0): Remove method after a snapshot
82+
#[cfg(stage0)]
7383
/// Glue for usage of the `write!` macro with implementers of this trait.
7484
///
7585
/// This method should generally not be invoked manually, but rather through
@@ -180,6 +190,7 @@ impl<'a> Arguments<'a> {
180190
/// macro validates the format string at compile-time so usage of the `write`
181191
/// and `format` functions can be safely performed.
182192
#[stable]
193+
#[deriving(Copy)]
183194
pub struct Arguments<'a> {
184195
// Format string pieces to print.
185196
pieces: &'a [&'a str],
@@ -193,6 +204,14 @@ pub struct Arguments<'a> {
193204
}
194205

195206
impl<'a> Show for Arguments<'a> {
207+
// NOTE(stage0): Remove cfg after a snapshot
208+
#[cfg(not(stage0))]
209+
fn fmt(&self, fmt: &mut Formatter) -> Result {
210+
write(fmt.buf, *self)
211+
}
212+
213+
// NOTE(stage0): Remove method after a snapshot
214+
#[cfg(stage0)]
196215
fn fmt(&self, fmt: &mut Formatter) -> Result {
197216
write(fmt.buf, self)
198217
}
@@ -268,6 +287,63 @@ static DEFAULT_ARGUMENT: rt::Argument<'static> = rt::Argument {
268287
}
269288
};
270289

290+
// NOTE(stage0): Remove cfg after a snapshot
291+
#[cfg(not(stage0))]
292+
/// The `write` function takes an output stream, a precompiled format string,
293+
/// and a list of arguments. The arguments will be formatted according to the
294+
/// specified format string into the output stream provided.
295+
///
296+
/// # Arguments
297+
///
298+
/// * output - the buffer to write output to
299+
/// * args - the precompiled arguments generated by `format_args!`
300+
#[experimental = "libcore and I/O have yet to be reconciled, and this is an \
301+
implementation detail which should not otherwise be exported"]
302+
pub fn write(output: &mut FormatWriter, args: Arguments) -> Result {
303+
let mut formatter = Formatter {
304+
flags: 0,
305+
width: None,
306+
precision: None,
307+
buf: output,
308+
align: rt::AlignUnknown,
309+
fill: ' ',
310+
args: args.args,
311+
curarg: args.args.iter(),
312+
};
313+
314+
let mut pieces = args.pieces.iter();
315+
316+
match args.fmt {
317+
None => {
318+
// We can use default formatting parameters for all arguments.
319+
for _ in range(0, args.args.len()) {
320+
try!(formatter.buf.write(pieces.next().unwrap().as_bytes()));
321+
try!(formatter.run(&DEFAULT_ARGUMENT));
322+
}
323+
}
324+
Some(fmt) => {
325+
// Every spec has a corresponding argument that is preceded by
326+
// a string piece.
327+
for (arg, piece) in fmt.iter().zip(pieces.by_ref()) {
328+
try!(formatter.buf.write(piece.as_bytes()));
329+
try!(formatter.run(arg));
330+
}
331+
}
332+
}
333+
334+
// There can be only one trailing string piece left.
335+
match pieces.next() {
336+
Some(piece) => {
337+
try!(formatter.buf.write(piece.as_bytes()));
338+
}
339+
None => {}
340+
}
341+
342+
Ok(())
343+
}
344+
345+
// NOTE(stage0): Remove function after a snapshot
346+
#[cfg(stage0)]
271347
/// The `write` function takes an output stream, a precompiled format string,
272348
/// and a list of arguments. The arguments will be formatted according to the
273349
/// specified format string into the output stream provided.
@@ -527,6 +603,16 @@ impl<'a> Formatter<'a> {
527603
self.buf.write(data)
528604
}
529605

606+
// NOTE(stage0): Remove cfg after a snapshot
607+
#[cfg(not(stage0))]
608+
/// Writes some formatted information into this instance
609+
#[unstable = "reconciling core and I/O may alter this definition"]
610+
pub fn write_fmt(&mut self, fmt: Arguments) -> Result {
611+
write(self.buf, fmt)
612+
}
613+
614+
// NOTE(stage0): Remove method after a snapshot
615+
#[cfg(stage0)]
530616
/// Writes some formatted information into this instance
531617
#[unstable = "reconciling core and I/O may alter this definition"]
532618
pub fn write_fmt(&mut self, fmt: &Arguments) -> Result {

src/libcore/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
//! distribution.
4040
//!
4141
//! * `rust_begin_unwind` - This function takes three arguments, a
42-
//! `&fmt::Arguments`, a `&str`, and a `uint`. These three arguments dictate
42+
//! `fmt::Arguments`, a `&str`, and a `uint`. These three arguments dictate
4343
//! the panic message, the file at which panic was invoked, and the line.
4444
//! It is up to consumers of this core library to define this panic
4545
//! function; it is only required to never return.

src/libcore/macros.rs

+34
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,30 @@
1010

1111
#![macro_escape]
1212

13+
// NOTE(stage0): Remove cfg after a snapshot
14+
#[cfg(not(stage0))]
15+
/// Entry point of task panic, for details, see std::macros
16+
#[macro_export]
17+
macro_rules! panic {
18+
() => (
19+
panic!("explicit panic")
20+
);
21+
($msg:expr) => ({
22+
static _MSG_FILE_LINE: (&'static str, &'static str, uint) = ($msg, file!(), line!());
23+
::core::panicking::panic(&_MSG_FILE_LINE)
24+
});
25+
($fmt:expr, $($arg:tt)*) => ({
26+
// The leading _'s are to avoid dead code warnings if this is
27+
// used inside a dead function. Just `#[allow(dead_code)]` is
28+
// insufficient, since the user may have
29+
// `#[forbid(dead_code)]` and which cannot be overridden.
30+
static _FILE_LINE: (&'static str, uint) = (file!(), line!());
31+
::core::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE)
32+
});
33+
}
34+
35+
// NOTE(stage0): Remove macro after a snapshot
36+
#[cfg(stage0)]
1337
/// Entry point of task panic, for details, see std::macros
1438
#[macro_export]
1539
macro_rules! panic {
@@ -105,6 +129,16 @@ macro_rules! try {
105129
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
106130
}
107131

132+
// NOTE(stage0): Remove cfg after a snapshot
133+
#[cfg(not(stage0))]
134+
/// Writing a formatted string into a writer
135+
#[macro_export]
136+
macro_rules! write {
137+
($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*)))
138+
}
139+
140+
// NOTE(stage0): Remove macro after a snapshot
141+
#[cfg(stage0)]
108142
/// Writing a formatted string into a writer
109143
#[macro_export]
110144
macro_rules! write {

src/libcore/panicking.rs

+41-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
//! interface for panicking is:
1717
//!
1818
//! ```ignore
19-
//! fn panic_impl(fmt: &fmt::Arguments, &(&'static str, uint)) -> !;
19+
//! fn panic_impl(fmt: fmt::Arguments, &(&'static str, uint)) -> !;
2020
//! ```
2121
//!
2222
//! This definition allows for panicking with any general message, but it does not
@@ -31,8 +31,20 @@
3131
#![allow(dead_code, missing_docs)]
3232

3333
use fmt;
34-
use intrinsics;
34+
// NOTE(stage0): Remove import after a snapshot
35+
#[cfg(stage0)] use intrinsics;
3536

37+
// NOTE(stage0): Remove cfg after a snapshot
38+
#[cfg(not(stage0))]
39+
#[cold] #[inline(never)] // this is the slow path, always
40+
#[lang="panic"]
41+
pub fn panic(expr_file_line: &(&'static str, &'static str, uint)) -> ! {
42+
let (expr, file, line) = *expr_file_line;
43+
panic_fmt(format_args!("{}", expr), &(file, line))
44+
}
45+
46+
// NOTE(stage0): Remove function after a snapshot
47+
#[cfg(stage0)]
3648
#[cold] #[inline(never)] // this is the slow path, always
3749
#[lang="panic"]
3850
pub fn panic(expr_file_line: &(&'static str, &'static str, uint)) -> ! {
@@ -45,6 +57,18 @@ pub fn panic(expr_file_line: &(&'static str, &'static str, uint)) -> ! {
4557
unsafe { intrinsics::abort() }
4658
}
4759

60+
// NOTE(stage0): Remove cfg after a snapshot
61+
#[cfg(not(stage0))]
62+
#[cold] #[inline(never)]
63+
#[lang="panic_bounds_check"]
64+
fn panic_bounds_check(file_line: &(&'static str, uint),
65+
index: uint, len: uint) -> ! {
66+
panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}",
67+
len, index), file_line)
68+
}
69+
70+
// NOTE(stage0): Remove function after a snapshot
71+
#[cfg(stage0)]
4872
#[cold] #[inline(never)]
4973
#[lang="panic_bounds_check"]
5074
fn panic_bounds_check(file_line: &(&'static str, uint),
@@ -55,6 +79,21 @@ fn panic_bounds_check(file_line: &(&'static str, uint),
5579
unsafe { intrinsics::abort() }
5680
}
5781

82+
// NOTE(stage0): Remove cfg after a snapshot
83+
#[cfg(not(stage0))]
84+
#[cold] #[inline(never)]
85+
pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, uint)) -> ! {
86+
#[allow(improper_ctypes)]
87+
extern {
88+
#[lang = "panic_fmt"]
89+
fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: uint) -> !;
90+
}
91+
let (file, line) = *file_line;
92+
unsafe { panic_impl(fmt, file, line) }
93+
}
94+
95+
// NOTE(stage0): Remove function after a snapshot
96+
#[cfg(stage0)]
5897
#[cold] #[inline(never)]
5998
pub fn panic_fmt(fmt: &fmt::Arguments, file_line: &(&'static str, uint)) -> ! {
6099
#[allow(improper_ctypes)]

src/liblog/lib.rs

+40-2
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ impl Drop for DefaultLogger {
268268
}
269269
}
270270

271+
// NOTE(stage0): Remove cfg after a snapshot
272+
#[cfg(not(stage0))]
271273
/// This function is called directly by the compiler when using the logging
272274
/// macros. This function does not take into account whether the log level
273275
/// specified is active or not, it will always log something if this method is
@@ -276,7 +278,7 @@ impl Drop for DefaultLogger {
276278
/// It is not recommended to call this function directly, rather it should be
277279
/// invoked through the logging family of macros.
278280
#[doc(hidden)]
279-
pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) {
281+
pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
280282
// Test the literal string from args against the current filter, if there
281283
// is one.
282284
match unsafe { FILTER.as_ref() } {
@@ -302,6 +304,42 @@ pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) {
302304
set_logger(logger);
303305
}
304306

307+
// NOTE(stage0): Remove function after a snapshot
308+
#[cfg(stage0)]
309+
/// This function is called directly by the compiler when using the logging
310+
/// macros. This function does not take into account whether the log level
311+
/// specified is active or not, it will always log something if this method is
312+
/// called.
313+
///
314+
/// It is not recommended to call this function directly, rather it should be
315+
/// invoked through the logging family of macros.
316+
#[doc(hidden)]
317+
pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) {
318+
// Test the literal string from args against the current filter, if there
319+
// is one.
320+
match unsafe { FILTER.as_ref() } {
321+
Some(filter) if !filter.is_match(args.to_string().as_slice()) => return,
322+
_ => {}
323+
}
324+
325+
// Completely remove the local logger from TLS in case anyone attempts to
326+
// frob the slot while we're doing the logging. This will destroy any logger
327+
// set during logging.
328+
let mut logger = LOCAL_LOGGER.with(|s| {
329+
s.borrow_mut().take()
330+
}).unwrap_or_else(|| {
331+
box DefaultLogger { handle: io::stderr() } as Box<Logger + Send>
332+
});
333+
logger.log(&LogRecord {
334+
level: LogLevel(level),
335+
args: *args,
336+
file: loc.file,
337+
module_path: loc.module_path,
338+
line: loc.line,
339+
});
340+
set_logger(logger);
341+
}
342+
305343
/// Getter for the global log level. This is a function so that it can be called
306344
/// safely
307345
#[doc(hidden)]
@@ -329,7 +367,7 @@ pub struct LogRecord<'a> {
329367
pub level: LogLevel,
330368

331369
/// The arguments from the log line.
332-
pub args: &'a fmt::Arguments<'a>,
370+
pub args: fmt::Arguments<'a>,
333371

334372
/// The file of where the LogRecord originated.
335373
pub file: &'a str,

0 commit comments

Comments
 (0)