Skip to content

Commit 6aba681

Browse files
committed
Use either original field name or array index in Debug/Format impls.
1 parent dc79a0e commit 6aba681

File tree

1 file changed

+42
-27
lines changed

1 file changed

+42
-27
lines changed

src/generate/fieldset.rs

+42-27
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use anyhow::Result;
22
use proc_macro2::TokenStream;
3-
use proc_macro2::{Ident, Literal, Span};
3+
use proc_macro2::{Ident, Span};
44
use quote::quote;
55

66
use crate::ir::*;
@@ -12,7 +12,6 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
1212
let span = Span::call_site();
1313
let mut items = TokenStream::new();
1414
let mut field_names = Vec::with_capacity(fs.fields.len());
15-
let mut field_names_str = Vec::with_capacity(fs.fields.len());
1615
let mut field_getters = Vec::with_capacity(fs.fields.len());
1716
let mut field_types = Vec::with_capacity(fs.fields.len());
1817

@@ -69,25 +68,24 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
6968
}
7069

7170
if let Some(array) = &f.array {
71+
// If the original field names are available, use them for the Debug/defmt::Format impls.
7272
if !f.array_names.is_empty() {
7373
for (i, field_name) in f.array_names.iter().enumerate() {
74-
field_names.push(proc_macro2::Ident::new(&field_name, span));
75-
field_names_str.push(field_name.clone());
74+
field_names.push(field_name.clone());
7675
field_types.push(field_ty.clone());
7776
field_getters.push(quote!(self.#name(#i)));
7877
}
78+
// Otherwise use array indexing in field names: "field[0]"
7979
} else {
8080
for i in 0..array.len() {
81-
let debug_name = format!("{}{i}", f.name);
82-
field_names.push(proc_macro2::Ident::new(&debug_name, span));
83-
field_names_str.push(debug_name);
81+
let debug_name = format!("{}[{i}]", f.name);
82+
field_names.push(debug_name);
8483
field_types.push(field_ty.clone());
8584
field_getters.push(quote!(self.#name(#i)));
8685
}
8786
}
8887
} else {
89-
field_names.push(name.clone());
90-
field_names_str.push(f.name.clone());
88+
field_names.push(f.name.clone());
9189
field_types.push(field_ty.clone());
9290
field_getters.push(quote!(self.#name()));
9391
}
@@ -193,31 +191,37 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
193191
}
194192

195193
let (_, name) = super::split_path(path);
196-
let name_str = {
197-
let mut literal = Literal::string(name);
198-
literal.set_span(span);
199-
literal
200-
};
194+
let name_str = name;
201195
let name = Ident::new(name, span);
202196
let doc = util::doc(&fs.description);
203197

204198
let impl_defmt_format = opts.defmt_feature.as_ref().map(|defmt_feature| {
199+
let mut defmt_format_string = String::new();
200+
defmt_format_string.push_str(name_str);
201+
defmt_format_string.push_str(" {{");
202+
for (i, (field_name, field_type)) in field_names.iter().zip(&field_types).enumerate() {
203+
if i > 0 {
204+
defmt_format_string.push_str(", ");
205+
} else {
206+
defmt_format_string.push_str(" ");
207+
}
208+
defmt_format_string.push_str(field_name);
209+
210+
if is_defmt_primitive_type(field_type) {
211+
defmt_format_string.push_str(": {=");
212+
defmt_format_string.push_str(&field_type.to_string());
213+
defmt_format_string.push_str(":?}");
214+
} else {
215+
defmt_format_string.push_str(": {:?}");
216+
}
217+
}
218+
defmt_format_string.push_str(" }}");
219+
205220
quote! {
206221
#[cfg(feature = #defmt_feature)]
207222
impl defmt::Format for #name {
208223
fn format(&self, f: defmt::Formatter) {
209-
#[derive(defmt::Format)]
210-
struct #name {
211-
#(
212-
#field_names: #field_types,
213-
)*
214-
}
215-
let proxy = #name {
216-
#(
217-
#field_names: #field_getters,
218-
)*
219-
};
220-
defmt::write!(f, "{}", proxy)
224+
defmt::write!(f, #defmt_format_string, #(#field_getters),*)
221225
}
222226
}
223227
}
@@ -244,7 +248,7 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
244248
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
245249
f.debug_struct(#name_str)
246250
#(
247-
.field(#field_names_str, &#field_getters)
251+
.field(#field_names, &#field_getters)
248252
)*
249253
.finish()
250254
}
@@ -255,3 +259,14 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
255259

256260
Ok(out)
257261
}
262+
263+
fn is_defmt_primitive_type(ty: &TokenStream) -> bool {
264+
// Supported by defmt but not included: [u8; N], [u8] and str.
265+
// Parsing these types is more complicated, so we skip them.
266+
// They should never occur as the field of a fieldset,
267+
// so this should not be a problem.
268+
let primitives = [
269+
"bool", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "u128", "i128", "f32", "f64",
270+
];
271+
primitives.as_slice().contains(&ty.to_string().as_str())
272+
}

0 commit comments

Comments
 (0)