about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorSteven Fackler <sfackler@gmail.com>2015-03-06 21:16:44 -0800
committerSteven Fackler <sfackler@gmail.com>2015-03-09 23:24:34 -0700
commite3656bd81baa3c2cb5065da04f9debf378f99772 (patch)
treed10b07092f56e83dd42e97c1f97fd924fc05b6bc /src/libcore
parent12b846ab80ca054d2fbfb0320d33badbd5ef0112 (diff)
downloadrust-e3656bd81baa3c2cb5065da04f9debf378f99772.tar.gz
rust-e3656bd81baa3c2cb5065da04f9debf378f99772.zip
Implement RFC 640
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/fmt/builders.rs292
-rw-r--r--src/libcore/fmt/mod.rs118
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")]