From e3656bd81baa3c2cb5065da04f9debf378f99772 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 6 Mar 2015 21:16:44 -0800 Subject: [PATCH 1/6] Implement RFC 640 --- src/libcore/fmt/builders.rs | 292 ++++++++++++++++++++++++ src/libcore/fmt/mod.rs | 118 +++++++++- src/libcoretest/fmt/builders.rs | 391 ++++++++++++++++++++++++++++++++ src/libcoretest/fmt/mod.rs | 1 + 4 files changed, 801 insertions(+), 1 deletion(-) create mode 100644 src/libcore/fmt/builders.rs create mode 100644 src/libcoretest/fmt/builders.rs diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs new file mode 100644 index 0000000000000..e7b4cd1122cd0 --- /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(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(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(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(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 e640bf02f5a32..572d613f192ad 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 { 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); + /// + /// 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")] diff --git a/src/libcoretest/fmt/builders.rs b/src/libcoretest/fmt/builders.rs new file mode 100644 index 0000000000000..84076b349d2f7 --- /dev/null +++ b/src/libcoretest/fmt/builders.rs @@ -0,0 +1,391 @@ +mod debug_struct { + use std::fmt; + + #[test] + fn test_empty() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Foo").finish() + } + } + + assert_eq!("Foo", format!("{:?}", Foo)); + assert_eq!("Foo", format!("{:#?}", Foo)); + } + + #[test] + fn test_single() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Foo") + .field("bar", &true) + .finish() + } + } + + assert_eq!("Foo { bar: true }", format!("{:?}", Foo)); + assert_eq!( +"Foo { + bar: true +}", + format!("{:#?}", Foo)); + } + + #[test] + fn test_multiple() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Foo") + .field("bar", &true) + .field("baz", &format_args!("{}/{}", 10i32, 20i32)) + .finish() + } + } + + assert_eq!("Foo { bar: true, baz: 10/20 }", format!("{:?}", Foo)); + assert_eq!( +"Foo { + bar: true, + baz: 10/20 +}", + format!("{:#?}", Foo)); + } + + #[test] + fn test_nested() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Foo") + .field("bar", &true) + .field("baz", &format_args!("{}/{}", 10i32, 20i32)) + .finish() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("Bar") + .field("foo", &Foo) + .field("hello", &"world") + .finish() + } + } + + assert_eq!("Bar { foo: Foo { bar: true, baz: 10/20 }, hello: \"world\" }", + format!("{:?}", Bar)); + assert_eq!( +"Bar { + foo: Foo { + bar: true, + baz: 10/20 + }, + hello: \"world\" +}", + format!("{:#?}", Bar)); + } +} + +mod debug_tuple { + use std::fmt; + + #[test] + fn test_empty() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_tuple("Foo").finish() + } + } + + assert_eq!("Foo", format!("{:?}", Foo)); + assert_eq!("Foo", format!("{:#?}", Foo)); + } + + #[test] + fn test_single() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_tuple("Foo") + .field(&true) + .finish() + } + } + + assert_eq!("Foo(true)", format!("{:?}", Foo)); + assert_eq!( +"Foo( + true +)", + format!("{:#?}", Foo)); + } + + #[test] + fn test_multiple() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_tuple("Foo") + .field(&true) + .field(&format_args!("{}/{}", 10i32, 20i32)) + .finish() + } + } + + assert_eq!("Foo(true, 10/20)", format!("{:?}", Foo)); + assert_eq!( +"Foo( + true, + 10/20 +)", + format!("{:#?}", Foo)); + } + + #[test] + fn test_nested() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_tuple("Foo") + .field(&true) + .field(&format_args!("{}/{}", 10i32, 20i32)) + .finish() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_tuple("Bar") + .field(&Foo) + .field(&"world") + .finish() + } + } + + assert_eq!("Bar(Foo(true, 10/20), \"world\")", + format!("{:?}", Bar)); + assert_eq!( +"Bar( + Foo( + true, + 10/20 + ), + \"world\" +)", + format!("{:#?}", Bar)); + } +} + +mod debug_map { + use std::fmt; + + #[test] + fn test_empty() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_map("Foo").finish() + } + } + + assert_eq!("Foo {}", format!("{:?}", Foo)); + assert_eq!("Foo {}", format!("{:#?}", Foo)); + } + + #[test] + fn test_single() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_map("Foo") + .entry(&"bar", &true) + .finish() + } + } + + assert_eq!("Foo { \"bar\": true }", format!("{:?}", Foo)); + assert_eq!( +"Foo { + \"bar\": true +}", + format!("{:#?}", Foo)); + } + + #[test] + fn test_multiple() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_map("Foo") + .entry(&"bar", &true) + .entry(&10i32, &format_args!("{}/{}", 10i32, 20i32)) + .finish() + } + } + + assert_eq!("Foo { \"bar\": true, 10: 10/20 }", format!("{:?}", Foo)); + assert_eq!( +"Foo { + \"bar\": true, + 10: 10/20 +}", + format!("{:#?}", Foo)); + } + + #[test] + fn test_nested() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_map("Foo") + .entry(&"bar", &true) + .entry(&10i32, &format_args!("{}/{}", 10i32, 20i32)) + .finish() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_map("Bar") + .entry(&"foo", &Foo) + .entry(&Foo, &"world") + .finish() + } + } + + assert_eq!("Bar { \"foo\": Foo { \"bar\": true, 10: 10/20 }, \ + Foo { \"bar\": true, 10: 10/20 }: \"world\" }", + format!("{:?}", Bar)); + assert_eq!( +"Bar { + \"foo\": Foo { + \"bar\": true, + 10: 10/20 + }, + Foo { + \"bar\": true, + 10: 10/20 + }: \"world\" +}", + format!("{:#?}", Bar)); + } +} + +mod debug_set { + use std::fmt; + + #[test] + fn test_empty() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_set("Foo").finish() + } + } + + assert_eq!("Foo {}", format!("{:?}", Foo)); + assert_eq!("Foo {}", format!("{:#?}", Foo)); + } + + #[test] + fn test_single() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_set("Foo") + .entry(&true) + .finish() + } + } + + assert_eq!("Foo { true }", format!("{:?}", Foo)); + assert_eq!( +"Foo { + true +}", + format!("{:#?}", Foo)); + } + + #[test] + fn test_multiple() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_set("Foo") + .entry(&true) + .entry(&format_args!("{}/{}", 10i32, 20i32)) + .finish() + } + } + + assert_eq!("Foo { true, 10/20 }", format!("{:?}", Foo)); + assert_eq!( +"Foo { + true, + 10/20 +}", + format!("{:#?}", Foo)); + } + + #[test] + fn test_nested() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_set("Foo") + .entry(&true) + .entry(&format_args!("{}/{}", 10i32, 20i32)) + .finish() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_set("Bar") + .entry(&Foo) + .entry(&"world") + .finish() + } + } + + assert_eq!("Bar { Foo { true, 10/20 }, \"world\" }", + format!("{:?}", Bar)); + assert_eq!( +"Bar { + Foo { + true, + 10/20 + }, + \"world\" +}", + format!("{:#?}", Bar)); + } +} diff --git a/src/libcoretest/fmt/mod.rs b/src/libcoretest/fmt/mod.rs index e779201444681..cdb9c38f027f7 100644 --- a/src/libcoretest/fmt/mod.rs +++ b/src/libcoretest/fmt/mod.rs @@ -9,6 +9,7 @@ // except according to those terms. mod num; +mod builders; #[test] fn test_format_flags() { From 8121cf077c68fa1d18a1a538deb5acdf79c5e732 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 6 Mar 2015 21:46:30 -0800 Subject: [PATCH 2/6] Restructure debug builders to minimize codegen Switching from generic bounds to trait objects and having un-inlined inner methods should cut down on the size of Debug impls, since we care about the speed of a Debug implementation way less than binary bloat. --- src/libcore/fmt/builders.rs | 76 ++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index e7b4cd1122cd0..d96da4cafb068 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -63,8 +63,13 @@ pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) 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(mut self, name: &str, value: &S) -> DebugStruct<'a, 'b> - where S: fmt::Debug { + #[inline] + pub fn field(mut self, name: &str, value: &fmt::Debug) -> DebugStruct<'a, 'b> { + self.field_inner(name, value); + self + } + + fn field_inner(&mut self, name: &str, value: &fmt::Debug) { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { "," @@ -81,13 +86,18 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { }); self.has_fields = true; - self } /// Consumes the `DebugStruct`, finishing output and returning any error /// encountered. #[unstable(feature = "core", reason = "method was just created")] + #[inline] pub fn finish(mut self) -> fmt::Result { + self.finish_inner(); + self.result + } + + fn finish_inner(&mut self) { if self.has_fields { self.result = self.result.and_then(|_| { if self.is_pretty() { @@ -97,7 +107,6 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { } }); } - self.result } fn is_pretty(&self) -> bool { @@ -127,7 +136,13 @@ pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> D 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(mut self, value: &S) -> DebugTuple<'a, 'b> where S: fmt::Debug { + #[inline] + pub fn field(mut self, value: &fmt::Debug) -> DebugTuple<'a, 'b> { + self.field_inner(value); + self + } + + fn field_inner(&mut self, value: &fmt::Debug) { self.result = self.result.and_then(|_| { let (prefix, space) = if self.has_fields { (",", " ") @@ -144,13 +159,18 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { }); self.has_fields = true; - self } /// Consumes the `DebugTuple`, finishing output and returning any error /// encountered. #[unstable(feature = "core", reason = "method was just created")] + #[inline] pub fn finish(mut self) -> fmt::Result { + self.finish_inner(); + self.result + } + + fn finish_inner(&mut self) { if self.has_fields { self.result = self.result.and_then(|_| { if self.is_pretty() { @@ -160,7 +180,6 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { } }); } - self.result } fn is_pretty(&self) -> bool { @@ -190,7 +209,13 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> Deb 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(mut self, entry: &S) -> DebugSet<'a, 'b> where S: fmt::Debug { + #[inline] + pub fn entry(mut self, entry: &fmt::Debug) -> DebugSet<'a, 'b> { + self.entry_inner(entry); + self + } + + fn entry_inner(&mut self, entry: &fmt::Debug) { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { "," @@ -207,21 +232,26 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { }); 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(|_| { + #[inline] + pub fn finish(mut self) -> fmt::Result { + self.finish_inner(); + self.result + } + + fn finish_inner(&mut self) { + self.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 { @@ -251,8 +281,13 @@ pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> Deb 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(mut self, key: &K, value: &V) -> DebugMap<'a, 'b> - where K: fmt::Debug, V: fmt::Debug { + #[inline] + pub fn entry(mut self, key: &fmt::Debug, value: &fmt::Debug) -> DebugMap<'a, 'b> { + self.entry_inner(key, value); + self + } + + fn entry_inner(&mut self, key: &fmt::Debug, value: &fmt::Debug) { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { "," @@ -269,21 +304,26 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { }); 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(|_| { + #[inline] + pub fn finish(mut self) -> fmt::Result { + self.finish_inner(); + self.result + } + + fn finish_inner(&mut self) { + self.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 { From bd6ed22fdf3df4e47d418487320a47d308c4477e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 7 Mar 2015 19:36:36 -0800 Subject: [PATCH 3/6] Switch derive(Debug) to use the debug builders --- src/libcore/fmt/builders.rs | 18 +++++ src/libcore/fmt/mod.rs | 6 +- src/libcoretest/fmt/builders.rs | 10 +++ src/libsyntax/ext/deriving/show.rs | 102 +++++++++++------------------ src/libsyntax/ext/expand.rs | 2 +- 5 files changed, 74 insertions(+), 64 deletions(-) diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index d96da4cafb068..37165cdc5ede3 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -1,3 +1,13 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use prelude::*; use fmt::{self, Write, FlagV1}; @@ -69,6 +79,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { self } + #[inline(never)] fn field_inner(&mut self, name: &str, value: &fmt::Debug) { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { @@ -97,6 +108,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { self.result } + #[inline(never)] fn finish_inner(&mut self) { if self.has_fields { self.result = self.result.and_then(|_| { @@ -142,6 +154,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { self } + #[inline(never)] fn field_inner(&mut self, value: &fmt::Debug) { self.result = self.result.and_then(|_| { let (prefix, space) = if self.has_fields { @@ -170,6 +183,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { self.result } + #[inline(never)] fn finish_inner(&mut self) { if self.has_fields { self.result = self.result.and_then(|_| { @@ -215,6 +229,7 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { self } + #[inline(never)] fn entry_inner(&mut self, entry: &fmt::Debug) { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { @@ -243,6 +258,7 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { self.result } + #[inline(never)] fn finish_inner(&mut self) { self.result = self.result.and_then(|_| { let end = match (self.has_fields, self.is_pretty()) { @@ -287,6 +303,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { self } + #[inline(never)] fn entry_inner(&mut self, key: &fmt::Debug, value: &fmt::Debug) { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { @@ -315,6 +332,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { self.result } + #[inline(never)] fn finish_inner(&mut self) { self.result = self.result.and_then(|_| { let end = match (self.has_fields, self.is_pretty()) { diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 572d613f192ad..741cf7b47fa1e 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -644,6 +644,7 @@ impl<'a> Formatter<'a> { /// 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) } @@ -671,6 +672,7 @@ impl<'a> Formatter<'a> { /// 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) } @@ -699,6 +701,7 @@ impl<'a> Formatter<'a> { /// 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) } @@ -724,9 +727,10 @@ impl<'a> Formatter<'a> { /// } /// /// // prints "Foo { "A": 10, "B": 11 }" - /// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 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) } diff --git a/src/libcoretest/fmt/builders.rs b/src/libcoretest/fmt/builders.rs index 84076b349d2f7..b2fbc90be5914 100644 --- a/src/libcoretest/fmt/builders.rs +++ b/src/libcoretest/fmt/builders.rs @@ -1,3 +1,13 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + mod debug_struct { use std::fmt; diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs index ce89c541fd44b..ae9a402006095 100644 --- a/src/libsyntax/ext/deriving/show.rs +++ b/src/libsyntax/ext/deriving/show.rs @@ -11,7 +11,6 @@ use ast; use ast::{MetaItem, Item, Expr,}; use codemap::Span; -use ext::format; use ext::base::ExtCtxt; use ext::build::AstBuilder; use ext::deriving::generic::*; @@ -19,8 +18,6 @@ use ext::deriving::generic::ty::*; use parse::token; use ptr::P; -use std::collections::HashMap; - pub fn expand_deriving_show(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, @@ -56,14 +53,12 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt, trait_def.expand(cx, mitem, item, push) } -/// We construct a format string and then defer to std::fmt, since that -/// knows what's up with formatting and so on. +/// We use the debug builders to do the heavy lifting here fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - // build ``, `({}, {}, ...)` or ` { : {}, - // : {}, ... }` based on the "shape". - // - // Easy start: they all start with the name. + // build fmt.debug_struct().field(, &)....build() + // or fmt.debug_tuple().field(&)....build() + // based on the "shape". let name = match *substr.fields { Struct(_) => substr.type_ident, EnumMatching(_, v, _) => v.node.name, @@ -72,70 +67,53 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, } }; - let mut format_string = String::from_str(&token::get_ident(name)); - // the internal fields we're actually formatting - let mut exprs = Vec::new(); + // We want to make sure we have the expn_id set so that we can use unstable methods + let span = Span { expn_id: cx.backtrace(), .. span }; + let name = cx.expr_lit(span, ast::Lit_::LitStr(token::get_ident(name), + ast::StrStyle::CookedStr)); + let mut expr = substr.nonself_args[0].clone(); - // Getting harder... making the format string: match *substr.fields { - // unit struct/nullary variant: no work necessary! - Struct(ref fields) if fields.len() == 0 => {} - EnumMatching(_, _, ref fields) if fields.len() == 0 => {} - Struct(ref fields) | EnumMatching(_, _, ref fields) => { - if fields[0].name.is_none() { + if fields.is_empty() || fields[0].name.is_none() { // tuple struct/"normal" variant - - format_string.push_str("("); - - for (i, field) in fields.iter().enumerate() { - if i != 0 { format_string.push_str(", "); } - - format_string.push_str("{:?}"); - - exprs.push(field.self_.clone()); + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("debug_tuple"), + vec![name]); + + for field in fields { + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("field"), + vec![cx.expr_addr_of(field.span, + field.self_.clone())]); } - - format_string.push_str(")"); } else { // normal struct/struct variant - - format_string.push_str(" {{"); - - for (i, field) in fields.iter().enumerate() { - if i != 0 { format_string.push_str(","); } - - let name = token::get_ident(field.name.unwrap()); - format_string.push_str(" "); - format_string.push_str(&name); - format_string.push_str(": {:?}"); - - exprs.push(field.self_.clone()); + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("debug_struct"), + vec![name]); + + for field in fields { + let name = cx.expr_lit(field.span, ast::Lit_::LitStr( + token::get_ident(field.name.clone().unwrap()), + ast::StrStyle::CookedStr)); + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("field"), + vec![name, + cx.expr_addr_of(field.span, + field.self_.clone())]); } - - format_string.push_str(" }}"); } } _ => unreachable!() } - // AST construction! - // we're basically calling - // - // format_arg_method!(fmt, write_fmt, "", exprs...) - // - // but doing it directly via ext::format. - let formatter = substr.nonself_args[0].clone(); - - let meth = cx.ident_of("write_fmt"); - let s = token::intern_and_get_ident(&format_string[..]); - let format_string = cx.expr_str(span, s); - - // phew, not our responsibility any more! - - let args = vec![ - format::expand_preparsed_format_args(cx, span, format_string, - exprs, vec![], HashMap::new()) - ]; - cx.expr_method_call(span, formatter, meth, args) + cx.expr_method_call(span, + expr, + token::str_to_ident("finish"), + vec![]) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 98c7aefcd8ad3..6883395933ef1 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1121,7 +1121,7 @@ fn expand_annotatable(a: Annotatable, callee: NameAndSpan { name: mname.to_string(), format: MacroAttribute, - span: None, + span: Some(attr.span), // attributes can do whatever they like, // for now. allow_internal_unstable: true, From 3181213f912f7ce678f902bb01eb681204c41fc4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 10 Mar 2015 19:47:57 -0700 Subject: [PATCH 4/6] Fix unstable span checks --- src/libsyntax/codemap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 7d2d4e53fe9fd..70aab26092c44 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -848,7 +848,7 @@ impl CodeMap { let span_comes_from_this_expansion = info.callee.span.map_or(span == info.call_site, |mac_span| { - mac_span.lo <= span.lo && span.hi < mac_span.hi + mac_span.lo <= span.lo && span.hi <= mac_span.hi }); debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}", From 4181d43c4b05c55a53a6d52f94723bc58de0b7ab Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 10 Mar 2015 21:33:04 -0700 Subject: [PATCH 5/6] Remove inline silliness from debug builders Turns out it's basically a wash, codegen wise. --- src/libcore/fmt/builders.rs | 71 ++++++------------------------------- 1 file changed, 11 insertions(+), 60 deletions(-) diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 37165cdc5ede3..75afd4722675a 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -73,14 +73,7 @@ pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// Adds a new field to the generated struct output. #[unstable(feature = "core", reason = "method was just created")] - #[inline] pub fn field(mut self, name: &str, value: &fmt::Debug) -> DebugStruct<'a, 'b> { - self.field_inner(name, value); - self - } - - #[inline(never)] - fn field_inner(&mut self, name: &str, value: &fmt::Debug) { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { "," @@ -97,19 +90,13 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { }); self.has_fields = true; + self } /// Consumes the `DebugStruct`, finishing output and returning any error /// encountered. #[unstable(feature = "core", reason = "method was just created")] - #[inline] pub fn finish(mut self) -> fmt::Result { - self.finish_inner(); - self.result - } - - #[inline(never)] - fn finish_inner(&mut self) { if self.has_fields { self.result = self.result.and_then(|_| { if self.is_pretty() { @@ -119,6 +106,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { } }); } + self.result } fn is_pretty(&self) -> bool { @@ -148,14 +136,7 @@ pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> D 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")] - #[inline] pub fn field(mut self, value: &fmt::Debug) -> DebugTuple<'a, 'b> { - self.field_inner(value); - self - } - - #[inline(never)] - fn field_inner(&mut self, value: &fmt::Debug) { self.result = self.result.and_then(|_| { let (prefix, space) = if self.has_fields { (",", " ") @@ -172,19 +153,13 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { }); self.has_fields = true; + self } /// Consumes the `DebugTuple`, finishing output and returning any error /// encountered. #[unstable(feature = "core", reason = "method was just created")] - #[inline] pub fn finish(mut self) -> fmt::Result { - self.finish_inner(); - self.result - } - - #[inline(never)] - fn finish_inner(&mut self) { if self.has_fields { self.result = self.result.and_then(|_| { if self.is_pretty() { @@ -194,6 +169,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { } }); } + self.result } fn is_pretty(&self) -> bool { @@ -223,14 +199,7 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> Deb impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// Adds a new entry to the set output. #[unstable(feature = "core", reason = "method was just created")] - #[inline] pub fn entry(mut self, entry: &fmt::Debug) -> DebugSet<'a, 'b> { - self.entry_inner(entry); - self - } - - #[inline(never)] - fn entry_inner(&mut self, entry: &fmt::Debug) { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { "," @@ -247,27 +216,21 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { }); self.has_fields = true; + self } /// Consumes the `DebugSet`, finishing output and returning any error /// encountered. #[unstable(feature = "core", reason = "method was just created")] - #[inline] pub fn finish(mut self) -> fmt::Result { - self.finish_inner(); - self.result - } - - #[inline(never)] - fn finish_inner(&mut self) { - self.result = self.result.and_then(|_| { + 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 { @@ -297,14 +260,7 @@ pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> Deb impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// Adds a new entry to the map output. #[unstable(feature = "core", reason = "method was just created")] - #[inline] pub fn entry(mut self, key: &fmt::Debug, value: &fmt::Debug) -> DebugMap<'a, 'b> { - self.entry_inner(key, value); - self - } - - #[inline(never)] - fn entry_inner(&mut self, key: &fmt::Debug, value: &fmt::Debug) { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { "," @@ -321,27 +277,22 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { }); self.has_fields = true; + + self } /// Consumes the `DebugMap`, finishing output and returning any error /// encountered. #[unstable(feature = "core", reason = "method was just created")] - #[inline] pub fn finish(mut self) -> fmt::Result { - self.finish_inner(); - self.result - } - - #[inline(never)] - fn finish_inner(&mut self) { - self.result = self.result.and_then(|_| { + 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 { From 905a611b94d1fd50f15cd06f27cd44fd4dacb131 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 11 Mar 2015 12:58:01 -0700 Subject: [PATCH 6/6] Switch to a specific feature --- src/libcore/fmt/builders.rs | 20 ++++++++++---------- src/libcoretest/lib.rs | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 75afd4722675a..07f029cc15e2f 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -72,7 +72,7 @@ pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// Adds a new field to the generated struct output. - #[unstable(feature = "core", reason = "method was just created")] + #[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 { @@ -95,7 +95,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// Consumes the `DebugStruct`, finishing output and returning any error /// encountered. - #[unstable(feature = "core", reason = "method was just created")] + #[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(|_| { @@ -135,7 +135,7 @@ pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> D 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")] + #[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 { @@ -158,7 +158,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { /// Consumes the `DebugTuple`, finishing output and returning any error /// encountered. - #[unstable(feature = "core", reason = "method was just created")] + #[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(|_| { @@ -198,7 +198,7 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> Deb impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// Adds a new entry to the set output. - #[unstable(feature = "core", reason = "method was just created")] + #[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 { @@ -221,8 +221,8 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// Consumes the `DebugSet`, finishing output and returning any error /// encountered. - #[unstable(feature = "core", reason = "method was just created")] - pub fn finish(mut self) -> fmt::Result { + #[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, _) => "}", @@ -259,7 +259,7 @@ pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> Deb impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// Adds a new entry to the map output. - #[unstable(feature = "core", reason = "method was just created")] + #[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 { @@ -283,8 +283,8 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// Consumes the `DebugMap`, finishing output and returning any error /// encountered. - #[unstable(feature = "core", reason = "method was just created")] - pub fn finish(mut self) -> fmt::Result { + #[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, _) => "}", diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 1dbbb845d46e0..536bce0d05f0b 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -23,6 +23,7 @@ #![feature(hash)] #![feature(io)] #![feature(collections)] +#![feature(debug_builders)] #![allow(deprecated)] // rand extern crate core;