Skip to content

std: Enforce Unicode in fmt::Writer #20377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/libcollections/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand Down Expand Up @@ -1073,6 +1075,13 @@ impl<'a> Str for CowString<'a> {
}
}

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::*;
Expand Down
6 changes: 3 additions & 3 deletions src/libcollections/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1488,9 +1488,9 @@ impl<T:fmt::Show> fmt::Show for Vec<T> {
}
}

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(())
}
}
Expand Down
20 changes: 10 additions & 10 deletions src/libcore/fmt/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use num::FpCategory as Fp;
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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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");
}
_ => {}
}
Expand Down Expand Up @@ -314,11 +314,11 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
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(())
}
}
Expand All @@ -332,5 +332,5 @@ pub fn float_to_str_bytes_common<T: Float, U, F>(
}
}

f(buf[..end])
f(unsafe { str::from_utf8_unchecked(buf[..end]) })
}
71 changes: 33 additions & 38 deletions src/libcore/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use result::Result::{Ok, Err};
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;
Expand Down Expand Up @@ -57,7 +57,7 @@ pub struct Error;
/// 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.
///
Expand All @@ -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.
///
Expand All @@ -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>],
}
Expand Down Expand Up @@ -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.
Expand All @@ -279,7 +268,7 @@ static DEFAULT_ARGUMENT: rt::Argument<'static> = rt::Argument {
/// * 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,
Expand All @@ -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));
}
}
Expand All @@ -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 => {}
}
Expand Down Expand Up @@ -378,7 +367,7 @@ impl<'a> Formatter<'a> {
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};
Expand All @@ -402,9 +391,10 @@ impl<'a> Formatter<'a> {
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(()) }
};

Expand All @@ -413,24 +403,26 @@ impl<'a> Formatter<'a> {
// 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)
})
}
}
Expand All @@ -451,7 +443,7 @@ impl<'a> Formatter<'a> {
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
Expand All @@ -463,7 +455,7 @@ impl<'a> Formatter<'a> {
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 => {}
Expand All @@ -472,17 +464,17 @@ impl<'a> Formatter<'a> {
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)
})
}
}
Expand All @@ -507,15 +499,16 @@ impl<'a> Formatter<'a> {

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(())
Expand All @@ -524,8 +517,8 @@ impl<'a> Formatter<'a> {
/// 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
Expand Down Expand Up @@ -616,7 +609,9 @@ impl Show for char {
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
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/libcore/fmt/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use fmt;
use iter::DoubleEndedIteratorExt;
use num::{Int, cast};
use slice::SliceExt;
use str;

/// A type that represents a specific radix
#[doc(hidden)]
Expand Down Expand Up @@ -60,7 +61,8 @@ trait GenericRadix {
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)
}
}

Expand Down
12 changes: 3 additions & 9 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use rustc_trans::save;
use rustc_trans::trans;
use rustc_typeck as typeck;

use serialize::{json, Encodable};
use serialize::json;

use std::io;
use std::io::fs;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -338,10 +335,7 @@ pub fn assign_node_ids_and_map<'ast>(sess: &Session,
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
Expand Down
Loading