diff options
| author | Steven Fackler <sfackler@gmail.com> | 2015-03-06 21:16:44 -0800 |
|---|---|---|
| committer | Steven Fackler <sfackler@gmail.com> | 2015-03-09 23:24:34 -0700 |
| commit | e3656bd81baa3c2cb5065da04f9debf378f99772 (patch) | |
| tree | d10b07092f56e83dd42e97c1f97fd924fc05b6bc /src/libcore/fmt | |
| parent | 12b846ab80ca054d2fbfb0320d33badbd5ef0112 (diff) | |
| download | rust-e3656bd81baa3c2cb5065da04f9debf378f99772.tar.gz rust-e3656bd81baa3c2cb5065da04f9debf378f99772.zip | |
Implement RFC 640
Diffstat (limited to 'src/libcore/fmt')
| -rw-r--r-- | src/libcore/fmt/builders.rs | 292 | ||||
| -rw-r--r-- | src/libcore/fmt/mod.rs | 118 |
2 files changed, 409 insertions, 1 deletions
diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs new file mode 100644 index 00000000000..e7b4cd1122c --- /dev/null +++ b/src/libcore/fmt/builders.rs @@ -0,0 +1,292 @@ +use prelude::*; +use fmt::{self, Write, FlagV1}; + +struct PadAdapter<'a, 'b: 'a> { + fmt: &'a mut fmt::Formatter<'b>, + on_newline: bool, +} + +impl<'a, 'b: 'a> PadAdapter<'a, 'b> { + fn new(fmt: &'a mut fmt::Formatter<'b>) -> PadAdapter<'a, 'b> { + PadAdapter { + fmt: fmt, + on_newline: false, + } + } +} + +impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> { + fn write_str(&mut self, mut s: &str) -> fmt::Result { + while !s.is_empty() { + if self.on_newline { + try!(self.fmt.write_str(" ")); + } + + let split = match s.find('\n') { + Some(pos) => { + self.on_newline = true; + pos + 1 + } + None => { + self.on_newline = false; + s.len() + } + }; + try!(self.fmt.write_str(&s[..split])); + s = &s[split..]; + } + + Ok(()) + } +} + +/// A struct to help with `fmt::Debug` implementations. +/// +/// Constructed by the `Formatter::debug_struct` method. +#[must_use] +pub struct DebugStruct<'a, 'b: 'a> { + fmt: &'a mut fmt::Formatter<'b>, + result: fmt::Result, + has_fields: bool, +} + +pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) + -> DebugStruct<'a, 'b> { + let result = fmt.write_str(name); + DebugStruct { + fmt: fmt, + result: result, + has_fields: false, + } +} + +impl<'a, 'b: 'a> DebugStruct<'a, 'b> { + /// Adds a new field to the generated struct output. + #[unstable(feature = "core", reason = "method was just created")] + pub fn field<S>(mut self, name: &str, value: &S) -> DebugStruct<'a, 'b> + where S: fmt::Debug { + self.result = self.result.and_then(|_| { + let prefix = if self.has_fields { + "," + } else { + " {" + }; + + if self.is_pretty() { + let mut writer = PadAdapter::new(self.fmt); + fmt::write(&mut writer, format_args!("{}\n{}: {:#?}", prefix, name, value)) + } else { + write!(self.fmt, "{} {}: {:?}", prefix, name, value) + } + }); + + self.has_fields = true; + self + } + + /// Consumes the `DebugStruct`, finishing output and returning any error + /// encountered. + #[unstable(feature = "core", reason = "method was just created")] + pub fn finish(mut self) -> fmt::Result { + if self.has_fields { + self.result = self.result.and_then(|_| { + if self.is_pretty() { + self.fmt.write_str("\n}") + } else { + self.fmt.write_str(" }") + } + }); + } + self.result + } + + fn is_pretty(&self) -> bool { + self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0 + } +} + +/// A struct to help with `fmt::Debug` implementations. +/// +/// Constructed by the `Formatter::debug_tuple` method. +#[must_use] +pub struct DebugTuple<'a, 'b: 'a> { + fmt: &'a mut fmt::Formatter<'b>, + result: fmt::Result, + has_fields: bool, +} + +pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugTuple<'a, 'b> { + let result = fmt.write_str(name); + DebugTuple { + fmt: fmt, + result: result, + has_fields: false, + } +} + +impl<'a, 'b: 'a> DebugTuple<'a, 'b> { + /// Adds a new field to the generated tuple struct output. + #[unstable(feature = "core", reason = "method was just created")] + pub fn field<S>(mut self, value: &S) -> DebugTuple<'a, 'b> where S: fmt::Debug { + self.result = self.result.and_then(|_| { + let (prefix, space) = if self.has_fields { + (",", " ") + } else { + ("(", "") + }; + + if self.is_pretty() { + let mut writer = PadAdapter::new(self.fmt); + fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, value)) + } else { + write!(self.fmt, "{}{}{:?}", prefix, space, value) + } + }); + + self.has_fields = true; + self + } + + /// Consumes the `DebugTuple`, finishing output and returning any error + /// encountered. + #[unstable(feature = "core", reason = "method was just created")] + pub fn finish(mut self) -> fmt::Result { + if self.has_fields { + self.result = self.result.and_then(|_| { + if self.is_pretty() { + self.fmt.write_str("\n)") + } else { + self.fmt.write_str(")") + } + }); + } + self.result + } + + fn is_pretty(&self) -> bool { + self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0 + } +} + +/// A struct to help with `fmt::Debug` implementations. +/// +/// Constructed by the `Formatter::debug_set` method. +#[must_use] +pub struct DebugSet<'a, 'b: 'a> { + fmt: &'a mut fmt::Formatter<'b>, + result: fmt::Result, + has_fields: bool, +} + +pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugSet<'a, 'b> { + let result = write!(fmt, "{} {{", name); + DebugSet { + fmt: fmt, + result: result, + has_fields: false, + } +} + +impl<'a, 'b: 'a> DebugSet<'a, 'b> { + /// Adds a new entry to the set output. + #[unstable(feature = "core", reason = "method was just created")] + pub fn entry<S>(mut self, entry: &S) -> DebugSet<'a, 'b> where S: fmt::Debug { + self.result = self.result.and_then(|_| { + let prefix = if self.has_fields { + "," + } else { + "" + }; + + if self.is_pretty() { + let mut writer = PadAdapter::new(self.fmt); + fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry)) + } else { + write!(self.fmt, "{} {:?}", prefix, entry) + } + }); + + self.has_fields = true; + self + } + + /// Consumes the `DebugSet`, finishing output and returning any error + /// encountered. + #[unstable(feature = "core", reason = "method was just created")] + pub fn finish(self) -> fmt::Result { + self.result.and_then(|_| { + let end = match (self.has_fields, self.is_pretty()) { + (false, _) => "}", + (true, false) => " }", + (true, true) => "\n}", + }; + self.fmt.write_str(end) + }) + } + + fn is_pretty(&self) -> bool { + self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0 + } +} + +/// A struct to help with `fmt::Debug` implementations. +/// +/// Constructed by the `Formatter::debug_map` method. +#[must_use] +pub struct DebugMap<'a, 'b: 'a> { + fmt: &'a mut fmt::Formatter<'b>, + result: fmt::Result, + has_fields: bool, +} + +pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugMap<'a, 'b> { + let result = write!(fmt, "{} {{", name); + DebugMap { + fmt: fmt, + result: result, + has_fields: false, + } +} + +impl<'a, 'b: 'a> DebugMap<'a, 'b> { + /// Adds a new entry to the map output. + #[unstable(feature = "core", reason = "method was just created")] + pub fn entry<K, V>(mut self, key: &K, value: &V) -> DebugMap<'a, 'b> + where K: fmt::Debug, V: fmt::Debug { + self.result = self.result.and_then(|_| { + let prefix = if self.has_fields { + "," + } else { + "" + }; + + if self.is_pretty() { + let mut writer = PadAdapter::new(self.fmt); + fmt::write(&mut writer, format_args!("{}\n{:#?}: {:#?}", prefix, key, value)) + } else { + write!(self.fmt, "{} {:?}: {:?}", prefix, key, value) + } + }); + + self.has_fields = true; + self + } + + /// Consumes the `DebugMap`, finishing output and returning any error + /// encountered. + #[unstable(feature = "core", reason = "method was just created")] + pub fn finish(self) -> fmt::Result { + self.result.and_then(|_| { + let end = match (self.has_fields, self.is_pretty()) { + (false, _) => "}", + (true, false) => " }", + (true, true) => "\n}", + }; + self.fmt.write_str(end) + }) + } + + fn is_pretty(&self) -> bool { + self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0 + } +} diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index e640bf02f5a..572d613f192 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -32,8 +32,11 @@ pub use self::num::radix; pub use self::num::Radix; pub use self::num::RadixFmt; +pub use self::builders::{DebugStruct, DebugTuple, DebugSet, DebugMap}; + mod num; mod float; +mod builders; #[stable(feature = "rust1", since = "1.0.0")] #[doc(hidden)] @@ -425,7 +428,7 @@ impl<'a> Formatter<'a> { /// # Arguments /// /// * is_positive - whether the original integer was positive or not. - /// * prefix - if the '#' character (FlagAlternate) is provided, this + /// * prefix - if the '#' character (Alternate) is provided, this /// is the prefix to put in front of the number. /// * buf - the byte array that the number has been formatted into /// @@ -614,6 +617,119 @@ impl<'a> Formatter<'a> { /// Optionally specified precision for numeric types #[unstable(feature = "core", reason = "method was just created")] pub fn precision(&self) -> Option<usize> { self.precision } + + /// Creates a `DebugStruct` builder designed to assist with creation of + /// `fmt::Debug` implementations for structs. + /// + /// # Examples + /// + /// ```rust + /// use std::fmt; + /// + /// struct Foo { + /// bar: i32, + /// baz: String, + /// } + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// fmt.debug_struct("Foo") + /// .field("bar", &self.bar) + /// .field("baz", &self.baz) + /// .finish() + /// } + /// } + /// + /// // prints "Foo { bar: 10, baz: "Hello World" }" + /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); + /// ``` + #[unstable(feature = "core", reason = "method was just created")] + pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> { + builders::debug_struct_new(self, name) + } + + /// Creates a `DebugTuple` builder designed to assist with creation of + /// `fmt::Debug` implementations for tuple structs. + /// + /// # Examples + /// + /// ```rust + /// use std::fmt; + /// + /// struct Foo(i32, String); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// fmt.debug_tuple("Foo") + /// .field(&self.0) + /// .field(&self.1) + /// .finish() + /// } + /// } + /// + /// // prints "Foo(10, "Hello World")" + /// println!("{:?}", Foo(10, "Hello World".to_string())); + /// ``` + #[unstable(feature = "core", reason = "method was just created")] + pub fn debug_tuple<'b>(&'b mut self, name: &str) -> DebugTuple<'b, 'a> { + builders::debug_tuple_new(self, name) + } + + /// Creates a `DebugSet` builder designed to assist with creation of + /// `fmt::Debug` implementations for set-like structures. + /// + /// # Examples + /// + /// ```rust + /// use std::fmt; + /// + /// struct Foo(Vec<i32>); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// let mut builder = fmt.debug_set("Foo"); + /// for i in &self.0 { + /// builder = builder.entry(i); + /// } + /// builder.finish() + /// } + /// } + /// + /// // prints "Foo { 10, 11 }" + /// println!("{:?}", Foo(vec![10, 11])); + /// ``` + #[unstable(feature = "core", reason = "method was just created")] + pub fn debug_set<'b>(&'b mut self, name: &str) -> DebugSet<'b, 'a> { + builders::debug_set_new(self, name) + } + + /// Creates a `DebugMap` builder designed to assist with creation of + /// `fmt::Debug` implementations for map-like structures. + /// + /// # Examples + /// + /// ```rust + /// use std::fmt; + /// + /// struct Foo(Vec<(String, i32)>); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + /// let mut builder = fmt.debug_map("Foo"); + /// for &(ref key, ref value) in &self.0 { + /// builder = builder.entry(key, value); + /// } + /// builder.finish() + /// } + /// } + /// + /// // prints "Foo { "A": 10, "B": 11 }" + /// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11))); + /// ``` + #[unstable(feature = "core", reason = "method was just created")] + pub fn debug_map<'b>(&'b mut self, name: &str) -> DebugMap<'b, 'a> { + builders::debug_map_new(self, name) + } } #[stable(feature = "rust1", since = "1.0.0")] |
