]> git.lizzy.rs Git - rust.git/commitdiff
std: Enforce Unicode in fmt::Writer
authorAlex Crichton <alex@alexcrichton.com>
Fri, 12 Dec 2014 18:59:41 +0000 (10:59 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 2 Jan 2015 06:04:46 +0000 (22:04 -0800)
This commit is an implementation of [RFC 526][rfc] which is a change to alter
the definition of the old `fmt::FormatWriter`. The new trait, renamed to
`Writer`, now only exposes one method `write_str` in order to guarantee that all
implementations of the formatting traits can only produce valid Unicode.

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0526-fmt-text-writer.md

One of the primary improvements of this patch is the performance of the
`.to_string()` method by avoiding an almost-always redundant UTF-8 check. This
is a breaking change due to the renaming of the trait as well as the loss of the
`write` method, but migration paths should be relatively easy:

* All usage of `write` should move to `write_str`. If truly binary data was
  being written in an implementation of `Show`, then it will need to use a
  different trait or an altogether different code path.

* All usage of `write!` should continue to work as-is with no modifications.

* All usage of `Show` where implementations just delegate to another should
  continue to work as-is.

[breaking-change]

Closes #20352

25 files changed:
src/libcollections/string.rs
src/libcollections/vec.rs
src/libcore/fmt/float.rs
src/libcore/fmt/mod.rs
src/libcore/fmt/num.rs
src/librustc_driver/driver.rs
src/librustdoc/html/escape.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render.rs
src/librustdoc/lib.rs
src/libserialize/json.rs
src/libstd/failure.rs
src/libstd/fmt.rs
src/libstd/io/mod.rs
src/libstd/rt/unwind.rs
src/libstd/rt/util.rs
src/libsyntax/ast.rs
src/libtest/lib.rs
src/test/compile-fail/variance-trait-matching-2.rs
src/test/run-fail/panic-non-utf8.rs [deleted file]
src/test/run-pass/colorful-write-macros.rs
src/test/run-pass/ifmt.rs
src/test/run-pass/issue-11881.rs
src/test/run-pass/issue-15924.rs

index 37a6e690f5d30ee5688931da70761286a34b67a7..74b698361f28737873c63215e700479203edb947 100644 (file)
@@ -995,9 +995,11 @@ pub trait ToString {
 
 impl<T: fmt::Show> ToString for T {
     fn to_string(&self) -> String {
-        let mut buf = Vec::<u8>::new();
-        let _ = fmt::write(&mut buf, format_args!("{}", *self));
-        String::from_utf8(buf).unwrap()
+        use core::fmt::Writer;
+        let mut buf = String::new();
+        let _ = buf.write_fmt(format_args!("{}", self));
+        buf.shrink_to_fit();
+        buf
     }
 }
 
@@ -1073,6 +1075,13 @@ fn as_slice<'b>(&'b self) -> &'b str {
     }
 }
 
+impl fmt::Writer for String {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.push_str(s);
+        Ok(())
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use prelude::*;
index a1952352badfaa28115cfad197b07a9840bd463a..a83e35a945dc4cdd0b2dc5f511c95cdcdadc4cbf 100644 (file)
@@ -1488,9 +1488,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-impl<'a> fmt::FormatWriter for Vec<u8> {
-    fn write(&mut self, buf: &[u8]) -> fmt::Result {
-        self.push_all(buf);
+impl<'a> fmt::Writer for Vec<u8> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.push_all(s.as_bytes());
         Ok(())
     }
 }
index e1728d762ed10ac97344ea723522f81ac9fcf9f7..a39168ec1ec82bd0a33eb5dc060c9db1f9ee3e72 100644 (file)
@@ -23,7 +23,7 @@
 use ops::FnOnce;
 use result::Result::Ok;
 use slice::{mod, SliceExt};
-use str::StrExt;
+use str::{mod, StrExt};
 
 /// A flag that specifies whether to use exponential (scientific) notation.
 pub enum ExponentFormat {
@@ -95,7 +95,7 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
     exp_upper: bool,
     f: F
 ) -> U where
-    F: FnOnce(&[u8]) -> U,
+    F: FnOnce(&str) -> U,
 {
     assert!(2 <= radix && radix <= 36);
     match exp_format {
@@ -109,12 +109,12 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
     let _1: T = Float::one();
 
     match num.classify() {
-        Fp::Nan => return f("NaN".as_bytes()),
+        Fp::Nan => return f("NaN"),
         Fp::Infinite if num > _0 => {
-            return f("inf".as_bytes());
+            return f("inf");
         }
         Fp::Infinite if num < _0 => {
-            return f("-inf".as_bytes());
+            return f("-inf");
         }
         _ => {}
     }
@@ -314,11 +314,11 @@ struct Filler<'a> {
                 end: &'a mut uint,
             }
 
-            impl<'a> fmt::FormatWriter for Filler<'a> {
-                fn write(&mut self, bytes: &[u8]) -> fmt::Result {
+            impl<'a> fmt::Writer for Filler<'a> {
+                fn write_str(&mut self, s: &str) -> fmt::Result {
                     slice::bytes::copy_memory(self.buf.slice_from_mut(*self.end),
-                                              bytes);
-                    *self.end += bytes.len();
+                                              s.as_bytes());
+                    *self.end += s.len();
                     Ok(())
                 }
             }
@@ -332,5 +332,5 @@ fn write(&mut self, bytes: &[u8]) -> fmt::Result {
         }
     }
 
-    f(buf[..end])
+    f(unsafe { str::from_utf8_unchecked(buf[..end]) })
 }
index 87fcb12e29f9c95ddc442e94899f7f1dd7d47890..f2439d515b457c284d7d85a7e753f7d691299bb5 100644 (file)
@@ -24,7 +24,7 @@
 use result;
 use slice::SliceExt;
 use slice;
-use str::{StrExt, Utf8Error};
+use str::{mod, StrExt, Utf8Error};
 
 pub use self::num::radix;
 pub use self::num::Radix;
@@ -57,7 +57,7 @@
 /// library. The `write!` macro accepts an instance of `io::Writer`, and the
 /// `io::Writer` trait is favored over implementing this trait.
 #[experimental = "waiting for core and I/O reconciliation"]
-pub trait FormatWriter {
+pub trait Writer {
     /// Writes a slice of bytes into this writer, returning whether the write
     /// succeeded.
     ///
@@ -68,7 +68,7 @@ pub trait FormatWriter {
     /// # Errors
     ///
     /// This function will return an instance of `FormatError` on error.
-    fn write(&mut self, bytes: &[u8]) -> Result;
+    fn write_str(&mut self, s: &str) -> Result;
 
     /// Glue for usage of the `write!` macro with implementers of this trait.
     ///
@@ -88,7 +88,7 @@ pub struct Formatter<'a> {
     width: Option<uint>,
     precision: Option<uint>,
 
-    buf: &'a mut (FormatWriter+'a),
+    buf: &'a mut (Writer+'a),
     curarg: slice::Iter<'a, Argument<'a>>,
     args: &'a [Argument<'a>],
 }
@@ -258,17 +258,6 @@ pub trait UpperExp for Sized? {
     fn fmt(&self, &mut Formatter) -> Result;
 }
 
-static DEFAULT_ARGUMENT: rt::Argument<'static> = rt::Argument {
-    position: rt::ArgumentNext,
-    format: rt::FormatSpec {
-        fill: ' ',
-        align: rt::AlignUnknown,
-        flags: 0,
-        precision: rt::CountImplied,
-        width: rt::CountImplied,
-    }
-};
-
 /// 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.
