std: Enforce Unicode in fmt::Writer
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
This commit is contained in:
parent
cd614164e6
commit
e423fcf0e0
25 changed files with 320 additions and 359 deletions
|
|
@ -10,17 +10,17 @@
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<6C>'
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
#![allow(unused_must_use)]
|
||||
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
struct A;
|
||||
struct B;
|
||||
|
|
@ -24,17 +23,17 @@ struct C;
|
|||
|
||||
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"));
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ extern crate rbml;
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue