From 109274426a7cd676b9aa1bb06afd9f86b44f6e9b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 14 Aug 2013 16:47:14 -0700 Subject: [PATCH 1/2] Implement `{:s}` for ~str and @str as well --- src/libstd/fmt/mod.rs | 6 +++--- src/test/run-pass/ifmt.rs | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index 70ec5d9319984..cd3f85e83faba 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -726,9 +726,9 @@ impl Bool for bool { } } -impl<'self> String for &'self str { - fn fmt(s: & &'self str, f: &mut Formatter) { - f.pad(*s); +impl<'self, T: str::Str> String for T { + fn fmt(s: &T, f: &mut Formatter) { + f.pad(s.as_slice()); } } diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index a0d3eb7d80328..8076c081e8774 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -45,6 +45,8 @@ pub fn main() { t!(ifmt!("{:x}", 10u), "a"); t!(ifmt!("{:X}", 10u), "A"); t!(ifmt!("{:s}", "foo"), "foo"); + t!(ifmt!("{:s}", ~"foo"), "foo"); + t!(ifmt!("{:s}", @"foo"), "foo"); t!(ifmt!("{:p}", 0x1234 as *int), "0x1234"); t!(ifmt!("{:p}", 0x1234 as *mut int), "0x1234"); t!(ifmt!("{:d}", A), "aloha"); From 22c7bbfd0c49330015e24adeb0f2c45ae669c29f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 14 Aug 2013 20:40:15 -0700 Subject: [PATCH 2/2] 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. --- src/libstd/fmt/mod.rs | 50 +++++++++++++++++++++++++++++++++++++++ src/libstd/fmt/parse.rs | 6 ++++- src/libsyntax/ext/ifmt.rs | 43 ++++++++++++++++----------------- src/test/run-pass/ifmt.rs | 30 +++++++++++++++++++---- 4 files changed, 100 insertions(+), 29 deletions(-) diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index cd3f85e83faba..29f55dc726012 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -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 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 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. diff --git a/src/libstd/fmt/parse.rs b/src/libstd/fmt/parse.rs index 0d39ae84a6057..ef8778abf0ed4 100644 --- a/src/libstd/fmt/parse.rs +++ b/src/libstd/fmt/parse.rs @@ -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; } diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs index 6999f046b7b7a..35be77b95c5f9 100644 --- a/src/libsyntax/ext/ifmt.rs +++ b/src/libsyntax/ext/ifmt.rs @@ -623,19 +623,16 @@ impl Context { fn format_arg(&self, sp: span, arg: Either, 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]) } } diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 8076c081e8774..cba28463f9906 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -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");