@@ -279,7 +268,7 @@ pub trait UpperExp for Sized? {
 ///   * args - the precompiled arguments generated by `format_args!`
 #[experimental = "libcore and I/O have yet to be reconciled, and this is an \
                   implementation detail which should not otherwise be exported"]
-pub fn write(output: &mut FormatWriter, args: Arguments) -> Result {
+pub fn write(output: &mut Writer, args: Arguments) -> Result {
     let mut formatter = Formatter {
         flags: 0,
         width: None,
@@ -296,16 +285,16 @@ pub fn write(output: &mut FormatWriter, args: Arguments) -> Result {
     match args.fmt {
         None => {
             // We can use default formatting parameters for all arguments.
-            for _ in range(0, args.args.len()) {
-                try!(formatter.buf.write(pieces.next().unwrap().as_bytes()));
-                try!(formatter.run(&DEFAULT_ARGUMENT));
+            for (arg, piece) in args.args.iter().zip(pieces.by_ref()) {
+                try!(formatter.buf.write_str(*piece));
+                try!((arg.formatter)(arg.value, &mut formatter));
             }
         }
         Some(fmt) => {
             // Every spec has a corresponding argument that is preceded by
             // a string piece.
             for (arg, piece) in fmt.iter().zip(pieces.by_ref()) {
-                try!(formatter.buf.write(piece.as_bytes()));
+                try!(formatter.buf.write_str(*piece));
                 try!(formatter.run(arg));
             }
         }
@@ -314,7 +303,7 @@ pub fn write(output: &mut FormatWriter, args: Arguments) -> Result {
     // There can be only one trailing string piece left.
     match pieces.next() {
         Some(piece) => {
-            try!(formatter.buf.write(piece.as_bytes()));
+            try!(formatter.buf.write_str(*piece));
         }
         None => {}
     }
@@ -378,7 +367,7 @@ fn getcount(&mut self, cnt: &rt::Count) -> Option<uint> {
     pub fn pad_integral(&mut self,
                         is_positive: bool,
                         prefix: &str,
-                        buf: &[u8])
+                        buf: &str)
                         -> Result {
         use char::Char;
         use fmt::rt::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
@@ -402,9 +391,10 @@ pub fn pad_integral(&mut self,
             for c in sign.into_iter() {
                 let mut b = [0; 4];
                 let n = c.encode_utf8(&mut b).unwrap_or(0);
-                try!(f.buf.write(b[..n]));
+                let b = unsafe { str::from_utf8_unchecked(b[0..n]) };
+                try!(f.buf.write_str(b));
             }
-            if prefixed { f.buf.write(prefix.as_bytes()) }
+            if prefixed { f.buf.write_str(prefix) }
             else { Ok(()) }
         };
 
@@ -413,24 +403,26 @@ pub fn pad_integral(&mut self,
             // If there's no minimum length requirements then we can just
             // write the bytes.
             None => {
-                try!(write_prefix(self)); self.buf.write(buf)
+                try!(write_prefix(self)); self.buf.write_str(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)
+                try!(write_prefix(self)); self.buf.write_str(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))
+                self.with_padding(min - width, rt::AlignRight, |f| {
+                    f.buf.write_str(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)
+                    try!(write_prefix(f)); f.buf.write_str(buf)
                 })
             }
         }
@@ -451,7 +443,7 @@ pub fn pad_integral(&mut self,
     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());
+            return self.buf.write_str(s);
         }
         // The `precision` field can be interpreted as a `max-width` for the
         // string being formatted
@@ -463,7 +455,7 @@ pub fn pad(&mut self, s: &str) -> Result {
                 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());
+                    return self.buf.write_str(s.slice_chars(0, nchars));
                 }
             }
             None => {}
@@ -472,17 +464,17 @@ pub fn pad(&mut self, s: &str) -> Result {
         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()),
+            None => self.buf.write_str(s),
             // 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())
+                self.buf.write_str(s)
             }
             // 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.char_len(), rt::AlignLeft, |me| {
-                    me.buf.write(s.as_bytes())
+                    me.buf.write_str(s)
                 })
             }
         }
@@ -507,15 +499,16 @@ fn with_padding<F>(&mut self, padding: uint, default: rt::Alignment, f: F) -> Re
 
         let mut fill = [0u8; 4];
         let len = self.fill.encode_utf8(&mut fill).unwrap_or(0);
+        let fill = unsafe { str::from_utf8_unchecked(fill[..len]) };
 
         for _ in range(0, pre_pad) {
-            try!(self.buf.write(fill[..len]));
+            try!(self.buf.write_str(fill));
         }
 
         try!(f(self));
 
         for _ in range(0, post_pad) {
-            try!(self.buf.write(fill[..len]));
+            try!(self.buf.write_str(fill));
         }
 
         Ok(())
@@ -524,8 +517,8 @@ fn with_padding<F>(&mut self, padding: uint, default: rt::Alignment, f: F) -> Re
     /// Writes some data to the underlying buffer contained within this
     /// formatter.
     #[unstable = "reconciling core and I/O may alter this definition"]
-    pub fn write(&mut self, data: &[u8]) -> Result {
-        self.buf.write(data)
+    pub fn write_str(&mut self, data: &str) -> Result {
+        self.buf.write_str(data)
     }
 
     /// Writes some formatted information into this instance
@@ -616,7 +609,9 @@ fn fmt(&self, f: &mut Formatter) -> Result {
 impl<T> Pointer for *const T {
     fn fmt(&self, f: &mut Formatter) -> Result {
         f.flags |= 1 << (rt::FlagAlternate as uint);
-        LowerHex::fmt(&(*self as uint), f)
+        let ret = LowerHex::fmt(&(*self as uint), f);
+        f.flags &= !(1 << (rt::FlagAlternate as uint));
+        ret
     }
 }
 
index 7de3e847dc68350986086c7e5c4e2b4814967741..4f0cecbb24353abc591c84fea56ef35fda598c25 100644 (file)
@@ -18,6 +18,7 @@
 use iter::DoubleEndedIteratorExt;
 use num::{Int, cast};
 use slice::SliceExt;
+use str;
 
 /// A type that represents a specific radix
 #[doc(hidden)]
@@ -60,7 +61,8 @@ fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
                 if x == zero { break };                   // No more digits left to accumulate.
             }
         }
-        f.pad_integral(is_positive, self.prefix(), buf[curr..])
+        let buf = unsafe { str::from_utf8_unchecked(buf[curr..]) };
+        f.pad_integral(is_positive, self.prefix(), buf)
     }
 }
 
index 91902b906735b2ef2f50e2678519b64eb7fe0023..a92c2fe2ccbd8105b0fc05b588d322081d31c164 100644 (file)
@@ -28,7 +28,7 @@
 use rustc_trans::trans;
 use rustc_typeck as typeck;
 
-use serialize::{json, Encodable};
+use serialize::json;
 
 use std::io;
 use std::io::fs;
@@ -143,10 +143,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
     });
 
     if sess.opts.debugging_opts & config::AST_JSON_NOEXPAND != 0 {
-        let mut stdout = io::BufferedWriter::new(io::stdout());
-        let mut json = json::PrettyEncoder::new(&mut stdout);
-        // unwrapping so IoError isn't ignored
-        krate.encode(&mut json).unwrap();
+        println!("{}", json::as_json(&krate));
     }
 
     if sess.show_span() {
@@ -338,10 +335,7 @@ fn new_id(&self, old_id: ast::NodeId) -> ast::NodeId {
                    ast_map::map_crate(forest, NodeIdAssigner { sess: sess }));
 
     if sess.opts.debugging_opts & config::AST_JSON != 0 {
-        let mut stdout = io::BufferedWriter::new(io::stdout());
-        let mut json = json::PrettyEncoder::new(&mut stdout);
-        // unwrapping so IoError isn't ignored
-        map.krate().encode(&mut json).unwrap();
+        println!("{}", json::as_json(map.krate()));
     }
 
     map
index fe93dbbc081f8b688963eb8e9461073c62057ded..b4afb67170bbdb9df8854a2f6981bf2da1e6ace8 100644 (file)
@@ -29,7 +29,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         for (i, ch) in s.bytes().enumerate() {
             match ch as char {
                 '<' | '>' | '&' | '\'' | '"' => {
-                    try!(fmt.write(pile_o_bits.slice(last, i).as_bytes()));
+                    try!(fmt.write_str(pile_o_bits.slice(last, i)));
                     let s = match ch as char {
                         '>' => "&gt;",
                         '<' => "&lt;",
@@ -38,7 +38,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                         '"' => "&quot;",
                         _ => unreachable!()
                     };
-                    try!(fmt.write(s.as_bytes()));
+                    try!(fmt.write_str(s));
                     last = i + 1;
                 }
                 _ => {}
@@ -46,7 +46,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         }
 
         if last < s.len() {
-            try!(fmt.write(pile_o_bits.slice_from(last).as_bytes()));
+            try!(fmt.write_str(pile_o_bits.slice_from(last)));
         }
         Ok(())
     }
index 3c09a10f3d98ed651dd4447540d0bf6c25b4df0c..36619566f8c8af67be8f4572a6b4131543305146 100644 (file)
@@ -69,7 +69,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let &TyParamBounds(bounds) = self;
         for (i, bound) in bounds.iter().enumerate() {
             if i > 0 {
-                try!(f.write(" + ".as_bytes()));
+                try!(f.write_str(" + "));
             }
             try!(write!(f, "{}", *bound));
         }
@@ -80,24 +80,24 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Show for clean::Generics {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if self.lifetimes.len() == 0 && self.type_params.len() == 0 { return Ok(()) }
-        try!(f.write("&lt;".as_bytes()));
+        try!(f.write_str("&lt;"));
 
         for (i, life) in self.lifetimes.iter().enumerate() {
             if i > 0 {
-                try!(f.write(", ".as_bytes()));
+                try!(f.write_str(", "));
             }
             try!(write!(f, "{}", *life));
         }
 
         if self.type_params.len() > 0 {
             if self.lifetimes.len() > 0 {
-                try!(f.write(", ".as_bytes()));
+                try!(f.write_str(", "));
             }
             for (i, tp) in self.type_params.iter().enumerate() {
                 if i > 0 {
-                    try!(f.write(", ".as_bytes()))
+                    try!(f.write_str(", "))
                 }
-                try!(f.write(tp.name.as_bytes()));
+                try!(f.write_str(tp.name[]));
 
                 if tp.bounds.len() > 0 {
                     try!(write!(f, ": {}", TyParamBounds(tp.bounds.as_slice())));
@@ -109,7 +109,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 };
             }
         }
-        try!(f.write("&gt;".as_bytes()));
+        try!(f.write_str("&gt;"));
         Ok(())
     }
 }
