about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/fmt/mod.rs843
-rw-r--r--src/libcore/fmt/num.rs470
-rw-r--r--src/libcore/fmt/rt.rs91
-rw-r--r--src/libcore/lib.rs3
4 files changed, 1407 insertions, 0 deletions
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
new file mode 100644
index 00000000000..0a45712616d
--- /dev/null
+++ b/src/libcore/fmt/mod.rs
@@ -0,0 +1,843 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Utilities for formatting and printing strings
+
+#![allow(unused_variable)]
+
+use any;
+use cast;
+use cell::Cell;
+use char::Char;
+use container::Container;
+use iter::{Iterator, range};
+use kinds::Copy;
+use option::{Option, Some, None};
+use owned::Box;
+use result;
+use result::{Ok, Err};
+use slice::{Vector, ImmutableVector};
+use slice;
+use str::StrSlice;
+use str;
+
+pub use self::num::radix;
+pub use self::num::Radix;
+pub use self::num::RadixFmt;
+
+macro_rules! write(
+    ($dst:expr, $($arg:tt)*) => ({
+        let dst: &mut ::fmt::FormatWriter = $dst;
+        format_args!(|args| { ::std::fmt::write(dst, args) }, $($arg)*)
+    })
+)
+
+mod num;
+mod float;
+pub mod rt;
+
+#[cfg(stage0)]
+#[allow(missing_doc)]
+pub mod parse {
+    #[deriving(Eq)]
+    pub enum Alignment {
+        AlignLeft,
+        AlignRight,
+        AlignUnknown,
+    }
+
+    pub enum PluralKeyword {
+        Zero,
+        One,
+        Two,
+        Few,
+        Many,
+    }
+
+    pub enum Flag {
+        FlagSignPlus,
+        FlagSignMinus,
+        FlagAlternate,
+        FlagSignAwareZeroPad,
+    }
+}
+
+pub type Result = result::Result<(), FormatError>;
+
+/// dox
+pub enum FormatError {
+    /// dox
+    WriteError,
+}
+
+/// dox
+pub trait FormatWriter {
+    /// dox
+    fn write(&mut self, bytes: &[u8]) -> Result;
+}
+
+/// A struct to represent both where to emit formatting strings to and how they
+/// should be formatted. A mutable version of this is passed to all formatting
+/// traits.
+pub struct Formatter<'a> {
+    /// Flags for formatting (packed version of rt::Flag)
+    pub flags: uint,
+    /// Character used as 'fill' whenever there is alignment
+    pub fill: char,
+    /// Boolean indication of whether the output should be left-aligned
+    pub align: rt::Alignment,
+    /// Optionally specified integer width that the output should be
+    pub width: Option<uint>,
+    /// Optionally specified precision for numeric types
+    pub precision: Option<uint>,
+
+    /// dox
+    #[cfg(stage0)]
+    pub buf: &'a mut FormatWriter,
+    #[cfg(not(stage0))]
+    buf: &'a mut FormatWriter,
+    curarg: slice::Items<'a, Argument<'a>>,
+    args: &'a [Argument<'a>],
+}
+
+enum CurrentlyFormatting<'a> {
+    Nothing,
+    RawString(&'a str),
+    Number(uint),
+}
+
+/// This struct represents the generic "argument" which is taken by the Xprintf
+/// family of functions. It contains a function to format the given value. At
+/// compile time it is ensured that the function and the value have the correct
+/// types, and then this struct is used to canonicalize arguments to one type.
+pub struct Argument<'a> {
+    formatter: extern "Rust" fn(&any::Void, &mut Formatter) -> Result,
+    value: &'a any::Void,
+}
+
+impl<'a> Arguments<'a> {
+    /// When using the format_args!() macro, this function is used to generate the
+    /// Arguments structure. The compiler inserts an `unsafe` block to call this,
+    /// which is valid because the compiler performs all necessary validation to
+    /// ensure that the resulting call to format/write would be safe.
+    #[doc(hidden)] #[inline]
+    pub unsafe fn new<'a>(fmt: &'static [rt::Piece<'static>],
+                          args: &'a [Argument<'a>]) -> Arguments<'a> {
+        Arguments{ fmt: cast::transmute(fmt), args: args }
+    }
+}
+
+/// This structure represents a safely precompiled version of a format string
+/// and its arguments. This cannot be generated at runtime because it cannot
+/// safely be done so, so no constructors are given and the fields are private
+/// to prevent modification.
+///
+/// The `format_args!` macro will safely create an instance of this structure
+/// and pass it to a user-supplied function. The macro validates the format
+/// string at compile-time so usage of the `write` and `format` functions can
+/// be safely performed.
+pub struct Arguments<'a> {
+    fmt: &'a [rt::Piece<'a>],
+    args: &'a [Argument<'a>],
+}
+
+impl<'a> Show for Arguments<'a> {
+    fn fmt(&self, fmt: &mut Formatter) -> Result {
+        write(fmt.buf, self)
+    }
+}
+
+/// 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.
+pub trait Show {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `b` character
+pub trait Bool {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `c` character
+pub trait Char {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `i` and `d` characters
+pub trait Signed {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `u` character
+pub trait Unsigned {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `o` character
+pub trait Octal {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `t` character
+pub trait Binary {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `x` character
+pub trait LowerHex {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `X` character
+pub trait UpperHex {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `s` character
+pub trait String {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `p` character
+pub trait Pointer {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `f` character
+pub trait Float {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `e` character
+pub trait LowerExp {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+/// Format trait for the `E` character
+pub trait UpperExp {
+    /// Formats the value using the given formatter.
+    fn fmt(&self, &mut Formatter) -> Result;
+}
+
+// FIXME #11938 - UFCS would make us able call the above methods
+// directly Show::show(x, fmt).
+macro_rules! uniform_fn_call_workaround {
+    ($( $name: ident, $trait_: ident; )*) => {
+        $(
+            #[doc(hidden)]
+            pub fn $name<T: $trait_>(x: &T, fmt: &mut Formatter) -> Result {
+                x.fmt(fmt)
+            }
+            )*
+    }
+}
+uniform_fn_call_workaround! {
+    secret_show, Show;
+    secret_bool, Bool;
+    secret_char, Char;
+    secret_signed, Signed;
+    secret_unsigned, Unsigned;
+    secret_octal, Octal;
+    secret_binary, Binary;
+    secret_lower_hex, LowerHex;
+    secret_upper_hex, UpperHex;
+    secret_string, String;
+    secret_pointer, Pointer;
+    secret_float, Float;
+    secret_lower_exp, LowerExp;
+    secret_upper_exp, UpperExp;
+}
+
+/// The `write` function takes an output stream, a precompiled format string,
+/// and a list of arguments. The arguments will be formatted according to the
+/// specified format string into the output stream provided.
+///
+/// # Arguments
+///
+///   * output - the buffer to write output to
+///   * args - the precompiled arguments generated by `format_args!`
+pub fn write(output: &mut FormatWriter, args: &Arguments) -> Result {
+    let mut formatter = Formatter {
+        flags: 0,
+        width: None,
+        precision: None,
+        buf: output,
+        align: rt::AlignUnknown,
+        fill: ' ',
+        args: args.args,
+        curarg: args.args.iter(),
+    };
+    for piece in args.fmt.iter() {
+        try!(formatter.run(piece, Nothing));
+    }
+    Ok(())
+}
+
+impl<'a> Formatter<'a> {
+
+    // First up is the collection of functions used to execute a format string
+    // at runtime. This consumes all of the compile-time statics generated by
+    // the format! syntax extension.
+
+    fn run(&mut self, piece: &rt::Piece, cur: CurrentlyFormatting) -> Result {
+        match *piece {
+            rt::String(s) => self.buf.write(s.as_bytes()),
+            rt::CurrentArgument(()) => {
+                match cur {
+                    Nothing => Ok(()),
+                    Number(n) => secret_show(&radix(n, 10), self),
+                    RawString(s) => self.buf.write(s.as_bytes()),
+                }
+            }
+            rt::Argument(ref arg) => {
+                // Fill in the format parameters into the formatter
+                self.fill = arg.format.fill;
+                self.align = arg.format.align;
+                self.flags = arg.format.flags;
+                self.width = self.getcount(&arg.format.width);
+                self.precision = self.getcount(&arg.format.precision);
+
+                // Extract the correct argument
+                let value = match arg.position {
+                    rt::ArgumentNext => { *self.curarg.next().unwrap() }
+                    rt::ArgumentIs(i) => self.args[i],
+                };
+
+                // Then actually do some printing
+                match arg.method {
+                    None => (value.formatter)(value.value, self),
+                    Some(ref method) => self.execute(*method, value)
+                }
+            }
+        }
+    }
+
+    fn getcount(&mut self, cnt: &rt::Count) -> Option<uint> {
+        match *cnt {
+            rt::CountIs(n) => { Some(n) }
+            rt::CountImplied => { None }
+            rt::CountIsParam(i) => {
+                let v = self.args[i].value;
+                unsafe { Some(*(v as *any::Void as *uint)) }
+            }
+            rt::CountIsNextParam => {
+                let v = self.curarg.next().unwrap().value;
+                unsafe { Some(*(v as *any::Void as *uint)) }
+            }
+        }
+    }
+
+    fn execute(&mut self, method: &rt::Method, arg: Argument) -> Result {
+        match *method {
+            // Pluralization is selection upon a numeric value specified as the
+            // parameter.
+            rt::Plural(offset, ref selectors, ref default) => {
+                // This is validated at compile-time to be a pointer to a
+                // '&uint' value.
+                let value: &uint = unsafe { cast::transmute(arg.value) };
+                let value = *value;
+
+                // First, attempt to match against explicit values without the
+                // offsetted value
+                for s in selectors.iter() {
+                    match s.selector {
+                        rt::Literal(val) if value == val => {
+                            return self.runplural(value, s.result);
+                        }
+                        _ => {}
+                    }
+                }
+
+                // Next, offset the value and attempt to match against the
+                // keyword selectors.
+                let value = value - match offset { Some(i) => i, None => 0 };
+                for s in selectors.iter() {
+                    let run = match s.selector {
+                        rt::Keyword(rt::Zero) => value == 0,
+                        rt::Keyword(rt::One) => value == 1,
+                        rt::Keyword(rt::Two) => value == 2,
+
+                        // FIXME: Few/Many should have a user-specified boundary
+                        //      One possible option would be in the function
+                        //      pointer of the 'arg: Argument' struct.
+                        rt::Keyword(rt::Few) => value < 8,
+                        rt::Keyword(rt::Many) => value >= 8,
+
+                        rt::Literal(..) => false
+                    };
+                    if run {
+                        return self.runplural(value, s.result);
+                    }
+                }
+
+                self.runplural(value, *default)
+            }
+
+            // Select is just a matching against the string specified.
+            rt::Select(ref selectors, ref default) => {
+                // This is validated at compile-time to be a pointer to a
+                // string slice,
+                let value: & &str = unsafe { cast::transmute(arg.value) };
+                let value = *value;
+
+                for s in selectors.iter() {
+                    if s.selector == value {
+                        for piece in s.result.iter() {
+                            try!(self.run(piece, RawString(value)));
+                        }
+                        return Ok(());
+                    }
+                }
+                for piece in default.iter() {
+                    try!(self.run(piece, RawString(value)));
+                }
+                Ok(())
+            }
+        }
+    }
+
+    fn runplural(&mut self, value: uint, pieces: &[rt::Piece]) -> Result {
+        for piece in pieces.iter() {
+            try!(self.run(piece, Number(value)));
+        }
+        Ok(())
+    }
+
+    // Helper methods used for padding and processing formatting arguments that
+    // all formatting traits can use.
+
+    /// Performs the correct padding for an integer which has already been
+    /// emitted into a byte-array. The byte-array should *not* contain the sign
+    /// for the integer, that will be added by this method.
+    ///
+    /// # Arguments
+    ///
+    /// * is_positive - whether the original integer was positive or not.
+    /// * prefix - if the '#' character (FlagAlternate) is provided, this
+    ///   is the prefix to put in front of the number.
+    /// * buf - the byte array that the number has been formatted into
+    ///
+    /// This function will correctly account for the flags provided as well as
+    /// the minimum width. It will not take precision into account.
+    pub fn pad_integral(&mut self, is_positive: bool, prefix: &str,
+                        buf: &[u8]) -> Result {
+        use fmt::rt::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
+
+        let mut width = buf.len();
+
+        let mut sign = None;
+        if !is_positive {
+            sign = Some('-'); width += 1;
+        } else if self.flags & (1 << (FlagSignPlus as uint)) != 0 {
+            sign = Some('+'); width += 1;
+        }
+
+        let mut prefixed = false;
+        if self.flags & (1 << (FlagAlternate as uint)) != 0 {
+            prefixed = true; width += prefix.len();
+        }
+
+        // Writes the sign if it exists, and then the prefix if it was requested
+        let write_prefix = |f: &mut Formatter| {
+            for c in sign.move_iter() {
+                let mut b = [0, ..4];
+                let n = c.encode_utf8(b);
+                try!(f.buf.write(b.slice_to(n)));
+            }
+            if prefixed { f.buf.write(prefix.as_bytes()) }
+            else { Ok(()) }
+        };
+
+        // The `width` field is more of a `min-width` parameter at this point.
+        match self.width {
+            // If there's no minimum length requirements then we can just
+            // write the bytes.
+            None => {
+                try!(write_prefix(self)); self.buf.write(buf)
+            }
+            // Check if we're over the minimum width, if so then we can also
+            // just write the bytes.
+            Some(min) if width >= min => {
+                try!(write_prefix(self)); self.buf.write(buf)
+            }
+            // The sign and prefix goes before the padding if the fill character
+            // is zero
+            Some(min) if self.flags & (1 << (FlagSignAwareZeroPad as uint)) != 0 => {
+                self.fill = '0';
+                try!(write_prefix(self));
+                self.with_padding(min - width, rt::AlignRight, |f| f.buf.write(buf))
+            }
+            // Otherwise, the sign and prefix goes after the padding
+            Some(min) => {
+                self.with_padding(min - width, rt::AlignRight, |f| {
+                    try!(write_prefix(f)); f.buf.write(buf)
+                })
+            }
+        }
+    }
+
+    /// This function takes a string slice and emits it to the internal buffer
+    /// after applying the relevant formatting flags specified. The flags
+    /// recognized for generic strings are:
+    ///
+    /// * width - the minimum width of what to emit
+    /// * fill/align - what to emit and where to emit it if the string
+    ///                provided needs to be padded
+    /// * precision - the maximum length to emit, the string is truncated if it
+    ///               is longer than this length
+    ///
+    /// Notably this function ignored the `flag` parameters
+    pub fn pad(&mut self, s: &str) -> Result {
+        // Make sure there's a fast path up front
+        if self.width.is_none() && self.precision.is_none() {
+            return self.buf.write(s.as_bytes());
+        }
+        // The `precision` field can be interpreted as a `max-width` for the
+        // string being formatted
+        match self.precision {
+            Some(max) => {
+                // If there's a maximum width and our string is longer than
+                // that, then we must always have truncation. This is the only
+                // case where the maximum length will matter.
+                let char_len = s.char_len();
+                if char_len >= max {
+                    let nchars = ::cmp::min(max, char_len);
+                    return self.buf.write(s.slice_chars(0, nchars).as_bytes());
+                }
+            }
+            None => {}
+        }
+        // The `width` field is more of a `min-width` parameter at this point.
+        match self.width {
+            // If we're under the maximum length, and there's no minimum length
+            // requirements, then we can just emit the string
+            None => self.buf.write(s.as_bytes()),
+            // If we're under the maximum width, check if we're over the minimum
+            // width, if so it's as easy as just emitting the string.
+            Some(width) if s.char_len() >= width => {
+                self.buf.write(s.as_bytes())
+            }
+            // If we're under both the maximum and the minimum width, then fill
+            // up the minimum width with the specified string + some alignment.
+            Some(width) => {
+                self.with_padding(width - s.len(), rt::AlignLeft, |me| {
+                    me.buf.write(s.as_bytes())
+                })
+            }
+        }
+    }
+
+    /// Runs a callback, emitting the correct padding either before or
+    /// afterwards depending on whether right or left alingment is requested.
+    fn with_padding(&mut self,
+                    padding: uint,
+                    default: rt::Alignment,
+                    f: |&mut Formatter| -> Result) -> Result {
+        let align = match self.align {
+            rt::AlignUnknown => default,
+            rt::AlignLeft | rt::AlignRight => self.align
+        };
+        if align == rt::AlignLeft {
+            try!(f(self));
+        }
+        let mut fill = [0u8, ..4];
+        let len = self.fill.encode_utf8(fill);
+        for _ in range(0, padding) {
+            try!(self.buf.write(fill.slice_to(len)));
+        }
+        if align == rt::AlignRight {
+            try!(f(self));
+        }
+        Ok(())
+    }
+
+    /// Writes some data to the underlying buffer contained within this
+    /// formatter.
+    pub fn write(&mut self, data: &[u8]) -> Result {
+        self.buf.write(data)
+    }
+
+    /// Writes some formatted information into this instance
+    pub fn write_fmt(&mut self, fmt: &Arguments) -> Result {
+        write(self.buf, fmt)
+    }
+}
+
+/// This is a function which calls are emitted to by the compiler itself to
+/// create the Argument structures that are passed into the `format` function.
+#[doc(hidden)] #[inline]
+pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result,
+                       t: &'a T) -> Argument<'a> {
+    unsafe {
+        Argument {
+            formatter: cast::transmute(f),
+            value: cast::transmute(t)
+        }
+    }
+}
+
+/// When the compiler determines that the type of an argument *must* be a string
+/// (such as for select), then it invokes this method.
+#[doc(hidden)] #[inline]
+pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> {
+    argument(secret_string, s)
+}
+
+/// When the compiler determines that the type of an argument *must* be a uint
+/// (such as for plural), then it invokes this method.
+#[doc(hidden)] #[inline]
+pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
+    argument(secret_unsigned, s)
+}
+
+// Implementations of the core formatting traits
+
+impl<T: Show> Show for @T {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
+}
+impl<T: Show> Show for Box<T> {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(&**self, f) }
+}
+impl<'a, T: Show> Show for &'a T {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_show(*self, f) }
+}
+
+impl Bool for bool {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_string(&(if *self {"true"} else {"false"}), f)
+    }
+}
+
+impl<'a, T: str::Str> String for T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        f.pad(self.as_slice())
+    }
+}
+
+impl Char for char {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        let mut utf8 = [0u8, ..4];
+        let amt = self.encode_utf8(utf8);
+        let s: &str = unsafe { cast::transmute(utf8.slice_to(amt)) };
+        secret_string(&s, f)
+    }
+}
+
+impl<T> Pointer for *T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        f.flags |= 1 << (rt::FlagAlternate as uint);
+        secret_lower_hex::<uint>(&(*self as uint), f)
+    }
+}
+impl<T> Pointer for *mut T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_pointer::<*T>(&(*self as *T), f)
+    }
+}
+impl<'a, T> Pointer for &'a T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_pointer::<*T>(&(&**self as *T), f)
+    }
+}
+impl<'a, T> Pointer for &'a mut T {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_pointer::<*T>(&(&**self as *T), f)
+    }
+}
+
+macro_rules! floating(($ty:ident) => {
+    impl Float for $ty {
+        fn fmt(&self, fmt: &mut Formatter) -> Result {
+            use num::Signed;
+
+            let digits = match fmt.precision {
+                Some(i) => float::DigExact(i),
+                None => float::DigMax(6),
+            };
+            float::float_to_str_bytes_common(self.abs(),
+                                             10,
+                                             true,
+                                             float::SignNeg,
+                                             digits,
+                                             float::ExpNone,
+                                             false,
+                                             |bytes| {
+                fmt.pad_integral(*self >= 0.0, "", bytes)
+            })
+        }
+    }
+
+    impl LowerExp for $ty {
+        fn fmt(&self, fmt: &mut Formatter) -> Result {
+            use num::Signed;
+
+            let digits = match fmt.precision {
+                Some(i) => float::DigExact(i),
+                None => float::DigMax(6),
+            };
+            float::float_to_str_bytes_common(self.abs(),
+                                             10,
+                                             true,
+                                             float::SignNeg,
+                                             digits,
+                                             float::ExpDec,
+                                             false,
+                                             |bytes| {
+                fmt.pad_integral(*self >= 0.0, "", bytes)
+            })
+        }
+    }
+
+    impl UpperExp for $ty {
+        fn fmt(&self, fmt: &mut Formatter) -> Result {
+            use num::Signed;
+
+            let digits = match fmt.precision {
+                Some(i) => float::DigExact(i),
+                None => float::DigMax(6),
+            };
+            float::float_to_str_bytes_common(self.abs(),
+                                             10,
+                                             true,
+                                             float::SignNeg,
+                                             digits,
+                                             float::ExpDec,
+                                             true,
+                                             |bytes| {
+                fmt.pad_integral(*self >= 0.0, "", bytes)
+            })
+        }
+    }
+})
+floating!(f32)
+floating!(f64)
+
+// Implementation of Show for various core types
+
+macro_rules! delegate(($ty:ty to $other:ident) => {
+    impl<'a> Show for $ty {
+        fn fmt(&self, f: &mut Formatter) -> Result {
+            (concat_idents!(secret_, $other)(self, f))
+        }
+    }
+})
+delegate!(~str to string)
+delegate!(&'a str to string)
+delegate!(bool to bool)
+delegate!(char to char)
+delegate!(f32 to float)
+delegate!(f64 to float)
+
+impl<T> Show for *T {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_pointer(self, f) }
+}
+impl<T> Show for *mut T {
+    fn fmt(&self, f: &mut Formatter) -> Result { secret_pointer(self, f) }
+}
+
+macro_rules! peel(($name:ident, $($other:ident,)*) => (tuple!($($other,)*)))
+
+macro_rules! tuple (
+    () => ();
+    ( $($name:ident,)+ ) => (
+        impl<$($name:Show),*> Show for ($($name,)*) {
+            #[allow(uppercase_variables, dead_assignment)]
+            fn fmt(&self, f: &mut Formatter) -> Result {
+                try!(write!(f.buf, "("));
+                let ($(ref $name,)*) = *self;
+                let mut n = 0;
+                $(
+                    if n > 0 {
+                        try!(write!(f.buf, ", "));
+                    }
+                    try!(write!(f.buf, "{}", *$name));
+                    n += 1;
+                )*
+                if n == 1 {
+                    try!(write!(f.buf, ","));
+                }
+                write!(f.buf, ")")
+            }
+        }
+        peel!($($name,)*)
+    )
+)
+
+tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
+
+impl Show for Box<any::Any> {
+    fn fmt(&self, f: &mut Formatter) -> Result { f.pad("Box<Any>") }
+}
+
+impl<'a> Show for &'a any::Any {
+    fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") }
+}
+
+impl<'a, T: Show> Show for &'a [T] {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
+            try!(write!(f.buf, "["));
+        }
+        let mut is_first = true;
+        for x in self.iter() {
+            if is_first {
+                is_first = false;
+            } else {
+                try!(write!(f.buf, ", "));
+            }
+            try!(write!(f.buf, "{}", *x))
+        }
+        if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
+            try!(write!(f.buf, "]"));
+        }
+        Ok(())
+    }
+}
+
+impl<'a, T: Show> Show for &'a mut [T] {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_show(&self.as_slice(), f)
+    }
+}
+
+impl<T: Show> Show for ~[T] {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        secret_show(&self.as_slice(), f)
+    }
+}
+
+impl Show for () {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        f.pad("()")
+    }
+}
+
+impl<T: Copy + Show> Show for Cell<T> {
+    fn fmt(&self, f: &mut Formatter) -> Result {
+        write!(f.buf, r"Cell \{ value: {} \}", self.get())
+    }
+}
+
+// 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/libcore/fmt/num.rs b/src/libcore/fmt/num.rs
new file mode 100644
index 00000000000..12adcee2f0f
--- /dev/null
+++ b/src/libcore/fmt/num.rs
@@ -0,0 +1,470 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Integer and floating-point number formatting
+
+// FIXME: #6220 Implement floating point formatting
+
+#![allow(unsigned_negate)]
+
+use container::Container;
+use fmt;
+use iter::{Iterator, DoubleEndedIterator};
+use num::{Int, cast, zero};
+use option::{Some, None};
+use slice::{ImmutableVector, MutableVector};
+
+/// A type that represents a specific radix
+trait GenericRadix {
+    /// The number of digits.
+    fn base(&self) -> u8;
+
+    /// A radix-specific prefix string.
+    fn prefix(&self) -> &'static str { "" }
+
+    /// Converts an integer to corresponding radix digit.
+    fn digit(&self, x: u8) -> u8;
+
+    /// Format an integer using the radix using a formatter.
+    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
+        // The radix can be as low as 2, so we need a buffer of at least 64
+        // characters for a base 2 number.
+        let mut buf = [0u8, ..64];
+        let base = cast(self.base()).unwrap();
+        let mut curr = buf.len();
+        let is_positive = x >= zero();
+        if is_positive {
+            // Accumulate each digit of the number from the least significant
+            // to the most significant figure.
+            for byte in buf.mut_iter().rev() {
+                let n = x % base;                         // Get the current place value.
+                x = x / base;                             // Deaccumulate the number.
+                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
+                curr -= 1;
+                if x == zero() { break; }                 // No more digits left to accumulate.
+            }
+        } else {
+            // Do the same as above, but accounting for two's complement.
+            for byte in buf.mut_iter().rev() {
+                let n = -(x % base);                      // Get the current place value.
+                x = x / base;                             // Deaccumulate the number.
+                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
+                curr -= 1;
+                if x == zero() { break; }                 // No more digits left to accumulate.
+            }
+        }
+        f.pad_integral(is_positive, self.prefix(), buf.slice_from(curr))
+    }
+}
+
+/// A binary (base 2) radix
+#[deriving(Clone, Eq)]
+struct Binary;
+
+/// An octal (base 8) radix
+#[deriving(Clone, Eq)]
+struct Octal;
+
+/// A decimal (base 10) radix
+#[deriving(Clone, Eq)]
+struct Decimal;
+
+/// A hexadecimal (base 16) radix, formatted with lower-case characters
+#[deriving(Clone, Eq)]
+struct LowerHex;
+
+/// A hexadecimal (base 16) radix, formatted with upper-case characters
+#[deriving(Clone, Eq)]
+pub struct UpperHex;
+
+macro_rules! radix {
+    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
+        impl GenericRadix for $T {
+            fn base(&self) -> u8 { $base }
+            fn prefix(&self) -> &'static str { $prefix }
+            fn digit(&self, x: u8) -> u8 {
+                match x {
+                    $($x => $conv,)+
+                    x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
+                }
+            }
+        }
+    }
+}
+
+radix!(Binary,    2, "0b", x @  0 .. 2 => '0' as u8 + x)
+radix!(Octal,     8, "0o", x @  0 .. 7 => '0' as u8 + x)
+radix!(Decimal,  10, "",   x @  0 .. 9 => '0' as u8 + x)
+radix!(LowerHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
+                           x @ 10 ..15 => 'a' as u8 + (x - 10))
+radix!(UpperHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
+                           x @ 10 ..15 => 'A' as u8 + (x - 10))
+
+/// A radix with in the range of `2..36`.
+#[deriving(Clone, Eq)]
+pub struct Radix {
+    base: u8,
+}
+
+impl Radix {
+    fn new(base: u8) -> Radix {
+        assert!(2 <= base && base <= 36, "the base must be in the range of 0..36: {}", base);
+        Radix { base: base }
+    }
+}
+
+impl GenericRadix for Radix {
+    fn base(&self) -> u8 { self.base }
+    fn digit(&self, x: u8) -> u8 {
+        match x {
+            x @  0 ..9 => '0' as u8 + x,
+            x if x < self.base() => 'a' as u8 + (x - 10),
+            x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
+        }
+    }
+}
+
+/// A helper type for formatting radixes.
+pub struct RadixFmt<T, R>(T, R);
+
+/// Constructs a radix formatter in the range of `2..36`.
+///
+/// # Example
+///
+/// ~~~
+/// use std::fmt::radix;
+/// assert_eq!(format!("{}", radix(55, 36)), "1j".to_owned());
+/// ~~~
+pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
+    RadixFmt(x, Radix::new(base))
+}
+
+macro_rules! radix_fmt {
+    ($T:ty as $U:ty, $fmt:ident) => {
+        impl fmt::Show for RadixFmt<$T, Radix> {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                match *self { RadixFmt(ref x, radix) => radix.$fmt(*x as $U, f) }
+            }
+        }
+    }
+}
+macro_rules! int_base {
+    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
+        impl fmt::$Trait for $T {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                $Radix.fmt_int(*self as $U, f)
+            }
+        }
+    }
+}
+macro_rules! integer {
+    ($Int:ident, $Uint:ident) => {
+        int_base!(Show     for $Int as $Int   -> Decimal)
+        int_base!(Signed   for $Int as $Int   -> Decimal)
+        int_base!(Binary   for $Int as $Uint  -> Binary)
+        int_base!(Octal    for $Int as $Uint  -> Octal)
+        int_base!(LowerHex for $Int as $Uint  -> LowerHex)
+        int_base!(UpperHex for $Int as $Uint  -> UpperHex)
+        radix_fmt!($Int as $Uint, fmt_int)
+
+        int_base!(Show     for $Uint as $Uint -> Decimal)
+        int_base!(Unsigned for $Uint as $Uint -> Decimal)
+        int_base!(Binary   for $Uint as $Uint -> Binary)
+        int_base!(Octal    for $Uint as $Uint -> Octal)
+        int_base!(LowerHex for $Uint as $Uint -> LowerHex)
+        int_base!(UpperHex for $Uint as $Uint -> UpperHex)
+        radix_fmt!($Uint as $Uint, fmt_int)
+    }
+}
+integer!(int, uint)
+integer!(i8, u8)
+integer!(i16, u16)
+integer!(i32, u32)
+integer!(i64, u64)
+
+#[cfg(test)]
+mod tests {
+    use fmt::radix;
+    use super::{Binary, Octal, Decimal, LowerHex, UpperHex};
+    use super::{GenericRadix, Radix};
+    use str::StrAllocating;
+
+    #[test]
+    fn test_radix_base() {
+        assert_eq!(Binary.base(), 2);
+        assert_eq!(Octal.base(), 8);
+        assert_eq!(Decimal.base(), 10);
+        assert_eq!(LowerHex.base(), 16);
+        assert_eq!(UpperHex.base(), 16);
+        assert_eq!(Radix { base: 36 }.base(), 36);
+    }
+
+    #[test]
+    fn test_radix_prefix() {
+        assert_eq!(Binary.prefix(), "0b");
+        assert_eq!(Octal.prefix(), "0o");
+        assert_eq!(Decimal.prefix(), "");
+        assert_eq!(LowerHex.prefix(), "0x");
+        assert_eq!(UpperHex.prefix(), "0x");
+        assert_eq!(Radix { base: 36 }.prefix(), "");
+    }
+
+    #[test]
+    fn test_radix_digit() {
+        assert_eq!(Binary.digit(0), '0' as u8);
+        assert_eq!(Binary.digit(2), '2' as u8);
+        assert_eq!(Octal.digit(0), '0' as u8);
+        assert_eq!(Octal.digit(7), '7' as u8);
+        assert_eq!(Decimal.digit(0), '0' as u8);
+        assert_eq!(Decimal.digit(9), '9' as u8);
+        assert_eq!(LowerHex.digit(0), '0' as u8);
+        assert_eq!(LowerHex.digit(10), 'a' as u8);
+        assert_eq!(LowerHex.digit(15), 'f' as u8);
+        assert_eq!(UpperHex.digit(0), '0' as u8);
+        assert_eq!(UpperHex.digit(10), 'A' as u8);
+        assert_eq!(UpperHex.digit(15), 'F' as u8);
+        assert_eq!(Radix { base: 36 }.digit(0), '0' as u8);
+        assert_eq!(Radix { base: 36 }.digit(15), 'f' as u8);
+        assert_eq!(Radix { base: 36 }.digit(35), 'z' as u8);
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_hex_radix_digit_overflow() {
+        let _ = LowerHex.digit(16);
+    }
+
+    #[test]
+    fn test_format_int() {
+        // 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.
+        assert_eq!(format!("{}", 1i), "1".to_owned());
+        assert_eq!(format!("{}", 1i8), "1".to_owned());
+        assert_eq!(format!("{}", 1i16), "1".to_owned());
+        assert_eq!(format!("{}", 1i32), "1".to_owned());
+        assert_eq!(format!("{}", 1i64), "1".to_owned());
+        assert_eq!(format!("{:d}", -1i), "-1".to_owned());
+        assert_eq!(format!("{:d}", -1i8), "-1".to_owned());
+        assert_eq!(format!("{:d}", -1i16), "-1".to_owned());
+        assert_eq!(format!("{:d}", -1i32), "-1".to_owned());
+        assert_eq!(format!("{:d}", -1i64), "-1".to_owned());
+        assert_eq!(format!("{:t}", 1i), "1".to_owned());
+        assert_eq!(format!("{:t}", 1i8), "1".to_owned());
+        assert_eq!(format!("{:t}", 1i16), "1".to_owned());
+        assert_eq!(format!("{:t}", 1i32), "1".to_owned());
+        assert_eq!(format!("{:t}", 1i64), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i8), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i16), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i32), "1".to_owned());
+        assert_eq!(format!("{:x}", 1i64), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i8), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i16), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i32), "1".to_owned());
+        assert_eq!(format!("{:X}", 1i64), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i8), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i16), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i32), "1".to_owned());
+        assert_eq!(format!("{:o}", 1i64), "1".to_owned());
+
+        assert_eq!(format!("{}", 1u), "1".to_owned());
+        assert_eq!(format!("{}", 1u8), "1".to_owned());
+        assert_eq!(format!("{}", 1u16), "1".to_owned());
+        assert_eq!(format!("{}", 1u32), "1".to_owned());
+        assert_eq!(format!("{}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:u}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:t}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:x}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:X}", 1u64), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u8), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u16), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u32), "1".to_owned());
+        assert_eq!(format!("{:o}", 1u64), "1".to_owned());
+
+        // Test a larger number
+        assert_eq!(format!("{:t}", 55), "110111".to_owned());
+        assert_eq!(format!("{:o}", 55), "67".to_owned());
+        assert_eq!(format!("{:d}", 55), "55".to_owned());
+        assert_eq!(format!("{:x}", 55), "37".to_owned());
+        assert_eq!(format!("{:X}", 55), "37".to_owned());
+    }
+
+    #[test]
+    fn test_format_int_zero() {
+        assert_eq!(format!("{}", 0i), "0".to_owned());
+        assert_eq!(format!("{:d}", 0i), "0".to_owned());
+        assert_eq!(format!("{:t}", 0i), "0".to_owned());
+        assert_eq!(format!("{:o}", 0i), "0".to_owned());
+        assert_eq!(format!("{:x}", 0i), "0".to_owned());
+        assert_eq!(format!("{:X}", 0i), "0".to_owned());
+
+        assert_eq!(format!("{}", 0u), "0".to_owned());
+        assert_eq!(format!("{:u}", 0u), "0".to_owned());
+        assert_eq!(format!("{:t}", 0u), "0".to_owned());
+        assert_eq!(format!("{:o}", 0u), "0".to_owned());
+        assert_eq!(format!("{:x}", 0u), "0".to_owned());
+        assert_eq!(format!("{:X}", 0u), "0".to_owned());
+    }
+
+    #[test]
+    fn test_format_int_flags() {
+        assert_eq!(format!("{:3d}", 1), "  1".to_owned());
+        assert_eq!(format!("{:>3d}", 1), "  1".to_owned());
+        assert_eq!(format!("{:>+3d}", 1), " +1".to_owned());
+        assert_eq!(format!("{:<3d}", 1), "1  ".to_owned());
+        assert_eq!(format!("{:#d}", 1), "1".to_owned());
+        assert_eq!(format!("{:#x}", 10), "0xa".to_owned());
+        assert_eq!(format!("{:#X}", 10), "0xA".to_owned());
+        assert_eq!(format!("{:#5x}", 10), "  0xa".to_owned());
+        assert_eq!(format!("{:#o}", 10), "0o12".to_owned());
+        assert_eq!(format!("{:08x}", 10), "0000000a".to_owned());
+        assert_eq!(format!("{:8x}", 10), "       a".to_owned());
+        assert_eq!(format!("{:<8x}", 10), "a       ".to_owned());
+        assert_eq!(format!("{:>8x}", 10), "       a".to_owned());
+        assert_eq!(format!("{:#08x}", 10), "0x00000a".to_owned());
+        assert_eq!(format!("{:08d}", -10), "-0000010".to_owned());
+        assert_eq!(format!("{:x}", -1u8), "ff".to_owned());
+        assert_eq!(format!("{:X}", -1u8), "FF".to_owned());
+        assert_eq!(format!("{:t}", -1u8), "11111111".to_owned());
+        assert_eq!(format!("{:o}", -1u8), "377".to_owned());
+        assert_eq!(format!("{:#x}", -1u8), "0xff".to_owned());
+        assert_eq!(format!("{:#X}", -1u8), "0xFF".to_owned());
+        assert_eq!(format!("{:#t}", -1u8), "0b11111111".to_owned());
+        assert_eq!(format!("{:#o}", -1u8), "0o377".to_owned());
+    }
+
+    #[test]
+    fn test_format_int_sign_padding() {
+        assert_eq!(format!("{:+5d}", 1), "   +1".to_owned());
+        assert_eq!(format!("{:+5d}", -1), "   -1".to_owned());
+        assert_eq!(format!("{:05d}", 1), "00001".to_owned());
+        assert_eq!(format!("{:05d}", -1), "-0001".to_owned());
+        assert_eq!(format!("{:+05d}", 1), "+0001".to_owned());
+        assert_eq!(format!("{:+05d}", -1), "-0001".to_owned());
+    }
+
+    #[test]
+    fn test_format_int_twos_complement() {
+        use {i8, i16, i32, i64};
+        assert_eq!(format!("{}", i8::MIN), "-128".to_owned());
+        assert_eq!(format!("{}", i16::MIN), "-32768".to_owned());
+        assert_eq!(format!("{}", i32::MIN), "-2147483648".to_owned());
+        assert_eq!(format!("{}", i64::MIN), "-9223372036854775808".to_owned());
+    }
+
+    #[test]
+    fn test_format_radix() {
+        assert_eq!(format!("{:04}", radix(3, 2)), "0011".to_owned());
+        assert_eq!(format!("{}", radix(55, 36)), "1j".to_owned());
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_radix_base_too_large() {
+        let _ = radix(55, 37);
+    }
+}
+
+#[cfg(test)]
+mod bench {
+    extern crate test;
+
+    mod uint {
+        use super::test::Bencher;
+        use fmt::radix;
+        use rand::{XorShiftRng, Rng};
+
+        #[bench]
+        fn format_bin(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:t}", rng.gen::<uint>()); })
+        }
+
+        #[bench]
+        fn format_oct(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:o}", rng.gen::<uint>()); })
+        }
+
+        #[bench]
+        fn format_dec(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:u}", rng.gen::<uint>()); })
+        }
+
+        #[bench]
+        fn format_hex(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:x}", rng.gen::<uint>()); })
+        }
+
+        #[bench]
+        fn format_base_36(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{}", radix(rng.gen::<uint>(), 36)); })
+        }
+    }
+
+    mod int {
+        use super::test::Bencher;
+        use fmt::radix;
+        use rand::{XorShiftRng, Rng};
+
+        #[bench]
+        fn format_bin(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:t}", rng.gen::<int>()); })
+        }
+
+        #[bench]
+        fn format_oct(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:o}", rng.gen::<int>()); })
+        }
+
+        #[bench]
+        fn format_dec(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:d}", rng.gen::<int>()); })
+        }
+
+        #[bench]
+        fn format_hex(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{:x}", rng.gen::<int>()); })
+        }
+
+        #[bench]
+        fn format_base_36(b: &mut Bencher) {
+            let mut rng = XorShiftRng::new().unwrap();
+            b.iter(|| { format!("{}", radix(rng.gen::<int>(), 36)); })
+        }
+    }
+}
diff --git a/src/libcore/fmt/rt.rs b/src/libcore/fmt/rt.rs
new file mode 100644
index 00000000000..00c8661c8e3
--- /dev/null
+++ b/src/libcore/fmt/rt.rs
@@ -0,0 +1,91 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This is an internal module used by the ifmt! runtime. These structures are
+//! emitted to static arrays to precompile format strings ahead of time.
+//!
+//! These definitions are similar to their `ct` equivalents, but differ in that
+//! these can be statically allocated and are slightly optimized for the runtime
+
+#![allow(missing_doc)]
+#![doc(hidden)]
+
+use option::Option;
+
+pub enum Piece<'a> {
+    String(&'a str),
+    // FIXME(#8259): this shouldn't require the unit-value here
+    CurrentArgument(()),
+    Argument(Argument<'a>),
+}
+
+pub struct Argument<'a> {
+    pub position: Position,
+    pub format: FormatSpec,
+    pub method: Option<&'a Method<'a>>
+}
+
+pub struct FormatSpec {
+    pub fill: char,
+    pub align: Alignment,
+    pub flags: uint,
+    pub precision: Count,
+    pub width: Count,
+}
+
+#[deriving(Eq)]
+pub enum Alignment {
+    AlignLeft,
+    AlignRight,
+    AlignUnknown,
+}
+
+pub enum Count {
+    CountIs(uint), CountIsParam(uint), CountIsNextParam, CountImplied,
+}
+
+pub enum Position {
+    ArgumentNext, ArgumentIs(uint)
+}
+
+pub enum Flag {
+    FlagSignPlus,
+    FlagSignMinus,
+    FlagAlternate,
+    FlagSignAwareZeroPad,
+}
+
+pub enum Method<'a> {
+    Plural(Option<uint>, &'a [PluralArm<'a>], &'a [Piece<'a>]),
+    Select(&'a [SelectArm<'a>], &'a [Piece<'a>]),
+}
+
+pub enum PluralSelector {
+    Keyword(PluralKeyword),
+    Literal(uint),
+}
+
+pub enum PluralKeyword {
+    Zero,
+    One,
+    Two,
+    Few,
+    Many,
+}
+
+pub struct PluralArm<'a> {
+    pub selector: PluralSelector,
+    pub result: &'a [Piece<'a>],
+}
+
+pub struct SelectArm<'a> {
+    pub selector: &'a str,
+    pub result: &'a [Piece<'a>],
+}
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 22719dc9f2d..a126766b0de 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -117,6 +117,7 @@ pub mod result;
 pub mod slice;
 pub mod str;
 pub mod tuple;
+pub mod fmt;
 
 // FIXME: this module should not exist. Once owned allocations are no longer a
 //        language type, this module can move outside to the owned allocation
@@ -130,7 +131,9 @@ mod core {
 mod std {
     pub use clone;
     pub use cmp;
+    pub use fmt;
     pub use kinds;
+    pub use option;
 
     #[cfg(test)] pub use realstd::fmt;    // needed for fail!()
     #[cfg(test)] pub use realstd::rt;     // needed for fail!()