Skip to content

Commit cf0b4e0

Browse files
committed
auto merge of #19506 : eddyb/rust/fmt-polish, r=alexcrichton
2 parents 1e69dfa + 15ca630 commit cf0b4e0

File tree

4 files changed

+72
-77
lines changed

4 files changed

+72
-77
lines changed

src/libcore/fmt/mod.rs

+53-36
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ pub struct Formatter<'a> {
9292
args: &'a [Argument<'a>],
9393
}
9494

95+
// NB. Argument is essentially an optimized partially applied formatting function,
96+
// equivalent to `exists T.(&T, fn(&T, &mut Formatter) -> Result`.
97+
9598
enum Void {}
9699

97100
/// This struct represents the generic "argument" which is taken by the Xprintf
@@ -100,37 +103,66 @@ enum Void {}
100103
/// types, and then this struct is used to canonicalize arguments to one type.
101104
#[experimental = "implementation detail of the `format_args!` macro"]
102105
pub struct Argument<'a> {
103-
formatter: extern "Rust" fn(&Void, &mut Formatter) -> Result,
104106
value: &'a Void,
107+
formatter: fn(&Void, &mut Formatter) -> Result,
108+
}
109+
110+
impl<'a> Argument<'a> {
111+
#[inline(never)]
112+
fn show_uint(x: &uint, f: &mut Formatter) -> Result {
113+
Show::fmt(x, f)
114+
}
115+
116+
fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter) -> Result) -> Argument<'a> {
117+
unsafe {
118+
Argument {
119+
formatter: mem::transmute(f),
120+
value: mem::transmute(x)
121+
}
122+
}
123+
}
124+
125+
fn from_uint<'a>(x: &'a uint) -> Argument<'a> {
126+
Argument::new(x, Argument::show_uint)
127+
}
128+
129+
fn as_uint(&self) -> Option<uint> {
130+
if self.formatter as uint == Argument::show_uint as uint {
131+
Some(unsafe { *(self.value as *const _ as *const uint) })
132+
} else {
133+
None
134+
}
135+
}
105136
}
106137

107138
impl<'a> Arguments<'a> {
108139
/// When using the format_args!() macro, this function is used to generate the
109-
/// Arguments structure. The compiler inserts an `unsafe` block to call this,
110-
/// which is valid because the compiler performs all necessary validation to
111-
/// ensure that the resulting call to format/write would be safe.
140+
/// Arguments structure.
112141
#[doc(hidden)] #[inline]
113142
#[experimental = "implementation detail of the `format_args!` macro"]
114-
pub unsafe fn new<'a>(pieces: &'static [&'static str],
115-
args: &'a [Argument<'a>]) -> Arguments<'a> {
143+
pub fn new<'a>(pieces: &'a [&'a str],
144+
args: &'a [Argument<'a>]) -> Arguments<'a> {
116145
Arguments {
117-
pieces: mem::transmute(pieces),
146+
pieces: pieces,
118147
fmt: None,
119148
args: args
120149
}
121150
}
122151

