From bd6ed22fdf3df4e47d418487320a47d308c4477e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 7 Mar 2015 19:36:36 -0800 Subject: [PATCH] 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 | 98 ++++++++++++------------------ src/libsyntax/ext/expand.rs | 2 +- 5 files changed, 72 insertions(+), 62 deletions(-) diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index d96da4cafb06..37165cdc5ede 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 572d613f192a..741cf7b47fa1 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 84076b349d2f..b2fbc90be591 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 ce89c541fd44..ae9a40200609 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 + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("debug_tuple"), + vec![name]); - 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()); + 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 + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("debug_struct"), + vec![name]); - 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()); + 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 98c7aefcd8ad..6883395933ef 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,