Delegate {} to Default instead of Poly

By using a separate trait this is overridable on a per-type basis and makes room
for the possibility of even more arguments passed in for the future.
This commit is contained in:
Alex Crichton 2013-08-14 20:40:15 -07:00
parent 109274426a
commit 22c7bbfd0c
4 changed files with 100 additions and 29 deletions

View File

@ -356,28 +356,46 @@ pub struct Argument<'self> {
priv value: &'self util::Void,
}
/// When a format is not otherwise specified, types are formatted by ascribing
/// to this trait. There is not an explicit way of selecting this trait to be
/// used for formatting, it is only if no other format is specified.
#[allow(missing_doc)]
pub trait Default { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `b` character
#[allow(missing_doc)]
pub trait Bool { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `c` character
#[allow(missing_doc)]
pub trait Char { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `i` and `d` characters
#[allow(missing_doc)]
pub trait Signed { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `u` character
#[allow(missing_doc)]
pub trait Unsigned { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `o` character
#[allow(missing_doc)]
pub trait Octal { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `b` character
#[allow(missing_doc)]
pub trait Binary { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `x` character
#[allow(missing_doc)]
pub trait LowerHex { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `X` character
#[allow(missing_doc)]
pub trait UpperHex { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `s` character
#[allow(missing_doc)]
pub trait String { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `?` character
#[allow(missing_doc)]
pub trait Poly { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `p` character
#[allow(missing_doc)]
pub trait Pointer { fn fmt(&Self, &mut Formatter); }
/// Format trait for the `f` character
#[allow(missing_doc)]
pub trait Float { fn fmt(&Self, &mut Formatter); }
@ -855,5 +873,37 @@ impl<T> Pointer for *const T {
}
}
// Implementation of Default for various core types
macro_rules! delegate(($ty:ty to $other:ident) => {
impl<'self> Default for $ty {
fn fmt(me: &$ty, f: &mut Formatter) {
$other::fmt(me, f)
}
}
})
delegate!(int to Signed)
delegate!( i8 to Signed)
delegate!(i16 to Signed)
delegate!(i32 to Signed)
delegate!(i64 to Signed)
delegate!(uint to Unsigned)
delegate!( u8 to Unsigned)
delegate!( u16 to Unsigned)
delegate!( u32 to Unsigned)
delegate!( u64 to Unsigned)
delegate!(@str to String)
delegate!(~str to String)
delegate!(&'self str to String)
delegate!(bool to Bool)
delegate!(char to Char)
delegate!(float to Float)
delegate!(f32 to Float)
delegate!(f64 to Float)
impl<T> Default for *const T {
fn fmt(me: &*const T, f: &mut Formatter) { Pointer::fmt(me, f) }
}
// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,
// it's a lot easier than creating all of the rt::Piece structures here.

View File

@ -339,7 +339,11 @@ impl<'self> Parser<'self> {
}
}
// Finally the actual format specifier
spec.ty = self.word();
if self.consume('?') {
spec.ty = "?";
} else {
spec.ty = self.word();
}
return spec;
}

View File

@ -623,19 +623,16 @@ impl Context {
fn format_arg(&self, sp: span, arg: Either<uint, @str>,
ident: ast::ident) -> @ast::expr {
let mut ty = match arg {
let ty = match arg {
Left(i) => self.arg_types[i].unwrap(),
Right(s) => *self.name_types.get(&s)
};
// Default types to '?' if nothing else is specified.
if ty == Unknown {
ty = Known(@"?");
}
let argptr = self.ecx.expr_addr_of(sp, self.ecx.expr_ident(sp, ident));
match ty {
let fmt_trait = match ty {
Unknown => "Default",
Known(tyname) => {
let fmt_trait = match tyname.as_slice() {
match tyname.as_slice() {
"?" => "Poly",
"b" => "Bool",
"c" => "Char",
@ -653,35 +650,35 @@ impl Context {
`%s`", tyname));
"Dummy"
}
};
let format_fn = self.ecx.path_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of(fmt_trait),
self.ecx.ident_of("fmt"),
]);
self.ecx.expr_call_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of("argument"),
], ~[self.ecx.expr_path(format_fn), argptr])
}
}
String => {
self.ecx.expr_call_global(sp, ~[
return self.ecx.expr_call_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of("argumentstr"),
], ~[argptr])
}
Unsigned => {
self.ecx.expr_call_global(sp, ~[
return self.ecx.expr_call_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of("argumentuint"),
], ~[argptr])
}
Unknown => { fail!() }
}
};
let format_fn = self.ecx.path_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of(fmt_trait),
self.ecx.ident_of("fmt"),
]);
self.ecx.expr_call_global(sp, ~[
self.ecx.ident_of("std"),
self.ecx.ident_of("fmt"),
self.ecx.ident_of("argument"),
], ~[self.ecx.expr_path(format_fn), argptr])
}
}

View File

@ -25,16 +25,36 @@ pub fn main() {
macro_rules! t(($a:expr, $b:expr) => { assert_eq!($a, $b.to_owned()) })
// Make sure there's a poly formatter that takes anything
t!(ifmt!("{}", 1), "1");
t!(ifmt!("{}", A), "{}");
t!(ifmt!("{}", ()), "()");
t!(ifmt!("{}", @(~1, "foo")), "@(~1, \"foo\")");
t!(ifmt!("{:?}", 1), "1");
t!(ifmt!("{:?}", A), "{}");
t!(ifmt!("{:?}", ()), "()");
t!(ifmt!("{:?}", @(~1, "foo")), "@(~1, \"foo\")");
// Various edge cases without formats
t!(ifmt!(""), "");
t!(ifmt!("hello"), "hello");
t!(ifmt!("hello \\{"), "hello {");
// default formatters should work
t!(ifmt!("{}", 1i), "1");
t!(ifmt!("{}", 1i8), "1");
t!(ifmt!("{}", 1i16), "1");
t!(ifmt!("{}", 1i32), "1");
t!(ifmt!("{}", 1i64), "1");
t!(ifmt!("{}", 1u), "1");
t!(ifmt!("{}", 1u8), "1");
t!(ifmt!("{}", 1u16), "1");
t!(ifmt!("{}", 1u32), "1");
t!(ifmt!("{}", 1u64), "1");
t!(ifmt!("{}", 1.0f), "1");
t!(ifmt!("{}", 1.0f32), "1");
t!(ifmt!("{}", 1.0f64), "1");
t!(ifmt!("{}", "a"), "a");
t!(ifmt!("{}", ~"a"), "a");
t!(ifmt!("{}", @"a"), "a");
t!(ifmt!("{}", false), "false");
t!(ifmt!("{}", 'a'), "a");
// At least exercise all the formats
t!(ifmt!("{:b}", true), "true");
t!(ifmt!("{:c}", '☃'), "");
@ -56,7 +76,7 @@ pub fn main() {
t!(ifmt!("{foo} {bar}", foo=0, bar=1), "0 1");
t!(ifmt!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
t!(ifmt!("{} {0:s}", "a"), "a a");
t!(ifmt!("{} {0}", "a"), "\"a\" \"a\"");
t!(ifmt!("{} {0}", "a"), "a a");
// Methods should probably work
t!(ifmt!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");