123152
/// This function is used to specify nonstandard formatting parameters.
124153
/// The `pieces` array must be at least as long as `fmt` to construct
125-
/// a valid Arguments structure.
154+
/// a valid Arguments structure. Also, any `Count` within `fmt` that is
155+
/// `CountIsParam` or `CountIsNextParam` has to point to an argument
156+
/// created with `argumentuint`. However, failing to do so doesn't cause
157+
/// unsafety, but will ignore invalid .
126158
#[doc(hidden)] #[inline]
127159
#[experimental = "implementation detail of the `format_args!` macro"]
128-
pub unsafe fn with_placeholders<'a>(pieces: &'static [&'static str],
129-
fmt: &'static [rt::Argument<'static>],
130-
args: &'a [Argument<'a>]) -> Arguments<'a> {
160+
pub fn with_placeholders<'a>(pieces: &'a [&'a str],
161+
fmt: &'a [rt::Argument<'a>],
162+
args: &'a [Argument<'a>]) -> Arguments<'a> {
131163
Arguments {
132-
pieces: mem::transmute(pieces),
133-
fmt: Some(mem::transmute(fmt)),
164+
pieces: pieces,
165+
fmt: Some(fmt),
134166
args: args
135167
}
136168
}
@@ -312,15 +344,13 @@ impl<'a> Formatter<'a> {
312344

313345
fn getcount(&mut self, cnt: &rt::Count) -> Option<uint> {
314346
match *cnt {
315-
rt::CountIs(n) => { Some(n) }
316-
rt::CountImplied => { None }
347+
rt::CountIs(n) => Some(n),
348+
rt::CountImplied => None,
317349
rt::CountIsParam(i) => {
318-
let v = self.args[i].value;
319-
unsafe { Some(*(v as *const _ as *const uint)) }
350+
self.args[i].as_uint()
320351
}
321352
rt::CountIsNextParam => {
322-
let v = self.curarg.next().unwrap().value;
323-
unsafe { Some(*(v as *const _ as *const uint)) }
353+
self.curarg.next().and_then(|arg| arg.as_uint())
324354
}
325355
}
326356
}
@@ -533,30 +563,17 @@ impl Show for Error {
533563
/// create the Argument structures that are passed into the `format` function.
534564
#[doc(hidden)] #[inline]
535565
#[experimental = "implementation detail of the `format_args!` macro"]
536-
pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result,
566+
pub fn argument<'a, T>(f: fn(&T, &mut Formatter) -> Result,
537567
t: &'a T) -> Argument<'a> {
538-
unsafe {
539-
Argument {
540-
formatter: mem::transmute(f),
541-
value: mem::transmute(t)
542-
}
543-
}
544-
}
545-
546-
/// When the compiler determines that the type of an argument *must* be a string
547-
/// (such as for select), then it invokes this method.
548-
#[doc(hidden)] #[inline]
549-
#[experimental = "implementation detail of the `format_args!` macro"]
550-
pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> {
551-
argument(Show::fmt, s)
568+
Argument::new(t, f)
552569
}
553570

554571
/// When the compiler determines that the type of an argument *must* be a uint
555-
/// (such as for plural), then it invokes this method.
572+
/// (such as for width and precision), then it invokes this method.
556573
#[doc(hidden)] #[inline]
557574
#[experimental = "implementation detail of the `format_args!` macro"]
558575
pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
559-
argument(Show::fmt, s)
576+
Argument::from_uint(s)
560577
}
561578

562579
// Implementations of the core formatting traits

src/libstd/fmt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ pub use core::fmt::Error;
418418
pub use core::fmt::{Argument, Arguments, write, radix, Radix, RadixFmt};
419419

420420
#[doc(hidden)]
421-
pub use core::fmt::{argument, argumentstr, argumentuint};
421+
pub use core::fmt::{argument, argumentuint};
422422

423423
/// The format function takes a precompiled format string and a list of
424424
/// arguments, to return the resulting formatted string.

src/libsyntax/ext/format.rs

+8-25
Original file line numberDiff line numberDiff line change
@@ -577,17 +577,11 @@ impl<'a, 'b> Context<'a, 'b> {
577577
}
578578

579579
// Now create a vector containing all the arguments
580-
let slicename = self.ecx.ident_of("__args_vec");
581-
{
582-
let args = names.into_iter().map(|a| a.unwrap());
583-
let args = locals.into_iter().chain(args);
584-
let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
585-
lets.push(self.ecx.stmt_let(self.fmtsp, false, slicename, args));
586-
}
580+
let args = locals.into_iter().chain(names.into_iter().map(|a| a.unwrap()));
587581

588582
// Now create the fmt::Arguments struct with all our locals we created.
589583
let pieces = self.ecx.expr_ident(self.fmtsp, static_str_name);
590-
let args_slice = self.ecx.expr_ident(self.fmtsp, slicename);
584+
let args_slice = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
591585

592586
let (fn_name, fn_args) = if self.all_pieces_simple {
593587
("new", vec![pieces, args_slice])
@@ -602,29 +596,18 @@ impl<'a, 'b> Context<'a, 'b> {
602596
self.ecx.ident_of("Arguments"),
603597
self.ecx.ident_of(fn_name)), fn_args);
604598

605-
// We did all the work of making sure that the arguments
606-
// structure is safe, so we can safely have an unsafe block.
607-
let result = self.ecx.expr_block(P(ast::Block {
608-
view_items: Vec::new(),
609-
stmts: Vec::new(),
610-
expr: Some(result),
611-
id: ast::DUMMY_NODE_ID,
612-
rules: ast::UnsafeBlock(ast::CompilerGenerated),
613-
span: self.fmtsp,
614-
}));
615-
let resname = self.ecx.ident_of("__args");
616-
lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
617-
let res = self.ecx.expr_ident(self.fmtsp, resname);
618599
let result = match invocation {
619600
Call(e) => {
620601
let span = e.span;
621-
self.ecx.expr_call(span, e,
622-
vec!(self.ecx.expr_addr_of(span, res)))
602+
self.ecx.expr_call(span, e, vec![
603+
self.ecx.expr_addr_of(span, result)
604+
])
623605
}
624606
MethodCall(e, m) => {
625607
let span = e.span;
626-
self.ecx.expr_method_call(span, e, m,
627-
vec!(self.ecx.expr_addr_of(span, res)))
608+
self.ecx.expr_method_call(span, e, m, vec![
609+
self.ecx.expr_addr_of(span, result)
610+
])
628611
}
629612
};
630613
let body = self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,

src/test/pretty/issue-4264.pp

+10-15
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,6 @@
4141
static __STATIC_FMTSTR: &'static [&'static str] =
4242
(&([("test" as &'static str)] as [&'static str, ..1]) as
4343
&'static [&'static str, ..1]);
44-
let __args_vec =
45-
(&([] as [core::fmt::Argument<'_>, ..0]) as
46-
&[core::fmt::Argument<'_>, ..0]);
47-
let __args =
48-
(unsafe {
49-
((::std::fmt::Arguments::new as
50-
unsafe fn(&'static [&'static str], &'a [core::fmt::Argument<'a>]) -> core::fmt::Arguments<'a>)((__STATIC_FMTSTR
51-
as
52-
&'static [&'static str]),
53-
(__args_vec
54-
as
55-
&[core::fmt::Argument<'_>, ..0]))
56-
as core::fmt::Arguments<'_>)
57-
} as core::fmt::Arguments<'_>);
5844

5945

6046

@@ -64,7 +50,16 @@
6450

6551

6652
((::std::fmt::format as
67-
fn(&core::fmt::Arguments<'_>) -> collections::string::String)((&(__args
53+
fn(&core::fmt::Arguments<'_>) -> collections::string::String)((&((::std::fmt::Arguments::new
54+
as
55+
fn(&'a [&'a str], &'a [core::fmt::Argument<'a>]) -> core::fmt::Arguments<'a>)((__STATIC_FMTSTR
56+
as
57+
&'static [&'static str]),
58+
(&([]
59+
as
60+
[core::fmt::Argument<'_>, ..0])
61+
as
62+
&[core::fmt::Argument<'_>, ..0]))
6863
as
6964
core::fmt::Arguments<'_>)
7065
as

0 commit comments

Comments
 (0)