@@ -120,10 +120,10 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if gens.where_predicates.len() == 0 {
             return Ok(());
         }
-        try!(f.write(" <span class='where'>where ".as_bytes()));
+        try!(f.write_str(" <span class='where'>where "));
         for (i, pred) in gens.where_predicates.iter().enumerate() {
             if i > 0 {
-                try!(f.write(", ".as_bytes()));
+                try!(f.write_str(", "));
             }
             match pred {
                 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
@@ -135,7 +135,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                     try!(write!(f, "{}: ", lifetime));
                     for (i, lifetime) in bounds.iter().enumerate() {
                         if i > 0 {
-                            try!(f.write(" + ".as_bytes()));
+                            try!(f.write_str(" + "));
                         }
 
                         try!(write!(f, "{}", lifetime));
@@ -146,14 +146,14 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 }
             }
         }
-        try!(f.write("</span>".as_bytes()));
+        try!(f.write_str("</span>"));
         Ok(())
     }
 }
 
 impl fmt::Show for clean::Lifetime {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(f.write(self.get_ref().as_bytes()));
+        try!(f.write_str(self.get_ref()));
         Ok(())
     }
 }
@@ -161,14 +161,14 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Show for clean::PolyTrait {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if self.lifetimes.len() > 0 {
-            try!(f.write("for&lt;".as_bytes()));
+            try!(f.write_str("for&lt;"));
             for (i, lt) in self.lifetimes.iter().enumerate() {
                 if i > 0 {
-                    try!(f.write(", ".as_bytes()));
+                    try!(f.write_str(", "));
                 }
                 try!(write!(f, "{}", lt));
             }
-            try!(f.write("&gt; ".as_bytes()));
+            try!(f.write_str("&gt; "));
         }
         write!(f, "{}", self.trait_)
     }
@@ -196,38 +196,38 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             clean::PathParameters::AngleBracketed { ref lifetimes, ref types } => {
                 if lifetimes.len() > 0 || types.len() > 0 {
-                    try!(f.write("&lt;".as_bytes()));
+                    try!(f.write_str("&lt;"));
                     let mut comma = false;
                     for lifetime in lifetimes.iter() {
                         if comma {
-                            try!(f.write(", ".as_bytes()));
+                            try!(f.write_str(", "));
                         }
                         comma = true;
                         try!(write!(f, "{}", *lifetime));
                     }
                     for ty in types.iter() {
                         if comma {
-                            try!(f.write(", ".as_bytes()));
+                            try!(f.write_str(", "));
                         }
                         comma = true;
                         try!(write!(f, "{}", *ty));
                     }
-                    try!(f.write("&gt;".as_bytes()));
+                    try!(f.write_str("&gt;"));
                 }
             }
             clean::PathParameters::Parenthesized { ref inputs, ref output } => {
-                try!(f.write("(".as_bytes()));
+                try!(f.write_str("("));
                 let mut comma = false;
                 for ty in inputs.iter() {
                     if comma {
-                        try!(f.write(", ".as_bytes()));
+                        try!(f.write_str(", "));
                     }
                     comma = true;
                     try!(write!(f, "{}", *ty));
                 }
-                try!(f.write(")".as_bytes()));
+                try!(f.write_str(")"));
                 if let Some(ref ty) = *output {
-                    try!(f.write(" -&gt; ".as_bytes()));
+                    try!(f.write_str(" -&gt; "));
                     try!(write!(f, "{}", ty));
                 }
             }
@@ -238,7 +238,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl fmt::Show for clean::PathSegment {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        try!(f.write(self.name.as_bytes()));
+        try!(f.write_str(self.name.as_slice()));
         write!(f, "{}", self.params)
     }
 }
