diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs index eeaea6a2cffa9..42b7edc0675f3 100644 --- a/src/libstd/bool.rs +++ b/src/libstd/bool.rs @@ -19,7 +19,6 @@ A quick summary: Implementations of the following traits: * `FromStr` -* `ToStr` * `Not` * `Ord` * `TotalOrd` @@ -39,7 +38,6 @@ Finally, some inquries into the nature of truth: `is_true` and `is_false`. use option::{None, Option, Some}; use from_str::FromStr; -use to_str::ToStr; #[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering}; #[cfg(not(test))] use ops::Not; @@ -202,28 +200,6 @@ impl FromStr for bool { } } -/** -* Convert a `bool` to a `str`. -* -* # Examples -* -* ~~~ {.rust} -* rusti> true.to_str() -* "true" -* ~~~ -* -* ~~~ {.rust} -* rusti> false.to_str() -* "false" -* ~~~ -*/ -impl ToStr for bool { - #[inline] - fn to_str(&self) -> ~str { - if *self { ~"true" } else { ~"false" } - } -} - /** * Iterates over all truth values, passing them to the given block. * diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index e3dae5308fed9..02217172761f9 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -56,15 +56,19 @@ pub fn console_off() { pub fn log_type(level: u32, object: &T) { use cast; use container::Container; - use io; + use rt::io::Decorator; + use rt::io::mem::MemWriter; use libc; use repr; use rt; use str; + use util; use vec; - let bytes = do io::with_bytes_writer |writer| { - repr::write_repr(writer, object); + let bytes = { + let wr = @mut MemWriter::new(); + repr::write_repr(wr, object); + util::replace(wr, MemWriter::new()).inner() }; match rt::context() { diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index cef32b5c7e445..2e599e7217c6a 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -19,6 +19,7 @@ macro_rules! int_module (($T:ty, $bits:expr) => (mod generated { use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; +use rt::io::StringWriter; use str; pub use cmp::{min, max}; @@ -557,6 +558,13 @@ impl ToStr for $T { fn to_str(&self) -> ~str { to_str(*self) } + + #[inline] + fn to_str_writer(&self, w: &mut W) { + do strconv::int_to_str_bytes_common(*self, 10u, strconv::SignNeg) |c| { + w.write_char(c as char) + } + } } impl ToStrRadix for $T { diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index acf7ea683fb54..c8333d7a5c6eb 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -20,6 +20,7 @@ use num::BitCount; use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; +use rt::io::StringWriter; use str; pub use cmp::{min, max}; @@ -411,6 +412,13 @@ impl ToStr for $T { fn to_str(&self) -> ~str { to_str(*self) } + + #[inline] + fn to_str_writer(&self, w: &mut W) { + do strconv::int_to_str_bytes_common(*self, 10u, strconv::SignNeg) |c| { + w.write_char(c as char) + } + } } impl ToStrRadix for $T { diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index edab639dfbe8b..3daae0da141d9 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -19,29 +19,29 @@ More runtime type reflection use cast::transmute; use char; use container::Container; -use io::{Writer, WriterUtil}; use iterator::Iterator; +use iterator::IteratorUtil; use libc::c_void; use option::{Some, None}; use ptr; use reflect; use reflect::{MovePtr, align}; +use rt::io::StringWriter; use str::StrSlice; use to_str::ToStr; use vec::OwnedVector; use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc}; use unstable::raw; -#[cfg(test)] use io; /// Helpers trait EscapedCharWriter { - fn write_escaped_char(&self, ch: char); + fn write_escaped_char(&mut self, ch: char); } -impl EscapedCharWriter for @Writer { - fn write_escaped_char(&self, ch: char) { +impl EscapedCharWriter for W { + fn write_escaped_char(&mut self, ch: char) { match ch { '\t' => self.write_str("\\t"), '\r' => self.write_str("\\r"), @@ -62,45 +62,35 @@ impl EscapedCharWriter for @Writer { /// Representations trait Repr { - fn write_repr(&self, writer: @Writer); + fn write_repr(&self, writer: &mut W); } impl Repr for () { - fn write_repr(&self, writer: @Writer) { writer.write_str("()"); } + fn write_repr(&self, writer: &mut W) { writer.write_str("()"); } } impl Repr for bool { - fn write_repr(&self, writer: @Writer) { + fn write_repr(&self, writer: &mut W) { writer.write_str(if *self { "true" } else { "false" }) } } -macro_rules! int_repr(($ty:ident) => (impl Repr for $ty { - fn write_repr(&self, writer: @Writer) { - do ::$ty::to_str_bytes(*self, 10u) |bits| { - writer.write(bits); - } - } -})) - -int_repr!(int) -int_repr!(i8) -int_repr!(i16) -int_repr!(i32) -int_repr!(i64) -int_repr!(uint) -int_repr!(u8) -int_repr!(u16) -int_repr!(u32) -int_repr!(u64) - macro_rules! num_repr(($ty:ident) => (impl Repr for $ty { - fn write_repr(&self, writer: @Writer) { - let s = self.to_str(); - writer.write(s.as_bytes()); + fn write_repr(&self, writer: &mut W) { + self.to_str_writer(writer); } })) +num_repr!(int) +num_repr!(i8) +num_repr!(i16) +num_repr!(i32) +num_repr!(i64) +num_repr!(uint) +num_repr!(u8) +num_repr!(u16) +num_repr!(u32) +num_repr!(u64) num_repr!(float) num_repr!(f32) num_repr!(f64) @@ -113,13 +103,14 @@ enum VariantState { AlreadyFound } -pub struct ReprVisitor { +pub struct ReprVisitor { ptr: @mut *c_void, ptr_stk: @mut ~[*c_void], var_stk: @mut ~[VariantState], - writer: @Writer + writer: @mut W, } -pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor { + +pub fn ReprVisitor(ptr: *c_void, writer: @mut W) -> ReprVisitor { ReprVisitor { ptr: @mut ptr, ptr_stk: @mut ~[], @@ -128,7 +119,7 @@ pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor { } } -impl MovePtr for ReprVisitor { +impl MovePtr for ReprVisitor { #[inline] fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) { *self.ptr = adjustment(*self.ptr); @@ -141,7 +132,7 @@ impl MovePtr for ReprVisitor { } } -impl ReprVisitor { +impl ReprVisitor { // Various helpers for the TyVisitor impl #[inline] @@ -175,21 +166,21 @@ impl ReprVisitor { } pub fn write_escaped_slice(&self, slice: &str) { - self.writer.write_char('"'); + (*self.writer).write_char('"'); foreach ch in slice.iter() { - self.writer.write_escaped_char(ch); + (*self.writer).write_escaped_char(ch); } - self.writer.write_char('"'); + (*self.writer).write_char('"'); } pub fn write_mut_qualifier(&self, mtbl: uint) { if mtbl == 0 { - self.writer.write_str("mut "); + (*self.writer).write_str("mut "); } else if mtbl == 1 { // skip, this is ast::m_imm } else { assert_eq!(mtbl, 2); - self.writer.write_str("const "); + (*self.writer).write_str("const "); } } @@ -201,7 +192,7 @@ impl ReprVisitor { -> bool { let mut p = ptr as *u8; let (sz, al) = unsafe { ((*inner).size, (*inner).align) }; - self.writer.write_char('['); + (*self.writer).write_char('['); let mut first = true; let mut left = len; // unit structs have 0 size, and don't loop forever. @@ -210,13 +201,13 @@ impl ReprVisitor { if first { first = false; } else { - self.writer.write_str(", "); + (*self.writer).write_str(", "); } self.visit_ptr_inner(p as *c_void, inner); p = align(ptr::offset(p, sz as int) as uint, al) as *u8; left -= dec; } - self.writer.write_char(']'); + (*self.writer).write_char(']'); true } @@ -230,9 +221,9 @@ impl ReprVisitor { } } -impl TyVisitor for ReprVisitor { +impl TyVisitor for ReprVisitor { fn visit_bot(&self) -> bool { - self.writer.write_str("!"); + (*self.writer).write_str("!"); true } fn visit_nil(&self) -> bool { self.write::<()>() } @@ -255,21 +246,21 @@ impl TyVisitor for ReprVisitor { fn visit_char(&self) -> bool { do self.get:: |&ch| { - self.writer.write_char('\''); - self.writer.write_escaped_char(ch); - self.writer.write_char('\''); + (*self.writer).write_char('\''); + (*self.writer).write_escaped_char(ch); + (*self.writer).write_char('\''); } } fn visit_estr_box(&self) -> bool { do self.get::<@str> |s| { - self.writer.write_char('@'); + (*self.writer).write_char('@'); self.write_escaped_slice(*s); } } fn visit_estr_uniq(&self) -> bool { do self.get::<~str> |s| { - self.writer.write_char('~'); + (*self.writer).write_char('~'); self.write_escaped_slice(*s); } } @@ -284,7 +275,7 @@ impl TyVisitor for ReprVisitor { _align: uint) -> bool { fail!(); } fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write_char('@'); + (*self.writer).write_char('@'); self.write_mut_qualifier(mtbl); do self.get::<&raw::Box<()>> |b| { let p = ptr::to_unsafe_ptr(&b.data) as *c_void; @@ -293,14 +284,14 @@ impl TyVisitor for ReprVisitor { } fn visit_uniq(&self, _mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write_char('~'); + (*self.writer).write_char('~'); do self.get::<*c_void> |b| { self.visit_ptr_inner(*b, inner); } } fn visit_uniq_managed(&self, _mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write_char('~'); + (*self.writer).write_char('~'); do self.get::<&raw::Box<()>> |b| { let p = ptr::to_unsafe_ptr(&b.data) as *c_void; self.visit_ptr_inner(p, inner); @@ -309,13 +300,13 @@ impl TyVisitor for ReprVisitor { fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool { do self.get::<*c_void> |p| { - self.writer.write_str(fmt!("(0x%x as *())", + (*self.writer).write_str(fmt!("(0x%x as *())", *p as uint)); } } fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool { - self.writer.write_char('&'); + (*self.writer).write_char('&'); self.write_mut_qualifier(mtbl); do self.get::<*c_void> |p| { self.visit_ptr_inner(*p, inner); @@ -334,7 +325,7 @@ impl TyVisitor for ReprVisitor { fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool { do self.get::<&raw::Box>> |b| { - self.writer.write_char('@'); + (*self.writer).write_char('@'); self.write_mut_qualifier(mtbl); self.write_unboxed_vec_repr(mtbl, &b.data, inner); } @@ -342,21 +333,21 @@ impl TyVisitor for ReprVisitor { fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool { do self.get::<&raw::Vec<()>> |b| { - self.writer.write_char('~'); + (*self.writer).write_char('~'); self.write_unboxed_vec_repr(mtbl, *b, inner); } } fn visit_evec_uniq_managed(&self, mtbl: uint, inner: *TyDesc) -> bool { do self.get::<&raw::Box>> |b| { - self.writer.write_char('~'); + (*self.writer).write_char('~'); self.write_unboxed_vec_repr(mtbl, &b.data, inner); } } fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool { do self.get::> |s| { - self.writer.write_char('&'); + (*self.writer).write_char('&'); self.write_vec_range(mtbl, s.data, s.len, inner); } } @@ -370,58 +361,58 @@ impl TyVisitor for ReprVisitor { fn visit_enter_rec(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { - self.writer.write_char('{'); + (*self.writer).write_char('{'); true } fn visit_rec_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool { if i != 0 { - self.writer.write_str(", "); + (*self.writer).write_str(", "); } self.write_mut_qualifier(mtbl); - self.writer.write_str(name); - self.writer.write_str(": "); + (*self.writer).write_str(name); + (*self.writer).write_str(": "); self.visit_inner(inner); true } fn visit_leave_rec(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { - self.writer.write_char('}'); + (*self.writer).write_char('}'); true } fn visit_enter_class(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { - self.writer.write_char('{'); + (*self.writer).write_char('{'); true } fn visit_class_field(&self, i: uint, name: &str, mtbl: uint, inner: *TyDesc) -> bool { if i != 0 { - self.writer.write_str(", "); + (*self.writer).write_str(", "); } self.write_mut_qualifier(mtbl); - self.writer.write_str(name); - self.writer.write_str(": "); + (*self.writer).write_str(name); + (*self.writer).write_str(": "); self.visit_inner(inner); true } fn visit_leave_class(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { - self.writer.write_char('}'); + (*self.writer).write_char('}'); true } fn visit_enter_tup(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { - self.writer.write_char('('); + (*self.writer).write_char('('); true } fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool { if i != 0 { - self.writer.write_str(", "); + (*self.writer).write_str(", "); } self.visit_inner(inner); true @@ -429,9 +420,9 @@ impl TyVisitor for ReprVisitor { fn visit_leave_tup(&self, _n_fields: uint, _sz: uint, _align: uint) -> bool { if _n_fields == 1 { - self.writer.write_char(','); + (*self.writer).write_char(','); } - self.writer.write_char(')'); + (*self.writer).write_char(')'); true } @@ -468,9 +459,9 @@ impl TyVisitor for ReprVisitor { } if write { - self.writer.write_str(name); + (*self.writer).write_str(name); if n_fields > 0 { - self.writer.write_char('('); + (*self.writer).write_char('('); } } true @@ -484,7 +475,7 @@ impl TyVisitor for ReprVisitor { match self.var_stk[self.var_stk.len() - 1] { Matched => { if i != 0 { - self.writer.write_str(", "); + (*self.writer).write_str(", "); } if ! self.visit_inner(inner) { return false; @@ -502,7 +493,7 @@ impl TyVisitor for ReprVisitor { match self.var_stk[self.var_stk.len() - 1] { Matched => { if n_fields > 0 { - self.writer.write_char(')'); + (*self.writer).write_char(')'); } } _ => () @@ -543,7 +534,7 @@ impl TyVisitor for ReprVisitor { fn visit_type(&self) -> bool { true } fn visit_opaque_box(&self) -> bool { - self.writer.write_char('@'); + (*self.writer).write_char('@'); do self.get::<&raw::Box<()>> |b| { let p = ptr::to_unsafe_ptr(&b.data) as *c_void; self.visit_ptr_inner(p, b.type_desc); @@ -556,7 +547,7 @@ impl TyVisitor for ReprVisitor { fn visit_closure_ptr(&self, _ck: uint) -> bool { true } } -pub fn write_repr(writer: @Writer, object: &T) { +pub fn write_repr(writer: @mut W, object: &T) { unsafe { let ptr = ptr::to_unsafe_ptr(object) as *c_void; let tydesc = get_tydesc::(); @@ -571,9 +562,22 @@ struct P {a: int, b: float} #[test] fn test_repr() { + use str; + use str::Str; + use rt::io::Decorator; + use rt::io::mem::MemWriter; + use util; + + fn log_str(t: &T) -> ~str { + let wr = @mut MemWriter::new(); + write_repr(wr, t); + let wr_out = util::replace(wr, MemWriter::new()); + str::from_bytes_owned(wr_out.inner()) + } fn exact_test(t: &T, e:&str) { - let s : &str = io::with_str_writer(|w| write_repr(w, t)); + let s = log_str(t); + let s = s.as_slice(); if s != e { error!("expected '%s', got '%s'", e, s); diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs index 2d21bf0f9dcf3..908eab55087ea 100644 --- a/src/libstd/rt/io/extensions.rs +++ b/src/libstd/rt/io/extensions.rs @@ -16,6 +16,7 @@ use uint; use int; use vec; +use str; use rt::io::{Reader, Writer}; use rt::io::{read_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE}; use option::{Option, Some, None}; @@ -273,6 +274,32 @@ pub trait WriterByteConversions { fn write_i8(&mut self, n: i8); } +pub trait StringWriter { + /// Write a single utf-8 encoded char. + fn write_char(&mut self, ch: char); + + /// Write every char in the given str, encoded as utf-8. + fn write_str(&mut self, s: &str); + + /// Write the given str, as utf-8, followed by '\n'. + fn write_line(&mut self, s: &str); +} + +impl StringWriter for T { + fn write_char(&mut self, ch: char) { + if (ch as uint) < 128u { + self.write(&[ch as u8]); + } else { + self.write_str(str::from_char(ch)); + } + } + fn write_str(&mut self, s: &str) { self.write(s.as_bytes()) } + fn write_line(&mut self, s: &str) { + self.write_str(s); + self.write_str(&"\n"); + } +} + impl ReaderUtil for T { fn read_byte(&mut self) -> Option { let mut buf = [0]; diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 838c2d86c9fa2..c73d0769d9744 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -262,6 +262,7 @@ pub use self::net::udp::UdpStream; pub use self::extensions::ReaderUtil; pub use self::extensions::ReaderByteConversions; pub use self::extensions::WriterByteConversions; +pub use self::extensions::StringWriter; /// Synchronous, non-blocking file I/O. pub mod file; @@ -505,4 +506,4 @@ pub fn placeholder_error() -> IoError { desc: "Placeholder error. You shouldn't be seeing this", detail: None } -} \ No newline at end of file +} diff --git a/src/libstd/str.rs b/src/libstd/str.rs index f0c0595744c95..971cb05767c7e 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -31,7 +31,6 @@ use num::Zero; use option::{None, Option, Some}; use ptr; use ptr::RawPtr; -use to_str::ToStr; use uint; use unstable::raw::Repr; use vec; @@ -115,19 +114,6 @@ pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { } } -impl ToStr for ~str { - #[inline] - fn to_str(&self) -> ~str { self.to_owned() } -} -impl<'self> ToStr for &'self str { - #[inline] - fn to_str(&self) -> ~str { self.to_owned() } -} -impl ToStr for @str { - #[inline] - fn to_str(&self) -> ~str { self.to_owned() } -} - /// Convert a byte to a UTF-8 string /// /// # Failure @@ -2271,6 +2257,7 @@ mod tests { use libc; use ptr; use str::*; + use to_str::ToStr; use vec; use vec::{ImmutableVector, CopyableVector}; use cmp::{TotalOrd, Less, Equal, Greater}; diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs index 4ca5d82265fbf..0f91c7fd7f0b9 100644 --- a/src/libstd/sys.rs +++ b/src/libstd/sys.rs @@ -14,13 +14,15 @@ use cast; use gc; -use io; use libc; use libc::{c_char, size_t}; use repr; +use rt::io::Decorator; +use rt::io::mem::MemWriter; use str::StrSlice; use str; use unstable::intrinsics; +use util; pub mod rustrt { use libc::{c_char, size_t}; @@ -104,9 +106,10 @@ pub fn refcount(t: @T) -> uint { } pub fn log_str(t: &T) -> ~str { - do io::with_str_writer |wr| { - repr::write_repr(wr, t) - } + let wr = @mut MemWriter::new(); + repr::write_repr(wr, t); + let wr_out = util::replace(wr, MemWriter::new()); + str::from_bytes_owned(wr_out.inner()) } /// Trait for initiating task failure. diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index 5ad7969c8d21f..8383ce7973600 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -15,12 +15,12 @@ The `ToBytes` and `IterBytes` traits */ use cast; -use io; -use io::Writer; +use rt::io::{Writer, Decorator}; +use rt::io::mem::MemWriter; use iterator::IteratorUtil; use option::{None, Option, Some}; use str::StrSlice; -use vec::ImmutableVector; +use vec::{Vector, ImmutableVector}; pub type Cb<'self> = &'self fn(buf: &[u8]) -> bool; @@ -251,22 +251,17 @@ impl IterBytes for (A,B,C) { } } -// Move this to vec, probably. -fn borrow<'x,A>(a: &'x [A]) -> &'x [A] { - a -} - impl IterBytes for ~[A] { #[inline] fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - borrow(*self).iter_bytes(lsb0, f) + self.as_slice().iter_bytes(lsb0, f) } } impl IterBytes for @[A] { #[inline] fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool { - borrow(*self).iter_bytes(lsb0, f) + self.as_slice().iter_bytes(lsb0, f) } } @@ -352,11 +347,11 @@ pub trait ToBytes { impl ToBytes for A { fn to_bytes(&self, lsb0: bool) -> ~[u8] { - do io::with_bytes_writer |wr| { - do self.iter_bytes(lsb0) |bytes| { - wr.write(bytes); - true - }; - } + let mut wr = MemWriter::new(); + do self.iter_bytes(lsb0) |bytes| { + wr.write(bytes); + true + }; + wr.inner() } } diff --git a/src/libstd/to_str.rs b/src/libstd/to_str.rs index b87a165706516..a605d1741309f 100644 --- a/src/libstd/to_str.rs +++ b/src/libstd/to_str.rs @@ -21,12 +21,28 @@ use hashmap::HashSet; use hash::Hash; use iterator::Iterator; use cmp::Eq; -use vec::ImmutableVector; +use rt::io::{StringWriter, Decorator}; +use rt::io::mem::MemWriter; +use str; +use str::StrSlice; +use vec::{Vector, ImmutableVector}; +// FIXME #7771: Needs to be marked that at least one method should be impl /// A generic trait for converting a value to a string pub trait ToStr { /// Converts the value of `self` to an owned string - fn to_str(&self) -> ~str; + fn to_str(&self) -> ~str { + let mut wr = MemWriter::new(); + self.to_str_writer(&mut wr); + str::from_bytes_owned(wr.inner()) + } + + /// Write a string representation of `self` to `w` + #[inline] + fn to_str_writer(&self, w: &mut W) { + // Passing down `StringWriter` restricts implementors to writing string parts, + w.write_str(self.to_str()); + } } /// Trait for converting a type to a string, consuming it in the process. @@ -37,152 +53,175 @@ pub trait ToStrConsume { impl ToStr for () { #[inline] - fn to_str(&self) -> ~str { ~"()" } + fn to_str_writer(&self, w: &mut W) { w.write_str("()"); } } -impl ToStr for (A,) { +/** +* Convert a `bool` to a `str`. +* +* # Examples +* +* ~~~ {.rust} +* rusti> true.to_str() +* "true" +* ~~~ +* +* ~~~ {.rust} +* rusti> false.to_str() +* "false" +* ~~~ +*/ +impl ToStr for bool { #[inline] - fn to_str(&self) -> ~str { - match *self { - (ref a,) => { - fmt!("(%s,)", (*a).to_str()) - } - } + fn to_str_writer(&self, w: &mut W) { + w.write_str(if *self { "true" } else { "false" }) } } -impl ToStr for HashMap { +impl ToStr for ~str { #[inline] - fn to_str(&self) -> ~str { - let mut acc = ~"{"; - let mut first = true; - foreach (key, value) in self.iter() { - if first { - first = false; - } - else { - acc.push_str(", "); - } - acc.push_str(key.to_str()); - acc.push_str(": "); - acc.push_str(value.to_str()); - } - acc.push_char('}'); - acc - } + fn to_str(&self) -> ~str { self.to_owned() } + #[inline] + fn to_str_writer(&self, w: &mut W) { w.write_str(*self); } } - -impl ToStr for HashSet { +impl<'self> ToStr for &'self str { #[inline] - fn to_str(&self) -> ~str { - let mut acc = ~"{"; - let mut first = true; - foreach element in self.iter() { - if first { - first = false; - } - else { - acc.push_str(", "); - } - acc.push_str(element.to_str()); - } - acc.push_char('}'); - acc - } + fn to_str(&self) -> ~str { self.to_owned() } + #[inline] + fn to_str_writer(&self, w: &mut W) { w.write_str(*self); } +} +impl ToStr for @str { + #[inline] + fn to_str(&self) -> ~str { self.to_owned() } + #[inline] + fn to_str_writer(&self, w: &mut W) { w.write_str(*self); } } -impl ToStr for (A, B) { +impl ToStr for (A, ) { #[inline] - fn to_str(&self) -> ~str { - // FIXME(#4653): this causes an llvm assertion - //let &(ref a, ref b) = self; + fn to_str_writer(&self, w: &mut W) { + w.write_char('('); match *self { - (ref a, ref b) => { - fmt!("(%s, %s)", (*a).to_str(), (*b).to_str()) - } + (ref a, ) => a.to_str_writer(w), } + w.write_str(",)"); } } -impl ToStr for (A, B, C) { - #[inline] - fn to_str(&self) -> ~str { - // FIXME(#4653): this causes an llvm assertion - //let &(ref a, ref b, ref c) = self; - match *self { - (ref a, ref b, ref c) => { - fmt!("(%s, %s, %s)", - (*a).to_str(), - (*b).to_str(), - (*c).to_str() - ) +macro_rules! tuple_tostr( + ($A:ident, $($B:ident),+) => ( + impl<$A: ToStr $(,$B: ToStr)+> ToStr for ($A, $($B),+) { + #[inline] + fn to_str_writer(&self, w: &mut W) { + w.write_char('('); + match *self { + (ref $A, $( ref $B ),+) => { + ($A).to_str_writer(w); + $( + w.write_str(", "); + ($B).to_str_writer(w); + )* + } + } + w.write_char(')'); } } - } -} + ) +) + +tuple_tostr!(A, B) +tuple_tostr!(A, B, C) +tuple_tostr!(A, B, C, D) +tuple_tostr!(A, B, C, D, E) +tuple_tostr!(A, B, C, D, E, F) +tuple_tostr!(A, B, C, D, E, F, G) +tuple_tostr!(A, B, C, D, E, F, G, H) +tuple_tostr!(A, B, C, D, E, F, G, H, I) +tuple_tostr!(A, B, C, D, E, F, G, H, I, J) +tuple_tostr!(A, B, C, D, E, F, G, H, I, J, K) +tuple_tostr!(A, B, C, D, E, F, G, H, I, J, K, L) + -impl<'self,A:ToStr> ToStr for &'self [A] { +impl<'self, A: ToStr> ToStr for &'self [A] { #[inline] - fn to_str(&self) -> ~str { - let mut acc = ~"["; + fn to_str_writer(&self, w: &mut W) { + w.write_char('['); let mut first = true; - foreach elt in self.iter() { + foreach element in self.iter() { if first { first = false; } else { - acc.push_str(", "); + w.write_str(", "); } - acc.push_str(elt.to_str()); + element.to_str_writer(w); } - acc.push_char(']'); - acc + w.write_char(']'); } } -impl ToStr for ~[A] { +impl ToStr for ~[A] { #[inline] - fn to_str(&self) -> ~str { - let mut acc = ~"["; + fn to_str_writer(&self, w: &mut W) { + self.as_slice().to_str_writer(w) + } +} + +impl ToStr for @[A] { + #[inline] + fn to_str_writer(&self, w: &mut W) { + self.as_slice().to_str_writer(w) + } +} + +impl ToStr for HashMap { + #[inline] + fn to_str_writer(&self, w: &mut W) { + w.write_char('{'); let mut first = true; - foreach elt in self.iter() { + foreach (key, value) in self.iter() { if first { first = false; } else { - acc.push_str(", "); + w.write_str(", "); } - acc.push_str(elt.to_str()); + key.to_str_writer(w); + w.write_str(": "); + value.to_str_writer(w); } - acc.push_char(']'); - acc + w.write_char('}'); } } -impl ToStr for @[A] { +impl ToStr for HashSet { #[inline] - fn to_str(&self) -> ~str { - let mut acc = ~"["; + fn to_str_writer(&self, w: &mut W) { + w.write_char('{'); let mut first = true; - foreach elt in self.iter() { + foreach element in self.iter() { if first { first = false; } else { - acc.push_str(", "); + w.write_str(", "); } - acc.push_str(elt.to_str()); + element.to_str_writer(w); } - acc.push_char(']'); - acc + w.write_char('}'); } } #[cfg(test)] mod tests { + extern mod extra; + use extra::test::BenchHarness; + use hashmap::HashMap; use hashmap::HashSet; - use container::{MutableSet, MutableMap}; + use uint; + use container::{Container, MutableSet, MutableMap}; + use str::StrSlice; use super::*; #[test] @@ -252,4 +291,16 @@ mod tests { assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}"); assert_eq!(empty_set.to_str(), ~"{}"); } + + #[bench] + fn bench_hashmap(b: &mut BenchHarness) { + let mut map = HashMap::new::(); + let s = "0123456789"; + for uint::range(0, 100) |i| { + map.insert(i, s.slice(0, i % s.len())); + } + do b.iter { + let s = map.to_str(); s.len(); + } + } }