diff options
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/fmt/builders.rs | 301 | ||||
| -rw-r--r-- | src/libcore/fmt/mod.rs | 122 |
2 files changed, 422 insertions, 1 deletions
diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs new file mode 100644 index 00000000000..07f029cc15e --- /dev/null +++ b/src/libcore/fmt/builders.rs @@ -0,0 +1,301 @@ +// Copyright 2015 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. + +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 = "debug_builders", reason = "method was just created")] + pub fn field(mut self, name: &str, value: &fmt::Debug) -> DebugStruct<'a, 'b> { + 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 = "debug_builders", 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 = "debug_builders", reason = "method was just created")] + pub fn field(mut self, value: &fmt::Debug) -> DebugTuple<'a, 'b> { + 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 = "debug_builders", 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 = "debug_builders", reason = "method was just created")] + pub fn entry(mut self, entry: &fmt::Debug) -> DebugSet<'a, 'b> { + 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 = "debug_builders", 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 = "debug_builders", reason = "method was just created")] + pub fn entry(mut self, key: &fmt::Debug, value: &fmt::Debug) -> DebugMap<'a, 'b> { + 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 = "debug_builders", 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..741cf7b47fa 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,123 @@ 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")] + #[inline] + 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")] + #[inline] + 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")] + #[inline] + 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")] + #[inline] + 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")] |
