sp_debug_derive/
impls.rs
1use proc_macro2::TokenStream;
19use quote::quote;
20use syn::{parse_quote, Data, DeriveInput};
21
22pub fn debug_derive(ast: DeriveInput) -> proc_macro::TokenStream {
23 let name_str = ast.ident.to_string();
24 let implementation = implementation::derive(&name_str, &ast.data);
25 let name = &ast.ident;
26 let mut generics = ast.generics.clone();
27 let (impl_generics, ty_generics, where_clause) = {
28 let wh = generics.make_where_clause();
29 for t in ast.generics.type_params() {
30 let name = &t.ident;
31 wh.predicates.push(parse_quote! { #name : core::fmt::Debug });
32 }
33 generics.split_for_impl()
34 };
35 let gen = quote! {
36 impl #impl_generics core::fmt::Debug for #name #ty_generics #where_clause {
37 fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
38 #implementation
39 }
40 }
41 };
42
43 gen.into()
44}
45
46#[cfg(all(not(feature = "std"), not(feature = "force-debug")))]
47mod implementation {
48 use super::*;
49
50 pub fn derive(_name_str: &str, _data: &Data) -> TokenStream {
55 quote! {
56 fmt.write_str("<wasm:stripped>")
57 }
58 }
59}
60
61#[cfg(any(feature = "std", feature = "force-debug"))]
62mod implementation {
63 use super::*;
64 use proc_macro2::Span;
65 use syn::{token::SelfValue, Ident, Index};
66
67 pub fn derive(name_str: &str, data: &Data) -> TokenStream {
69 match *data {
70 Data::Struct(ref s) => derive_struct(name_str, &s.fields),
71 Data::Union(ref u) => derive_fields(name_str, Fields::new(u.fields.named.iter(), None)),
72 Data::Enum(ref e) => derive_enum(name_str, e),
73 }
74 }
75
76 enum Fields {
77 Indexed { indices: Vec<Index> },
78 Unnamed { vars: Vec<Ident> },
79 Named { names: Vec<Ident>, this: Option<SelfValue> },
80 }
81
82 impl Fields {
83 fn new<'a>(fields: impl Iterator<Item = &'a syn::Field>, this: Option<SelfValue>) -> Self {
84 let mut indices = vec![];
85 let mut names = vec![];
86
87 for (i, f) in fields.enumerate() {
88 if let Some(ident) = f.ident.clone() {
89 names.push(ident);
90 } else {
91 indices.push(Index::from(i));
92 }
93 }
94
95 if names.is_empty() {
96 Self::Indexed { indices }
97 } else {
98 Self::Named { names, this }
99 }
100 }
101 }
102
103 fn derive_fields(name_str: &str, fields: Fields) -> TokenStream {
104 match fields {
105 Fields::Named { names, this } => {
106 let names_str: Vec<_> = names.iter().map(|x| x.to_string()).collect();
107
108 let fields = match this {
109 None => quote! { #( .field(#names_str, #names) )* },
110 Some(this) => quote! { #( .field(#names_str, &#this.#names) )* },
111 };
112
113 quote! {
114 fmt.debug_struct(#name_str)
115 #fields
116 .finish()
117 }
118 },
119 Fields::Indexed { indices } => {
120 quote! {
121 fmt.debug_tuple(#name_str)
122 #( .field(&self.#indices) )*
123 .finish()
124 }
125 },
126 Fields::Unnamed { vars } => {
127 quote! {
128 fmt.debug_tuple(#name_str)
129 #( .field(#vars) )*
130 .finish()
131 }
132 },
133 }
134 }
135
136 fn derive_enum(name: &str, e: &syn::DataEnum) -> TokenStream {
137 let v = e.variants.iter().map(|v| {
138 let name = format!("{}::{}", name, v.ident);
139 let ident = &v.ident;
140 match v.fields {
141 syn::Fields::Named(ref f) => {
142 let names: Vec<_> = f.named.iter().flat_map(|f| f.ident.clone()).collect();
143 let fields_impl =
144 derive_fields(&name, Fields::Named { names: names.clone(), this: None });
145 (ident, (quote! { { #( ref #names ),* } }, fields_impl))
146 },
147 syn::Fields::Unnamed(ref f) => {
148 let names = f
149 .unnamed
150 .iter()
151 .enumerate()
152 .map(|(id, _)| Ident::new(&format!("a{}", id), Span::call_site()))
153 .collect::<Vec<_>>();
154 let fields_impl = derive_fields(&name, Fields::Unnamed { vars: names.clone() });
155 (ident, (quote! { ( #( ref #names ),* ) }, fields_impl))
156 },
157 syn::Fields::Unit => {
158 let fields_impl = derive_fields(&name, Fields::Indexed { indices: vec![] });
159 (ident, (quote! {}, fields_impl))
160 },
161 }
162 });
163
164 type Vecs<A, B> = (Vec<A>, Vec<B>);
165 let (variants, others): Vecs<_, _> = v.unzip();
166 let (match_fields, variants_impl): Vecs<_, _> = others.into_iter().unzip();
167
168 quote! {
169 match self {
170 #( Self::#variants #match_fields => #variants_impl, )*
171 _ => Ok(()),
172 }
173 }
174 }
175
176 fn derive_struct(name_str: &str, fields: &syn::Fields) -> TokenStream {
177 match *fields {
178 syn::Fields::Named(ref f) => derive_fields(
179 name_str,
180 Fields::new(f.named.iter(), Some(syn::Token!(self)(Span::call_site()))),
181 ),
182 syn::Fields::Unnamed(ref f) =>
183 derive_fields(name_str, Fields::new(f.unnamed.iter(), None)),
184 syn::Fields::Unit => derive_fields(name_str, Fields::Indexed { indices: vec![] }),
185 }
186 }
187}