From 6feb58ed84d8dce2aea35a8be9fd8d7b6883f002 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 10 Aug 2013 13:38:32 -0700 Subject: [PATCH] Define integer formats for all widths Closes #1653 --- src/libstd/fmt/mod.rs | 109 ++++++++++++++++++++++---------------- src/libsyntax/ext/ifmt.rs | 1 + src/test/run-pass/ifmt.rs | 64 ++++++++++++++++++++++ 3 files changed, 129 insertions(+), 45 deletions(-) diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index a25620cfa69..7085147aaee 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -17,7 +17,6 @@ use rt::io::mem::MemWriter; use rt::io; use str; use sys; -use uint; use util; use vec; @@ -238,7 +237,7 @@ impl<'self> Formatter<'self> { } fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) { - do uint::to_str_bytes(value, 10) |buf| { + do ::uint::to_str_bytes(value, 10) |buf| { let valuestr = str::from_bytes_slice(buf); for piece in pieces.iter() { self.run(piece, Some(valuestr)); @@ -314,7 +313,7 @@ impl<'self> Formatter<'self> { // case where the maximum length will matter. let char_len = s.char_len(); if char_len >= max { - let nchars = uint::min(max, char_len); + let nchars = ::uint::min(max, char_len); self.buf.write(s.slice_chars(0, nchars).as_bytes()); return } @@ -409,53 +408,73 @@ impl Char for char { } } -impl Signed for int { - fn fmt(c: &int, f: &mut Formatter) { - do uint::to_str_bytes(c.abs() as uint, 10) |buf| { - f.pad_integral(buf, "", *c >= 0); - } - } -} - -impl Unsigned for uint { - fn fmt(c: &uint, f: &mut Formatter) { - do uint::to_str_bytes(*c, 10) |buf| { - f.pad_integral(buf, "", true); - } - } -} - -impl Octal for uint { - fn fmt(c: &uint, f: &mut Formatter) { - do uint::to_str_bytes(*c, 8) |buf| { - f.pad_integral(buf, "0o", true); - } - } -} - -impl LowerHex for uint { - fn fmt(c: &uint, f: &mut Formatter) { - do uint::to_str_bytes(*c, 16) |buf| { - f.pad_integral(buf, "0x", true); - } - } -} - -impl UpperHex for uint { - fn fmt(c: &uint, f: &mut Formatter) { - do uint::to_str_bytes(*c, 16) |buf| { - let mut local = [0u8, ..16]; - for (l, &b) in local.mut_iter().zip(buf.iter()) { - *l = match b as char { - 'a' .. 'f' => (b - 'a' as u8) + 'A' as u8, - _ => b, - }; +macro_rules! int_base(($ty:ident, $into:ident, $base:expr, + $name:ident, $prefix:expr) => { + impl $name for $ty { + fn fmt(c: &$ty, f: &mut Formatter) { + do ::$into::to_str_bytes(*c as $into, $base) |buf| { + f.pad_integral(buf, $prefix, true); } - f.pad_integral(local.slice_to(buf.len()), "0x", true); } } +}) +macro_rules! upper_hex(($ty:ident, $into:ident) => { + impl UpperHex for $ty { + fn fmt(c: &$ty, f: &mut Formatter) { + do ::$into::to_str_bytes(*c as $into, 16) |buf| { + upperhex(buf, f); + } + } + } +}) + +// Not sure why, but this causes an "unresolved enum variant, struct or const" +// when inlined into the above macro... +#[doc(hidden)] +pub fn upperhex(buf: &[u8], f: &mut Formatter) { + let mut local = [0u8, ..16]; + for i in ::iterator::range(0, buf.len()) { + local[i] = match buf[i] as char { + 'a' .. 'f' => (buf[i] - 'a' as u8) + 'A' as u8, + c => c as u8, + } + } + f.pad_integral(local.slice_to(buf.len()), "0x", true); } +// FIXME(#4375) shouldn't need an inner module +macro_rules! integer(($signed:ident, $unsigned:ident) => { + mod $signed { + use super::*; + + // Signed is special because it actuall emits the negative sign, + // nothing else should do that, however. + impl Signed for $signed { + fn fmt(c: &$signed, f: &mut Formatter) { + do ::$unsigned::to_str_bytes(c.abs() as $unsigned, 10) |buf| { + f.pad_integral(buf, "", *c >= 0); + } + } + } + int_base!($signed, $unsigned, 2, Binary, "0b") + int_base!($signed, $unsigned, 8, Octal, "0o") + int_base!($signed, $unsigned, 16, LowerHex, "0x") + upper_hex!($signed, $unsigned) + + int_base!($unsigned, $unsigned, 2, Binary, "0b") + int_base!($unsigned, $unsigned, 8, Octal, "0o") + int_base!($unsigned, $unsigned, 10, Unsigned, "") + int_base!($unsigned, $unsigned, 16, LowerHex, "0x") + upper_hex!($unsigned, $unsigned) + } +}) + +integer!(int, uint) +integer!(i8, u8) +integer!(i16, u16) +integer!(i32, u32) +integer!(i64, u64) + impl Poly for T { fn fmt(t: &T, f: &mut Formatter) { match (f.width, f.precision) { diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs index 66b091849c0..6dda3fc26e8 100644 --- a/src/libsyntax/ext/ifmt.rs +++ b/src/libsyntax/ext/ifmt.rs @@ -638,6 +638,7 @@ impl Context { "X" => "UpperHex", "s" => "String", "p" => "Pointer", + "t" => "Binary", _ => { self.ecx.span_err(sp, fmt!("unknown format trait \ `%s`", tyname)); diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index df61ac76d36..adb19e23c03 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -91,6 +91,70 @@ pub fn main() { t!(ifmt!("{:-#s}", "a"), "a"); t!(ifmt!("{:+#s}", "a"), "a"); + // Formatting integers should select the right implementation based off the + // type of the argument. Also, hex/octal/binary should be defined for + // integers, but they shouldn't emit the negative sign. + t!(ifmt!("{:d}", -1i), "-1"); + t!(ifmt!("{:d}", -1i8), "1"); + t!(ifmt!("{:d}", -1i16), "1"); + t!(ifmt!("{:d}", -1i32), "1"); + t!(ifmt!("{:d}", -1i64), "1"); + t!(ifmt!("{:t}", -1i), "1"); + t!(ifmt!("{:t}", -1i8), "1"); + t!(ifmt!("{:t}", -1i16), "1"); + t!(ifmt!("{:t}", -1i32), "1"); + t!(ifmt!("{:t}", -1i64), "1"); + t!(ifmt!("{:x}", -1i), "1"); + t!(ifmt!("{:x}", -1i8), "1"); + t!(ifmt!("{:x}", -1i16), "1"); + t!(ifmt!("{:x}", -1i32), "1"); + t!(ifmt!("{:x}", -1i64), "1"); + t!(ifmt!("{:X}", -1i), "1"); + t!(ifmt!("{:X}", -1i8), "1"); + t!(ifmt!("{:X}", -1i16), "1"); + t!(ifmt!("{:X}", -1i32), "1"); + t!(ifmt!("{:X}", -1i64), "1"); + t!(ifmt!("{:o}", -1i), "1"); + t!(ifmt!("{:o}", -1i8), "1"); + t!(ifmt!("{:o}", -1i16), "1"); + t!(ifmt!("{:o}", -1i32), "1"); + t!(ifmt!("{:o}", -1i64), "1"); + + t!(ifmt!("{:d}", 1u), "1"); + t!(ifmt!("{:d}", 1u8), "1"); + t!(ifmt!("{:d}", 1u16), "1"); + t!(ifmt!("{:d}", 1u32), "1"); + t!(ifmt!("{:d}", 1u64), "1"); + t!(ifmt!("{:t}", 1u), "1"); + t!(ifmt!("{:t}", 1u8), "1"); + t!(ifmt!("{:t}", 1u16), "1"); + t!(ifmt!("{:t}", 1u32), "1"); + t!(ifmt!("{:t}", 1u64), "1"); + t!(ifmt!("{:x}", 1u), "1"); + t!(ifmt!("{:x}", 1u8), "1"); + t!(ifmt!("{:x}", 1u16), "1"); + t!(ifmt!("{:x}", 1u32), "1"); + t!(ifmt!("{:x}", 1u64), "1"); + t!(ifmt!("{:X}", 1u), "1"); + t!(ifmt!("{:X}", 1u8), "1"); + t!(ifmt!("{:X}", 1u16), "1"); + t!(ifmt!("{:X}", 1u32), "1"); + t!(ifmt!("{:X}", 1u64), "1"); + t!(ifmt!("{:o}", 1u), "1"); + t!(ifmt!("{:o}", 1u8), "1"); + t!(ifmt!("{:o}", 1u16), "1"); + t!(ifmt!("{:o}", 1u32), "1"); + t!(ifmt!("{:o}", 1u64), "1"); + + // Test the flags for formatting integers + t!(ifmt!("{:3d}", 1), "1 "); + t!(ifmt!("{:>3d}", 1), " 1"); + t!(ifmt!("{:#d}", 1), "1"); + t!(ifmt!("{:#x}", 10u), "0xa"); + t!(ifmt!("{:#X}", 10u), "0xA"); + t!(ifmt!("{:#5x}", 10u), "0xa "); + t!(ifmt!("{:#o}", 10u), "0o12"); + // Precision overrides 0-padding // FIXME #2481: Recent gcc's report some of these as warnings /*t!(ifmt!("{:0>6.5d}", 0), ~" 00000");*/