@@ -246,12 +246,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 impl fmt::Show for clean::Path {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         if self.global {
-            try!(f.write("::".as_bytes()))
+            try!(f.write_str("::"))
         }
 
         for (i, seg) in self.segments.iter().enumerate() {
             if i > 0 {
-                try!(f.write("::".as_bytes()))
+                try!(f.write_str("::"))
             }
             try!(write!(f, "{}", seg));
         }
@@ -433,10 +433,10 @@ impl fmt::Show for clean::Type {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             clean::TyParamBinder(id) => {
-                f.write(cache().typarams[ast_util::local_def(id)].as_bytes())
+                f.write_str(cache().typarams[ast_util::local_def(id)][])
             }
             clean::Generic(ref name) => {
-                f.write(name.as_bytes())
+                f.write_str(name.as_slice())
             }
             clean::ResolvedPath{ did, ref typarams, ref path } => {
                 try!(resolved_path(f, did, path, false));
@@ -522,7 +522,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                 primitive_link(f, clean::Slice,
                                format!("[{}, ..{}]", **t, *s).as_slice())
             }
-            clean::Bottom => f.write("!".as_bytes()),
+            clean::Bottom => f.write_str("!"),
             clean::RawPointer(m, ref t) => {
                 write!(f, "*{}{}", RawMutableSpace(m), **t)
             }
index 2c05524ea7f7b51b0133db598fc6bee72c75b8ce..fd7145552c427866ab494403cc951aa8c8acf461 100644 (file)
@@ -302,7 +302,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
 
         if ret.is_ok() {
             let buf = slice::from_raw_buf(&(*ob).data, (*ob).size as uint);
-            ret = w.write(buf);
+            ret = w.write_str(str::from_utf8(buf).unwrap());
         }
         hoedown_buffer_free(ob);
         ret
index f8a0b88b4088d99ac4ffcf7fbf56771f3d7d359a..c3cc61c79901fefecc2d05f92184c9e265a3acf9 100644 (file)
@@ -49,7 +49,6 @@
 use externalfiles::ExternalHtml;
 
 use serialize::json;
-use serialize::Encodable;
 use serialize::json::ToJson;
 use syntax::ast;
 use syntax::ast_util;
@@ -1095,7 +1094,7 @@ fn krate(mut self, mut krate: clean::Crate,
         try!(self.recurse(stability.name.clone(), |this| {
             let json_dst = &this.dst.join("stability.json");
             let mut json_out = BufferedWriter::new(try!(File::create(json_dst)));
-            try!(stability.encode(&mut json::Encoder::new(&mut json_out)));
+            try!(write!(&mut json_out, "{}", json::as_json(&stability)));
 
             let mut title = stability.name.clone();
             title.push_str(" - Stability dashboard");
@@ -1311,7 +1310,8 @@ fn href(&self, cx: &Context) -> Option<String> {
         // has anchors for the line numbers that we're linking to.
         if ast_util::is_local(self.item.def_id) {
             let mut path = Vec::new();
-            clean_srcpath(&cx.src_root, self.item.source.filename.as_bytes(), |component| {
+            clean_srcpath(&cx.src_root, self.item.source.filename.as_bytes(),
+                          |component| {
                 path.push(component.to_string());
             });
             let href = if self.item.source.loline == self.item.source.hiline {
@@ -1713,7 +1713,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
             try!(write!(w, ";\n"));
         }
         if types.len() > 0 && required.len() > 0 {
-            try!(w.write("\n".as_bytes()));
+            try!(w.write_str("\n"));
         }
         for m in required.iter() {
             try!(write!(w, "    "));
@@ -1721,7 +1721,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
             try!(write!(w, ";\n"));
         }
         if required.len() > 0 && provided.len() > 0 {
-            try!(w.write("\n".as_bytes()));
+            try!(w.write_str("\n"));
         }
         for m in provided.iter() {
             try!(write!(w, "    "));
@@ -2260,8 +2260,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 
 fn item_macro(w: &mut fmt::Formatter, it: &clean::Item,
               t: &clean::Macro) -> fmt::Result {
-    try!(w.write(highlight::highlight(t.source.as_slice(), Some("macro"),
-                                      None).as_bytes()));
+    try!(w.write_str(highlight::highlight(t.source.as_slice(),
+                                          Some("macro"),
+                                          None)[]));
     document(w, it)
 }
 
index ccdc816425503d95a0b6c4139f9a60e7f8ecf165..8eb4448c649b1555bc62281e44b3704fa323c68e 100644 (file)
@@ -41,7 +41,7 @@
 use std::io;
 use std::rc::Rc;
 use externalfiles::ExternalHtml;
-use serialize::{Decodable, Encodable};
+use serialize::Decodable;
 use serialize::json::{mod, Json};
 use rustc::session::search_paths::SearchPaths;
 
@@ -493,14 +493,7 @@ fn json_output(krate: clean::Crate, res: Vec<plugins::PluginJson> ,
 
     // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode
     // straight to the Rust JSON representation.
-    let crate_json_str = {
-        let mut w = Vec::new();
-        {
-            let mut encoder = json::Encoder::new(&mut w as &mut io::Writer);
-            krate.encode(&mut encoder).unwrap();
-        }
-        String::from_utf8(w).unwrap()
-    };
+    let crate_json_str = format!("{}", json::as_json(&krate));
     let crate_json = match json::from_str(crate_json_str.as_slice()) {
         Ok(j) => j,
         Err(e) => panic!("Rust generated JSON is invalid: {}", e)
@@ -510,5 +503,5 @@ fn json_output(krate: clean::Crate, res: Vec<plugins::PluginJson> ,
     json.insert("plugins".to_string(), Json::Object(plugins_json));
 
     let mut file = try!(File::create(&dst));
-    Json::Object(json).to_writer(&mut file)
+    write!(&mut file, "{}", Json::Object(json))
 }
index 8a9c2eebf3a5325db027fdad1c508e4dc58c09be..2c83807aa4f53ee9c18ee9cf34746d9877cddf28 100644 (file)
@@ -227,6 +227,11 @@ pub enum Json {
 pub type Array = Vec<Json>;
 pub type Object = BTreeMap<string::String, Json>;
 
+pub struct PrettyJson<'a> { inner: &'a Json }
+
+pub struct AsJson<'a, T: 'a> { inner: &'a T }
+pub struct AsPrettyJson<'a, T: 'a> { inner: &'a T, indent: Option<uint> }
+
 /// The errors that can arise while parsing a JSON stream.
 #[deriving(Clone, Copy, PartialEq)]
 pub enum ErrorCode {
@@ -303,9 +308,15 @@ pub fn decode<T: ::Decodable<Decoder, DecoderError>>(s: &str) -> DecodeResult<T>
 }
 
 /// Shortcut function to encode a `T` into a JSON `String`
-pub fn encode<'a, T: Encodable<Encoder<'a>, io::IoError>>(object: &T) -> string::String {
-    let buff = Encoder::buffer_encode(object);
-    string::String::from_utf8(buff).unwrap()
+pub fn encode<T>(object: &T) -> string::String
+                 where T: for<'a> Encodable<Encoder<'a>, fmt::Error>
+{
+    let mut s = String::new();
+    {
+        let mut encoder = Encoder::new(&mut s);
+        let _ = object.encode(&mut encoder);
+    }
+    s
 }
 
 impl fmt::Show for ErrorCode {
@@ -323,16 +334,16 @@ fn description(&self) -> &str { "decoder error" }
     fn detail(&self) -> Option<std::string::String> { Some(self.to_string()) }
 }
 
-pub type EncodeResult = io::IoResult<()>;
+pub type EncodeResult = fmt::Result;
 pub type DecodeResult<T> = Result<T, DecoderError>;
 
-pub fn escape_bytes(wr: &mut io::Writer, bytes: &[u8]) -> Result<(), io::IoError> {
+fn escape_str(wr: &mut fmt::Writer, v: &str) -> fmt::Result {
     try!(wr.write_str("\""));
 
     let mut start = 0;
 
-    for (i, byte) in bytes.iter().enumerate() {
-        let escaped = match *byte {
+    for (i, byte) in v.bytes().enumerate() {
+        let escaped = match byte {
             b'"' => "\\\"",
             b'\\' => "\\\\",
             b'\x00' => "\\u0000",
@@ -372,7 +383,7 @@ pub fn escape_bytes(wr: &mut io::Writer, bytes: &[u8]) -> Result<(), io::IoError
         };
 
         if start < i {
-            try!(wr.write(bytes[start..i]));
+            try!(wr.write_str(v[start..i]));
         }
 
         try!(wr.write_str(escaped));
@@ -380,34 +391,30 @@ pub fn escape_bytes(wr: &mut io::Writer, bytes: &[u8]) -> Result<(), io::IoError
         start = i + 1;
     }
 
-    if start != bytes.len() {
-        try!(wr.write(bytes[start..]));
+    if start != v.len() {
+        try!(wr.write_str(v[start..]));
     }
 
     wr.write_str("\"")
 }
 
-fn escape_str(writer: &mut io::Writer, v: &str) -> Result<(), io::IoError> {
-    escape_bytes(writer, v.as_bytes())
+fn escape_char(writer: &mut fmt::Writer, v: char) -> fmt::Result {
+    let mut buf = [0, .. 4];
+    let n = v.encode_utf8(&mut buf).unwrap();
+    let buf = unsafe { str::from_utf8_unchecked(buf[0..n]) };
+    escape_str(writer, buf)
 }
 
-fn escape_char(writer: &mut io::Writer, v: char) -> Result<(), io::IoError> {
-    let mut buf = [0; 4];
-    let len = v.encode_utf8(&mut buf).unwrap();
-    escape_bytes(writer, buf[mut ..len])
-}
-
-fn spaces(wr: &mut io::Writer, mut n: uint) -> Result<(), io::IoError> {
-    const LEN: uint = 16;
-    static BUF: [u8; LEN] = [b' '; LEN];
+fn spaces(wr: &mut fmt::Writer, mut n: uint) -> fmt::Result {
+    const BUF: &'static str = "                ";
 
-    while n >= LEN {
-        try!(wr.write(&BUF));
-        n -= LEN;
+    while n >= BUF.len() {
+        try!(wr.write_str(BUF));
+        n -= BUF.len();
     }
 
     if n > 0 {
-        wr.write(BUF[..n])
+        wr.write_str(BUF[..n])
     } else {
         Ok(())
     }
@@ -423,31 +430,18 @@ fn fmt_number_or_null(v: f64) -> string::String {
 
 /// A structure for implementing serialization to JSON.
 pub struct Encoder<'a> {
-    writer: &'a mut (io::Writer+'a),
+    writer: &'a mut (fmt::Writer+'a),
 }
 
 impl<'a> Encoder<'a> {
     /// Creates a new JSON encoder whose output will be written to the writer
     /// specified.
-    pub fn new(writer: &'a mut io::Writer) -> Encoder<'a> {
+    pub fn new(writer: &'a mut fmt::Writer) -> Encoder<'a> {
         Encoder { writer: writer }
     }
-
-    /// Encode the specified struct into a json [u8]
-    pub fn buffer_encode<T: Encodable<Encoder<'a>, io::IoError>>(object: &T) -> Vec<u8>  {
-        //Serialize the object in a string using a writer
-        let mut m = Vec::new();
-        // FIXME(14302) remove the transmute and unsafe block.
-        unsafe {
-            let mut encoder = Encoder::new(&mut m as &mut io::Writer);
-            // Vec<u8> never Errs
-            let _ = object.encode(transmute(&mut encoder));
-        }
-        m
-    }
 }
 
-impl<'a> ::Encoder<io::IoError> for Encoder<'a> {
+impl<'a> ::Encoder<fmt::Error> for Encoder<'a> {
     fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") }
 
     fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) }
@@ -646,14 +640,14 @@ fn emit_map_elt_val<F>(&mut self, _idx: uint, f: F) -> EncodeResult where
 /// Another encoder for JSON, but prints out human-readable JSON instead of
 /// compact data
 pub struct PrettyEncoder<'a> {
-    writer: &'a mut (io::Writer+'a),
+    writer: &'a mut (fmt::Writer+'a),
     curr_indent: uint,
     indent: uint,
 }
 
 impl<'a> PrettyEncoder<'a> {
     /// Creates a new encoder whose output will be written to the specified writer
-    pub fn new(writer: &'a mut io::Writer) -> PrettyEncoder<'a> {
+    pub fn new(writer: &'a mut fmt::Writer) -> PrettyEncoder<'a> {
         PrettyEncoder { writer: writer, curr_indent: 0, indent: 2, }
     }
 
@@ -667,7 +661,7 @@ pub fn set_indent(&mut self, indent: uint) {
     }
 }
 
-impl<'a> ::Encoder<io::IoError> for PrettyEncoder<'a> {
+impl<'a> ::Encoder<fmt::Error> for PrettyEncoder<'a> {
     fn emit_nil(&mut self) -> EncodeResult { write!(self.writer, "null") }
 
     fn emit_uint(&mut self, v: uint) -> EncodeResult { write!(self.writer, "{}", v) }
@@ -927,25 +921,23 @@ fn encode(&self, e: &mut E) -> Result<(), S> {
     }
 }
 
-impl Json {
-    /// Encodes a json value into an io::writer. Uses a single line.
-    pub fn to_writer(&self, writer: &mut io::Writer) -> EncodeResult {
-        let mut encoder = Encoder::new(writer);
-        self.encode(&mut encoder)
-    }
+/// Create an `AsJson` wrapper which can be used to print a value as JSON
+/// on-the-fly via `write!`
+pub fn as_json<T>(t: &T) -> AsJson<T> {
+    AsJson { inner: t }
+}
 
-    /// Encodes a json value into an io::writer.
-    /// Pretty-prints in a more readable format.
-    pub fn to_pretty_writer(&self, writer: &mut io::Writer) -> EncodeResult {
-        let mut encoder = PrettyEncoder::new(writer);
-        self.encode(&mut encoder)
-    }
+/// Create an `AsPrettyJson` wrapper which can be used to print a value as JSON
+/// on-the-fly via `write!`
+pub fn as_pretty_json<T>(t: &T) -> AsPrettyJson<T> {
+    AsPrettyJson { inner: t, indent: None }
+}
 
-    /// Encodes a json value into a string
-    pub fn to_pretty_str(&self) -> string::String {
-        let mut s = Vec::new();
-        self.to_pretty_writer(&mut s as &mut io::Writer).unwrap();
-        string::String::from_utf8(s).unwrap()
+impl Json {
+    /// Borrow this json object as a pretty object to generate a pretty
+    /// representation for it via `Show`.
+    pub fn pretty(&self) -> PrettyJson {
+        PrettyJson { inner: self }
     }
 
      /// If the Json value is an Object, returns the value associated with the provided key.
@@ -2424,10 +2416,65 @@ fn to_json(&self) -> Json {
     }
 }
 
+struct FormatShim<'a, 'b: 'a> {
+    inner: &'a mut fmt::Formatter<'b>,
+}
+
+impl<'a, 'b> fmt::Writer for FormatShim<'a, 'b> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.inner.write_str(s)
+    }
+}
+
 impl fmt::Show for Json {
     /// Encodes a json value into a string
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.to_writer(f).map_err(|_| fmt::Error)
+        let mut shim = FormatShim { inner: f };
+        let mut encoder = Encoder::new(&mut shim);
+        self.encode(&mut encoder)
+    }
+}
+
+impl<'a> fmt::Show for PrettyJson<'a> {
+    /// Encodes a json value into a string
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let mut shim = FormatShim { inner: f };
+        let mut encoder = PrettyEncoder::new(&mut shim);
+        self.inner.encode(&mut encoder)
+    }
+}
+
+impl<'a, T> fmt::Show for AsJson<'a, T>
+    where T: for<'b> Encodable<Encoder<'b>, fmt::Error>
+{
+    /// Encodes a json value into a string
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let mut shim = FormatShim { inner: f };
+        let mut encoder = Encoder::new(&mut shim);
+        self.inner.encode(&mut encoder)
+    }
+}
+
+impl<'a, T> AsPrettyJson<'a, T> {
+    /// Set the indentation level for the emitted JSON
+    pub fn indent(mut self, indent: uint) -> AsPrettyJson<'a, T> {
+        self.indent = Some(indent);
+        self
+    }
+}
+
+impl<'a, T> fmt::Show for AsPrettyJson<'a, T>
+    where T: for<'b> Encodable<PrettyEncoder<'b>, fmt::Error>
+{
+    /// Encodes a json value into a string
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let mut shim = FormatShim { inner: f };
+        let mut encoder = PrettyEncoder::new(&mut shim);
+        match self.indent {
+            Some(n) => encoder.set_indent(n),
+            None => {}
+        }
+        self.inner.encode(&mut encoder)
     }
 }
 
@@ -2450,9 +2497,9 @@ mod tests {
     use super::DecoderError::*;
     use super::JsonEvent::*;
     use super::StackElement::*;
-    use super::{PrettyEncoder, Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser,
-                StackElement, Stack, Encoder, Decoder};
-    use std::{i64, u64, f32, f64, io};
+    use super::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser,
+                StackElement, Stack, Decoder};
+    use std::{i64, u64, f32, f64};
     use std::collections::BTreeMap;
     use std::num::Float;
     use std::string;
@@ -2523,74 +2570,74 @@ fn test_from_str_trait() {
     #[test]
     fn test_write_null() {
         assert_eq!(Null.to_string(), "null");
-        assert_eq!(Null.to_pretty_str(), "null");
+        assert_eq!(Null.pretty().to_string(), "null");
     }
 
     #[test]
     fn test_write_i64() {
         assert_eq!(U64(0).to_string(), "0");
-        assert_eq!(U64(0).to_pretty_str(), "0");
+        assert_eq!(U64(0).pretty().to_string(), "0");
 
         assert_eq!(U64(1234).to_string(), "1234");
-        assert_eq!(U64(1234).to_pretty_str(), "1234");
+        assert_eq!(U64(1234).pretty().to_string(), "1234");
 
         assert_eq!(I64(-5678).to_string(), "-5678");
-        assert_eq!(I64(-5678).to_pretty_str(), "-5678");
+        assert_eq!(I64(-5678).pretty().to_string(), "-5678");
 
         assert_eq!(U64(7650007200025252000).to_string(), "7650007200025252000");
-        assert_eq!(U64(7650007200025252000).to_pretty_str(), "7650007200025252000");
+        assert_eq!(U64(7650007200025252000).pretty().to_string(), "7650007200025252000");
     }
 
     #[test]
     fn test_write_f64() {
         assert_eq!(F64(3.0).to_string(), "3.0");
-        assert_eq!(F64(3.0).to_pretty_str(), "3.0");
+        assert_eq!(F64(3.0).pretty().to_string(), "3.0");
 
         assert_eq!(F64(3.1).to_string(), "3.1");
-        assert_eq!(F64(3.1).to_pretty_str(), "3.1");
+        assert_eq!(F64(3.1).pretty().to_string(), "3.1");
 
         assert_eq!(F64(-1.5).to_string(), "-1.5");
-        assert_eq!(F64(-1.5).to_pretty_str(), "-1.5");
+        assert_eq!(F64(-1.5).pretty().to_string(), "-1.5");
 
         assert_eq!(F64(0.5).to_string(), "0.5");
-        assert_eq!(F64(0.5).to_pretty_str(), "0.5");
+        assert_eq!(F64(0.5).pretty().to_string(), "0.5");
 
         assert_eq!(F64(f64::NAN).to_string(), "null");
-        assert_eq!(F64(f64::NAN).to_pretty_str(), "null");
+        assert_eq!(F64(f64::NAN).pretty().to_string(), "null");
 
         assert_eq!(F64(f64::INFINITY).to_string(), "null");
-        assert_eq!(F64(f64::INFINITY).to_pretty_str(), "null");
+        assert_eq!(F64(f64::INFINITY).pretty().to_string(), "null");
 
         assert_eq!(F64(f64::NEG_INFINITY).to_string(), "null");
-        assert_eq!(F64(f64::NEG_INFINITY).to_pretty_str(), "null");
+        assert_eq!(F64(f64::NEG_INFINITY).pretty().to_string(), "null");
     }
 
     #[test]
     fn test_write_str() {
         assert_eq!(String("".to_string()).to_string(), "\"\"");
-        assert_eq!(String("".to_string()).to_pretty_str(), "\"\"");
+        assert_eq!(String("".to_string()).pretty().to_string(), "\"\"");
 
         assert_eq!(String("homura".to_string()).to_string(), "\"homura\"");
-        assert_eq!(String("madoka".to_string()).to_pretty_str(), "\"madoka\"");
+        assert_eq!(String("madoka".to_string()).pretty().to_string(), "\"madoka\"");
     }
 
     #[test]
     fn test_write_bool() {
         assert_eq!(Boolean(true).to_string(), "true");
-        assert_eq!(Boolean(true).to_pretty_str(), "true");
+        assert_eq!(Boolean(true).pretty().to_string(), "true");
 
         assert_eq!(Boolean(false).to_string(), "false");
-        assert_eq!(Boolean(false).to_pretty_str(), "false");
+        assert_eq!(Boolean(false).pretty().to_string(), "false");
     }
 
     #[test]
     fn test_write_array() {
         assert_eq!(Array(vec![]).to_string(), "[]");
-        assert_eq!(Array(vec![]).to_pretty_str(), "[]");
+        assert_eq!(Array(vec![]).pretty().to_string(), "[]");
 
         assert_eq!(Array(vec![Boolean(true)]).to_string(), "[true]");
         assert_eq!(
-            Array(vec![Boolean(true)]).to_pretty_str(),
+            Array(vec![Boolean(true)]).pretty().to_string(),
             "\
             [\n  \
                 true\n\
@@ -2605,7 +2652,7 @@ fn test_write_array() {
         assert_eq!(long_test_array.to_string(),
             "[false,null,[\"foo\\nbar\",3.5]]");
         assert_eq!(
-            long_test_array.to_pretty_str(),
+            long_test_array.pretty().to_string(),
             "\
             [\n  \
                 false,\n  \
@@ -2621,7 +2668,7 @@ fn test_write_array() {
     #[test]
     fn test_write_object() {
         assert_eq!(mk_object(&[]).to_string(), "{}");
-        assert_eq!(mk_object(&[]).to_pretty_str(), "{}");
+        assert_eq!(mk_object(&[]).pretty().to_string(), "{}");
 
         assert_eq!(
             mk_object(&[
@@ -2630,7 +2677,7 @@ fn test_write_object() {
             "{\"a\":true}"
         );
         assert_eq!(
-            mk_object(&[("a".to_string(), Boolean(true))]).to_pretty_str(),
+            mk_object(&[("a".to_string(), Boolean(true))]).pretty().to_string(),
             "\
             {\n  \
                 \"a\": true\n\
@@ -2654,7 +2701,7 @@ fn test_write_object() {
             }"
         );
         assert_eq!(
-            complex_obj.to_pretty_str(),
+            complex_obj.pretty().to_string(),
             "\
             {\n  \
                 \"b\": [\n    \
@@ -2678,48 +2725,29 @@ fn test_write_object() {
 
         // We can't compare the strings directly because the object fields be
         // printed in a different order.
-        assert_eq!(a.clone(), from_str(a.to_string().as_slice()).unwrap());
-        assert_eq!(a.clone(),
-                   from_str(a.to_pretty_str().as_slice()).unwrap());
-    }
-
-    fn with_str_writer<F>(f: F) -> string::String where F: FnOnce(&mut io::Writer){
-        let mut m = Vec::new();
-        f(&mut m as &mut io::Writer);
-        string::String::from_utf8(m).unwrap()
+        assert_eq!(a.clone(), a.to_string().parse().unwrap());
+        assert_eq!(a.clone(), a.pretty().to_string().parse().unwrap());
     }
 
     #[test]
     fn test_write_enum() {
         let animal = Dog;
         assert_eq!(
-            with_str_writer(|writer| {
-                let mut encoder = Encoder::new(writer);
-                animal.encode(&mut encoder).unwrap();
-            }),
+            format!("{}", super::as_json(&animal)),
             "\"Dog\""
         );
         assert_eq!(
-            with_str_writer(|writer| {
-                let mut encoder = PrettyEncoder::new(writer);
-                animal.encode(&mut encoder).unwrap();
-            }),
+            format!("{}", super::as_pretty_json(&animal)),
             "\"Dog\""
         );
 
         let animal = Frog("Henry".to_string(), 349);
         assert_eq!(
-            with_str_writer(|writer| {
-                let mut encoder = Encoder::new(writer);
-                animal.encode(&mut encoder).unwrap();
-            }),
+            format!("{}", super::as_json(&animal)),
             "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}"
         );
         assert_eq!(
-            with_str_writer(|writer| {
-                let mut encoder = PrettyEncoder::new(writer);
-                animal.encode(&mut encoder).unwrap();
-            }),
+            format!("{}", super::as_pretty_json(&animal)),
             "{\n  \
                \"variant\": \"Frog\",\n  \
                \"fields\": [\n    \
@@ -2732,16 +2760,10 @@ fn test_write_enum() {
 
     macro_rules! check_encoder_for_simple {
         ($value:expr, $expected:expr) => ({
-            let s = with_str_writer(|writer| {
-                let mut encoder = Encoder::new(writer);
-                $value.encode(&mut encoder).unwrap();
-            });
+            let s = format!("{}", super::as_json(&$value));
             assert_eq!(s, $expected);
 
-            let s = with_str_writer(|writer| {
-                let mut encoder = PrettyEncoder::new(writer);
-                $value.encode(&mut encoder).unwrap();
-            });
+            let s = format!("{}", super::as_pretty_json(&$value));
             assert_eq!(s, $expected);
         })
     }
@@ -3320,10 +3342,7 @@ fn test_encode_hashmap_with_numeric_key() {
         let mut hm: HashMap<uint, bool> = HashMap::new();
         hm.insert(1, true);
         let mut mem_buf = Vec::new();
-        {
-            let mut encoder = Encoder::new(&mut mem_buf as &mut io::Writer);
-            hm.encode(&mut encoder).unwrap();
-        }
+        write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap();
         let json_str = from_utf8(mem_buf[]).unwrap();
         match from_str(json_str) {
             Err(_) => panic!("Unable to parse json_str: {}", json_str),
@@ -3339,10 +3358,7 @@ fn test_prettyencode_hashmap_with_numeric_key() {
         let mut hm: HashMap<uint, bool> = HashMap::new();
         hm.insert(1, true);
         let mut mem_buf = Vec::new();
-        {
-            let mut encoder = PrettyEncoder::new(&mut mem_buf as &mut io::Writer);
-            hm.encode(&mut encoder).unwrap()
-        }
+        write!(&mut mem_buf, "{}", super::as_pretty_json(&hm)).unwrap();
         let json_str = from_utf8(mem_buf[]).unwrap();
         match from_str(json_str) {
             Err(_) => panic!("Unable to parse json_str: {}", json_str),
@@ -3373,18 +3389,15 @@ fn test_prettyencoder_indent_level_param() {
 
         // Helper function for counting indents
         fn indents(source: &str) -> uint {
-            let trimmed = source.trim_left_chars(' ');
+            let trimmed = source.trim_left_matches(' ');
             source.len() - trimmed.len()
         }
 
         // Test up to 4 spaces of indents (more?)
         for i in range(0, 4u) {
             let mut writer = Vec::new();
-            {
-                let ref mut encoder = PrettyEncoder::new(&mut writer);
-                encoder.set_indent(i);
-                json.encode(encoder).unwrap();
-            }
+            write!(&mut writer, "{}",
+                   super::as_pretty_json(&json).indent(i)).unwrap();
 
             let printed = from_utf8(writer[]).unwrap();
 
index 7010eae6dba0dba03e285e707d6232fc07451661..30dc48f6fcc7325d64e0a3decd3ede0c68c44943 100644 (file)
@@ -14,7 +14,6 @@
 
 use any::{Any, AnyRefExt};
 use cell::RefCell;
-use fmt;
 use io::IoResult;
 use rt::{backtrace, unwind};
 use rt::util::{Stderr, Stdio};
 
 impl Writer for Stdio {
     fn write(&mut self, bytes: &[u8]) -> IoResult<()> {
-        fn fmt_write<F: fmt::FormatWriter>(f: &mut F, bytes: &[u8]) {
-            let _ = f.write(bytes);
-        }
-        fmt_write(self, bytes);
+        let _ = self.write_bytes(bytes);
         Ok(())
     }
 }
index 957dd54a037cf86376dd462d6996434e33c77791..32f5f2d45363fdee716e3350d2780c41fb9a7c21 100644 (file)
 //!         // for details, and the function `pad` can be used to pad strings.
 //!         let decimals = f.precision().unwrap_or(3);
 //!         let string = f64::to_str_exact(magnitude, decimals);
-//!         f.pad_integral(true, "", string.as_bytes())
+//!         f.pad_integral(true, "", string.as_slice())
 //!     }
 //! }
 //!
 
 #![experimental]
 
-use io::Writer;
-use io;
-use result::Result::{Ok, Err};
 use string;
-use vec::Vec;
 
-pub use core::fmt::{Formatter, Result, FormatWriter, rt};
+pub use core::fmt::{Formatter, Result, Writer, rt};
 pub use core::fmt::{Show, Octal, Binary};
 pub use core::fmt::{LowerHex, UpperHex, Pointer};
 pub use core::fmt::{LowerExp, UpperExp};
 #[experimental = "this is an implementation detail of format! and should not \
                   be called directly"]
 pub fn format(args: Arguments) -> string::String {
-    let mut output = Vec::new();
-    let _ = write!(&mut output as &mut Writer, "{}", args);
-    string::String::from_utf8(output).unwrap()
-}
-
-impl<'a> Writer for Formatter<'a> {
-    fn write(&mut self, b: &[u8]) -> io::IoResult<()> {
-        match (*self).write(b) {
-            Ok(()) => Ok(()),
-            Err(Error) => Err(io::standard_error(io::OtherIoError))
-        }
-    }
+    let mut output = string::String::new();
+    let _ = write!(&mut output, "{}", args);
+    output
 }
index e8b852ee492b95c02e42ae4bc47daf4bf7d19449..3f6eb21724550edb0ddd23ef1d0c734b736bb824 100644 (file)
@@ -1028,16 +1028,16 @@ fn flush(&mut self) -> IoResult<()> { Ok(()) }
     ///
     /// This function will return any I/O error reported while formatting.
     fn write_fmt(&mut self, fmt: fmt::Arguments) -> IoResult<()> {
-        // Create a shim which translates a Writer to a FormatWriter and saves
+        // Create a shim which translates a Writer to a fmt::Writer and saves
         // off I/O errors. instead of discarding them
         struct Adaptor<'a, T:'a> {
             inner: &'a mut T,
             error: IoResult<()>,
         }
 
-        impl<'a, T: Writer> fmt::FormatWriter for Adaptor<'a, T> {
-            fn write(&mut self, bytes: &[u8]) -> fmt::Result {
-                match self.inner.write(bytes) {
+        impl<'a, T: Writer> fmt::Writer for Adaptor<'a, T> {
+            fn write_str(&mut self, s: &str) -> fmt::Result {
+                match self.inner.write(s.as_bytes()) {
                     Ok(()) => Ok(()),
                     Err(e) => {
                         self.error = Err(e);
index e0c512706e6a96b5fcdd5260748606cabd7ccecc..8d7713d05584042265168ae2fcf952f3a7f43f72 100644 (file)
@@ -493,27 +493,16 @@ extern "C" fn inner(
 /// the actual formatting into this shared place.
 #[inline(never)] #[cold]
 pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, uint)) -> ! {
-    use fmt::FormatWriter;
+    use fmt::Writer;
 
     // We do two allocations here, unfortunately. But (a) they're
     // required with the current scheme, and (b) we don't handle
     // panic + OOM properly anyway (see comment in begin_unwind
     // below).
 
-    struct VecWriter<'a> { v: &'a mut Vec<u8> }
-
-    impl<'a> fmt::FormatWriter for VecWriter<'a> {
-        fn write(&mut self, buf: &[u8]) -> fmt::Result {
-            self.v.push_all(buf);
-            Ok(())
-        }
-    }
-
-    let mut v = Vec::new();
-    let _ = write!(&mut VecWriter { v: &mut v }, "{}", msg);
-
-    let msg = box String::from_utf8_lossy(v.as_slice()).into_owned();
-    begin_unwind_inner(msg, file_line)
+    let mut s = String::new();
+    let _ = write!(&mut s, "{}", msg);
+    begin_unwind_inner(box s, file_line)
 }
 
 /// This is the entry point of unwinding for panic!() and assert!().
index fee86e33455d40c086e96c835bc0c675eca5537f..fa7c305d69eae4be6559072e5c218c84a829289b 100644 (file)
@@ -96,8 +96,8 @@ pub fn default_sched_threads() -> uint {
 #[allow(non_upper_case_globals)]
 pub const Stderr: Stdio = Stdio(libc::STDERR_FILENO);
 
-impl fmt::FormatWriter for Stdio {
-    fn write(&mut self, data: &[u8]) -> fmt::Result {
+impl Stdio {
+    pub fn write_bytes(&mut self, data: &[u8]) {
         #[cfg(unix)]
         type WriteLen = libc::size_t;
         #[cfg(windows)]
@@ -108,6 +108,12 @@ fn write(&mut self, data: &[u8]) -> fmt::Result {
                         data.as_ptr() as *const libc::c_void,
                         data.len() as WriteLen);
         }
+    }
+}
+
+impl fmt::Writer for Stdio {
+    fn write_str(&mut self, data: &str) -> fmt::Result {
+        self.write_bytes(data.as_bytes());
         Ok(()) // yes, we're lying
     }
 }
@@ -117,16 +123,16 @@ pub fn dumb_print(args: fmt::Arguments) {
 }
 
 pub fn abort(args: fmt::Arguments) -> ! {
-    use fmt::FormatWriter;
+    use fmt::Writer;
 
     struct BufWriter<'a> {
         buf: &'a mut [u8],
         pos: uint,
     }
-    impl<'a> FormatWriter for BufWriter<'a> {
-        fn write(&mut self, bytes: &[u8]) -> fmt::Result {
+    impl<'a> fmt::Writer for BufWriter<'a> {
+        fn write_str(&mut self, bytes: &str) -> fmt::Result {
             let left = self.buf.slice_from_mut(self.pos);
-            let to_write = bytes[..cmp::min(bytes.len(), left.len())];
+            let to_write = bytes.as_bytes()[..cmp::min(bytes.len(), left.len())];
             slice::bytes::copy_memory(left, to_write);
             self.pos += to_write.len();
             Ok(())
index 12432c8c78f2c109822ca57c41a1398cdf5904ba..4606e70d83bb54b8bc5ec1e7fe0d0ca89b0fde2c 100644 (file)
@@ -1662,6 +1662,7 @@ mod test {
     use serialize;
     use codemap::*;
     use super::*;
+    use std::fmt;
 
     // are ASTs encodable?
     #[test]
@@ -1687,6 +1688,6 @@ fn check_asts_encodable() {
             exported_macros: Vec::new(),
         };
         // doesn't matter which encoder we use....
-        let _f = &e as &serialize::Encodable<json::Encoder, io::IoError>;
+        let _f = &e as &serialize::Encodable<json::Encoder, fmt::Error>;
     }
 }
index 19821ecb7ca7a03b75effb31f911d7ed7b699eb3..565c98797b8c1e7072fb8f5c429922331f9d179a 100644 (file)
@@ -171,14 +171,14 @@ fn padding(&self) -> NamePadding {
 
 impl fmt::Show for TestFn {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write(match *self {
+        f.write_str(match *self {
             StaticTestFn(..) => "StaticTestFn(..)",
             StaticBenchFn(..) => "StaticBenchFn(..)",
             StaticMetricFn(..) => "StaticMetricFn(..)",
             DynTestFn(..) => "DynTestFn(..)",
             DynMetricFn(..) => "DynMetricFn(..)",
             DynBenchFn(..) => "DynBenchFn(..)"
-        }.as_bytes())
+        })
     }
 }
 
@@ -1212,8 +1212,7 @@ pub fn load(p: &Path) -> MetricMap {
     pub fn save(&self, p: &Path) -> io::IoResult<()> {
         let mut file = try!(File::create(p));
         let MetricMap(ref map) = *self;
-        let mut enc = json::PrettyEncoder::new(&mut file);
-        map.encode(&mut enc)
+        write!(&mut file, "{}", json::as_json(map))
     }
 
     /// Compare against another MetricMap. Optionally compare all
index ed4fdc525729e820c3b7443f8ce675469646dcea..cae7a4cefadb0c5635cc73a97bfa0ee9da3f1a30 100644 (file)
 
 extern crate serialize;
 
-use std::io;
+use std::fmt;
 use serialize::{Encodable, Encoder};
 
 pub fn buffer_encode<'a,
-                     T:Encodable<serialize::json::Encoder<'a>,io::IoError>>(
+                     T:Encodable<serialize::json::Encoder<'a>,fmt::Error>>(
                      to_encode_object: &T)
-                     -> Vec<u8> {
-    let mut m = Vec::new();
+                     -> String {
+    let mut m = String::new();
     {
         let mut encoder =
-            serialize::json::Encoder::new(&mut m as &mut io::Writer);
+            serialize::json::Encoder::new(&mut m);
         //~^ ERROR `m` does not live long enough
         to_encode_object.encode(&mut encoder);
     }
diff --git a/src/test/run-fail/panic-non-utf8.rs b/src/test/run-fail/panic-non-utf8.rs
deleted file mode 100644 (file)
index 8b01319..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-
-// 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.
-
-// Previously failed formating invalid utf8.
-// cc #16877
-
-// error-pattern:panicked at 'hello�'
-
-struct Foo;
-impl std::fmt::Show for Foo {
-    fn fmt(&self, fmtr:&mut std::fmt::Formatter) -> std::fmt::Result {
-        // Purge invalid utf8: 0xff
-        fmtr.write(&[104, 101, 108, 108, 111, 0xff])
-    }
-}
-fn main() {
-    panic!("{}", Foo)
-}
index bbb049eb9603315577e73789545a5954b7bb17da..d2caecdf05be2a31a8d81282b88c02182bc737c7 100644 (file)
@@ -15,7 +15,6 @@
 
 use std::io::MemWriter;
 use std::fmt;
-use std::fmt::FormatWriter;
 
 struct Foo<'a> {
     writer: &'a mut (Writer+'a),
@@ -24,8 +23,8 @@ struct Foo<'a> {
 
 struct Bar;
 
-impl fmt::FormatWriter for Bar {
-    fn write(&mut self, _: &[u8]) -> fmt::Result {
+impl fmt::Writer for Bar {
+    fn write_str(&mut self, _: &str) -> fmt::Result {
         Ok(())
     }
 }
@@ -41,5 +40,8 @@ fn main() {
     println!("ok");
 
     let mut s = Bar;
-    write!(&mut s, "test");
+    {
+        use std::fmt::Writer;
+        write!(&mut s, "test");
+    }
 }
index fa62699a303783b4e0538c174f90c214894aa96a..1efae89f665631ad0f0ac47a6b5422e69beb5573 100644 (file)
@@ -16,7 +16,6 @@
 #![allow(unused_must_use)]
 
 use std::fmt;
-use std::io;
 
 struct A;
 struct B;
 
 impl fmt::LowerHex for A {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write("aloha".as_bytes())
+        f.write_str("aloha")
     }
 }
 impl fmt::UpperHex for B {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.write("adios".as_bytes())
+        f.write_str("adios")
     }
 }
 impl fmt::Show for C {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.pad_integral(true, "☃", "123".as_bytes())
+        f.pad_integral(true, "☃", "123")
     }
 }
 
@@ -160,18 +159,18 @@ pub fn main() {
 // Basic test to make sure that we can invoke the `write!` macro with an
 // io::Writer instance.
 fn test_write() {
-    let mut buf = Vec::new();
-    write!(&mut buf as &mut io::Writer, "{}", 3i);
+    use std::fmt::Writer;
+    let mut buf = String::new();
+    write!(&mut buf, "{}", 3i);
     {
-        let w = &mut buf as &mut io::Writer;
+        let w = &mut buf;
         write!(w, "{foo}", foo=4i);
         write!(w, "{}", "hello");
         writeln!(w, "{}", "line");
         writeln!(w, "{foo}", foo="bar");
     }
 
-    let s = String::from_utf8(buf).unwrap();
-    t!(s, "34helloline\nbar\n");
+    t!(buf, "34helloline\nbar\n");
 }
 
 // Just make sure that the macros are defined, there's not really a lot that we
@@ -187,14 +186,15 @@ fn test_print() {
 // Just make sure that the macros are defined, there's not really a lot that we
 // can do with them just yet (to test the output)
 fn test_format_args() {
-    let mut buf = Vec::new();
+    use std::fmt::Writer;
+    let mut buf = String::new();
     {
-        let w = &mut buf as &mut io::Writer;
+        let w = &mut buf;
         write!(w, "{}", format_args!("{}", 1i));
         write!(w, "{}", format_args!("test"));
         write!(w, "{}", format_args!("{test}", test=3i));
     }
-    let s = String::from_utf8(buf).unwrap();
+    let s = buf;
     t!(s, "1test3");
 
     let s = fmt::format(format_args!("hello {}", "world"));
index 8de847bfa3314ed3518a2a515a02ec7d48ae866b..0e0aea081f634eb8ed08a66008d5a97109432959 100644 (file)
@@ -12,7 +12,8 @@
 extern crate serialize;
 
 use std::io;
-use std::io::{IoError, IoResult, SeekStyle};
+use std::fmt;
+use std::io::{IoResult, SeekStyle};
 use std::slice;
 
 use serialize::{Encodable, Encoder};
@@ -37,16 +38,15 @@ enum WireProtocol {
     // ...
 }
 
-fn encode_json<'a,
-               T: Encodable<json::Encoder<'a>,
-                            std::io::IoError>>(val: &T,
-                                               wr: &'a mut SeekableMemWriter) {
-    let mut encoder = json::Encoder::new(wr);
-    val.encode(&mut encoder);
+fn encode_json<
+               T: for<'a> Encodable<json::Encoder<'a>,
+                            fmt::Error>>(val: &T,
+                                               wr: &mut SeekableMemWriter) {
+    write!(wr, "{}", json::as_json(val));
 }
 fn encode_rbml<'a,
                T: Encodable<writer::Encoder<'a, SeekableMemWriter>,
-                            std::io::IoError>>(val: &T,
+                            io::IoError>>(val: &T,
                                                wr: &'a mut SeekableMemWriter) {
     let mut encoder = writer::Encoder::new(wr);
     val.encode(&mut encoder);
index 8d5b928964dae8e936023be8aa13f56a2e06e115..1ab8deda3830e035c91436617afe1d55d30bd1f0 100644 (file)
@@ -12,7 +12,7 @@
 
 extern crate serialize;
 
-use std::io::IoError;
+use std::fmt;
 use serialize::{Encoder, Encodable};
 use serialize::json;
 
@@ -21,7 +21,7 @@ struct Foo<T> {
 }
 
 #[unsafe_destructor]
-impl<'a, T: Encodable<json::Encoder<'a>, IoError>> Drop for Foo<T> {
+impl<T: for<'a> Encodable<json::Encoder<'a>, fmt::Error>> Drop for Foo<T> {
     fn drop(&mut self) {
         json::encode(&self.v);
     }