1
1
use anyhow:: Result ;
2
2
use proc_macro2:: TokenStream ;
3
- use proc_macro2:: { Ident , Literal , Span } ;
3
+ use proc_macro2:: { Ident , Span } ;
4
4
use quote:: quote;
5
5
6
6
use crate :: ir:: * ;
@@ -12,7 +12,6 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
12
12
let span = Span :: call_site ( ) ;
13
13
let mut items = TokenStream :: new ( ) ;
14
14
let mut field_names = Vec :: with_capacity ( fs. fields . len ( ) ) ;
15
- let mut field_names_str = Vec :: with_capacity ( fs. fields . len ( ) ) ;
16
15
let mut field_getters = Vec :: with_capacity ( fs. fields . len ( ) ) ;
17
16
let mut field_types = Vec :: with_capacity ( fs. fields . len ( ) ) ;
18
17
@@ -69,25 +68,24 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
69
68
}
70
69
71
70
if let Some ( array) = & f. array {
71
+ // If the original field names are available, use them for the Debug/defmt::Format impls.
72
72
if !f. array_names . is_empty ( ) {
73
73
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 ( ) ) ;
76
75
field_types. push ( field_ty. clone ( ) ) ;
77
76
field_getters. push ( quote ! ( self . #name( #i) ) ) ;
78
77
}
78
+ // Otherwise use array indexing in field names: "field[0]"
79
79
} else {
80
80
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) ;
84
83
field_types. push ( field_ty. clone ( ) ) ;
85
84
field_getters. push ( quote ! ( self . #name( #i) ) ) ;
86
85
}
87
86
}
88
87
} else {
89
- field_names. push ( name. clone ( ) ) ;
90
- field_names_str. push ( f. name . clone ( ) ) ;
88
+ field_names. push ( f. name . clone ( ) ) ;
91
89
field_types. push ( field_ty. clone ( ) ) ;
92
90
field_getters. push ( quote ! ( self . #name( ) ) ) ;
93
91
}
@@ -193,31 +191,37 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
193
191
}
194
192
195
193
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;
201
195
let name = Ident :: new ( name, span) ;
202
196
let doc = util:: doc ( & fs. description ) ;
203
197
204
198
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
+
205
220
quote ! {
206
221
#[ cfg( feature = #defmt_feature) ]
207
222
impl defmt:: Format for #name {
208
223
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) , * )
221
225
}
222
226
}
223
227
}
@@ -244,7 +248,7 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
244
248
fn fmt( & self , f: & mut core:: fmt:: Formatter ) -> core:: fmt:: Result {
245
249
f. debug_struct( #name_str)
246
250
#(
247
- . field( #field_names_str , & #field_getters)
251
+ . field( #field_names , & #field_getters)
248
252
) *
249
253
. finish( )
250
254
}
@@ -255,3 +259,14 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
255
259
256
260
Ok ( out)
257
261
}
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