From 2e808a1842175bdaa557ca65623d8e8b72f2e603 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Sun, 5 Jan 2025 11:59:57 +0100 Subject: [PATCH 1/4] Print array fields separate instead of as array. --- src/generate/fieldset.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/generate/fieldset.rs b/src/generate/fieldset.rs index 891a7e3..bc7c138 100644 --- a/src/generate/fieldset.rs +++ b/src/generate/fieldset.rs @@ -68,14 +68,17 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu } } - field_names.push(name.clone()); - field_names_str.push(f.name.as_str()); if let Some(array) = &f.array { - let len = array.len(); - let i = 0..len; - field_types.push(quote!([#field_ty; #len])); - field_getters.push(quote!([#( self.#name(#i), )*])); + for i in 0..array.len() { + let debug_name = format!("{}{i}", f.name); + field_names.push(proc_macro2::Ident::new(&debug_name, span)); + field_names_str.push(debug_name); + field_types.push(field_ty.clone()); + field_getters.push(quote!(self.#name(#i))); + } } else { + field_names.push(name.clone()); + field_names_str.push(f.name.clone()); field_types.push(field_ty.clone()); field_getters.push(quote!(self.#name())); } From db76534bd8c7ae9f678f5b566e5731ad830377bd Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Sun, 5 Jan 2025 22:11:18 +0100 Subject: [PATCH 2/4] Use original field names for array elements in Debug and defmt impls. --- src/generate/fieldset.rs | 21 +++++++++++++++------ src/ir.rs | 3 +++ src/svd2ir.rs | 1 + src/transform/fix_register_bit_sizes.rs | 1 + src/transform/make_field_array.rs | 2 ++ 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/generate/fieldset.rs b/src/generate/fieldset.rs index bc7c138..eed39e9 100644 --- a/src/generate/fieldset.rs +++ b/src/generate/fieldset.rs @@ -69,12 +69,21 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu } if let Some(array) = &f.array { - for i in 0..array.len() { - let debug_name = format!("{}{i}", f.name); - field_names.push(proc_macro2::Ident::new(&debug_name, span)); - field_names_str.push(debug_name); - field_types.push(field_ty.clone()); - field_getters.push(quote!(self.#name(#i))); + if !f.array_names.is_empty() { + for (i, field_name) in f.array_names.iter().enumerate() { + field_names.push(proc_macro2::Ident::new(&field_name, span)); + field_names_str.push(field_name.clone()); + field_types.push(field_ty.clone()); + field_getters.push(quote!(self.#name(#i))); + } + } else { + for i in 0..array.len() { + let debug_name = format!("{}{i}", f.name); + field_names.push(proc_macro2::Ident::new(&debug_name, span)); + field_names_str.push(debug_name); + field_types.push(field_ty.clone()); + field_getters.push(quote!(self.#name(#i))); + } } } else { field_names.push(name.clone()); diff --git a/src/ir.rs b/src/ir.rs index f696328..9fed051 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -215,6 +215,9 @@ pub struct Field { pub bit_size: u32, #[serde(default, skip_serializing_if = "Option::is_none")] pub array: Option, + /// The names of the individual array elements. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub array_names: Vec, #[serde(default, skip_serializing_if = "Option::is_none", rename = "enum")] pub enumm: Option, } diff --git a/src/svd2ir.rs b/src/svd2ir.rs index 61afdae..fd056c6 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -278,6 +278,7 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() bit_offset: BitOffset::Regular(f.bit_range.offset), bit_size: f.bit_range.width, array: None, + array_names: Vec::new(), enumm: None, }; diff --git a/src/transform/fix_register_bit_sizes.rs b/src/transform/fix_register_bit_sizes.rs index d43c649..7e5ebcd 100644 --- a/src/transform/fix_register_bit_sizes.rs +++ b/src/transform/fix_register_bit_sizes.rs @@ -36,6 +36,7 @@ impl FixRegisterBitSizes { description: None, enumm: None, array: None, + array_names: Vec::new(), }], description: None, extends: None, diff --git a/src/transform/make_field_array.rs b/src/transform/make_field_array.rs index f36e0d3..da5792a 100644 --- a/src/transform/make_field_array.rs +++ b/src/transform/make_field_array.rs @@ -62,6 +62,7 @@ impl MakeFieldArray { self.mode, )?; + let item_names = items.iter().map(|x| x.name.clone()).collect(); let mut item = items[0].clone(); // Remove all @@ -70,6 +71,7 @@ impl MakeFieldArray { // Create the new array item item.name = to; item.array = Some(array); + item.array_names = item_names; item.bit_offset = BitOffset::Regular(offset); b.fields.push(item); } From 663174dc6128ac320ed32fec2fdd26caeabd5781 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 8 Jan 2025 11:45:42 +0100 Subject: [PATCH 3/4] Use either original field name or array index in Debug/Format impls. --- src/generate/fieldset.rs | 69 ++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/src/generate/fieldset.rs b/src/generate/fieldset.rs index eed39e9..5449f1d 100644 --- a/src/generate/fieldset.rs +++ b/src/generate/fieldset.rs @@ -1,6 +1,6 @@ use anyhow::Result; use proc_macro2::TokenStream; -use proc_macro2::{Ident, Literal, Span}; +use proc_macro2::{Ident, Span}; use quote::quote; use crate::ir::*; @@ -12,7 +12,6 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu let span = Span::call_site(); let mut items = TokenStream::new(); let mut field_names = Vec::with_capacity(fs.fields.len()); - let mut field_names_str = Vec::with_capacity(fs.fields.len()); let mut field_getters = Vec::with_capacity(fs.fields.len()); let mut field_types = Vec::with_capacity(fs.fields.len()); @@ -69,25 +68,24 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu } if let Some(array) = &f.array { + // If the original field names are available, use them for the Debug/defmt::Format impls. if !f.array_names.is_empty() { for (i, field_name) in f.array_names.iter().enumerate() { - field_names.push(proc_macro2::Ident::new(&field_name, span)); - field_names_str.push(field_name.clone()); + field_names.push(field_name.clone()); field_types.push(field_ty.clone()); field_getters.push(quote!(self.#name(#i))); } + // Otherwise use array indexing in field names: "field[0]" } else { for i in 0..array.len() { - let debug_name = format!("{}{i}", f.name); - field_names.push(proc_macro2::Ident::new(&debug_name, span)); - field_names_str.push(debug_name); + let debug_name = format!("{}[{i}]", f.name); + field_names.push(debug_name); field_types.push(field_ty.clone()); field_getters.push(quote!(self.#name(#i))); } } } else { - field_names.push(name.clone()); - field_names_str.push(f.name.clone()); + field_names.push(f.name.clone()); field_types.push(field_ty.clone()); field_getters.push(quote!(self.#name())); } @@ -193,31 +191,37 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu } let (_, name) = super::split_path(path); - let name_str = { - let mut literal = Literal::string(name); - literal.set_span(span); - literal - }; + let name_str = name; let name = Ident::new(name, span); let doc = util::doc(&fs.description); let impl_defmt_format = opts.defmt_feature.as_ref().map(|defmt_feature| { + let mut defmt_format_string = String::new(); + defmt_format_string.push_str(name_str); + defmt_format_string.push_str(" {{"); + for (i, (field_name, field_type)) in field_names.iter().zip(&field_types).enumerate() { + if i > 0 { + defmt_format_string.push_str(", "); + } else { + defmt_format_string.push_str(" "); + } + defmt_format_string.push_str(field_name); + + if is_defmt_primitive_type(field_type) { + defmt_format_string.push_str(": {="); + defmt_format_string.push_str(&field_type.to_string()); + defmt_format_string.push_str(":?}"); + } else { + defmt_format_string.push_str(": {:?}"); + } + } + defmt_format_string.push_str(" }}"); + quote! { #[cfg(feature = #defmt_feature)] impl defmt::Format for #name { fn format(&self, f: defmt::Formatter) { - #[derive(defmt::Format)] - struct #name { - #( - #field_names: #field_types, - )* - } - let proxy = #name { - #( - #field_names: #field_getters, - )* - }; - defmt::write!(f, "{}", proxy) + defmt::write!(f, #defmt_format_string, #(#field_getters),*) } } } @@ -244,7 +248,7 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_struct(#name_str) #( - .field(#field_names_str, &#field_getters) + .field(#field_names, &#field_getters) )* .finish() } @@ -255,3 +259,14 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu Ok(out) } + +fn is_defmt_primitive_type(ty: &TokenStream) -> bool { + // Supported by defmt but not included: [u8; N], [u8] and str. + // Parsing these types is more complicated, so we skip them. + // They should never occur as the field of a fieldset, + // so this should not be a problem. + let primitives = [ + "bool", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "u128", "i128", "f32", "f64", + ]; + primitives.as_slice().contains(&ty.to_string().as_str()) +} From 34fc0dc9a20c0794032c4c4b4221c331839cdbd0 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Mon, 17 Feb 2025 13:13:49 +0100 Subject: [PATCH 4/4] Remove original array field names. --- src/generate/fieldset.rs | 21 ++++++--------------- src/ir.rs | 3 --- src/svd2ir.rs | 1 - src/transform/fix_register_bit_sizes.rs | 1 - src/transform/make_field_array.rs | 2 -- 5 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/generate/fieldset.rs b/src/generate/fieldset.rs index 5449f1d..02cca52 100644 --- a/src/generate/fieldset.rs +++ b/src/generate/fieldset.rs @@ -68,21 +68,12 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu } if let Some(array) = &f.array { - // If the original field names are available, use them for the Debug/defmt::Format impls. - if !f.array_names.is_empty() { - for (i, field_name) in f.array_names.iter().enumerate() { - field_names.push(field_name.clone()); - field_types.push(field_ty.clone()); - field_getters.push(quote!(self.#name(#i))); - } - // Otherwise use array indexing in field names: "field[0]" - } else { - for i in 0..array.len() { - let debug_name = format!("{}[{i}]", f.name); - field_names.push(debug_name); - field_types.push(field_ty.clone()); - field_getters.push(quote!(self.#name(#i))); - } + // Print array fields using array indexing: "field[0]" + for i in 0..array.len() { + let debug_name = format!("{}[{i}]", f.name); + field_names.push(debug_name); + field_types.push(field_ty.clone()); + field_getters.push(quote!(self.#name(#i))); } } else { field_names.push(f.name.clone()); diff --git a/src/ir.rs b/src/ir.rs index 9fed051..f696328 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -215,9 +215,6 @@ pub struct Field { pub bit_size: u32, #[serde(default, skip_serializing_if = "Option::is_none")] pub array: Option, - /// The names of the individual array elements. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub array_names: Vec, #[serde(default, skip_serializing_if = "Option::is_none", rename = "enum")] pub enumm: Option, } diff --git a/src/svd2ir.rs b/src/svd2ir.rs index fd056c6..61afdae 100644 --- a/src/svd2ir.rs +++ b/src/svd2ir.rs @@ -278,7 +278,6 @@ pub fn convert_peripheral(ir: &mut IR, p: &svd::Peripheral) -> anyhow::Result<() bit_offset: BitOffset::Regular(f.bit_range.offset), bit_size: f.bit_range.width, array: None, - array_names: Vec::new(), enumm: None, }; diff --git a/src/transform/fix_register_bit_sizes.rs b/src/transform/fix_register_bit_sizes.rs index 7e5ebcd..d43c649 100644 --- a/src/transform/fix_register_bit_sizes.rs +++ b/src/transform/fix_register_bit_sizes.rs @@ -36,7 +36,6 @@ impl FixRegisterBitSizes { description: None, enumm: None, array: None, - array_names: Vec::new(), }], description: None, extends: None, diff --git a/src/transform/make_field_array.rs b/src/transform/make_field_array.rs index da5792a..f36e0d3 100644 --- a/src/transform/make_field_array.rs +++ b/src/transform/make_field_array.rs @@ -62,7 +62,6 @@ impl MakeFieldArray { self.mode, )?; - let item_names = items.iter().map(|x| x.name.clone()).collect(); let mut item = items[0].clone(); // Remove all @@ -71,7 +70,6 @@ impl MakeFieldArray { // Create the new array item item.name = to; item.array = Some(array); - item.array_names = item_names; item.bit_offset = BitOffset::Regular(offset); b.fields.push(item); }