@@ -28,6 +28,7 @@ fn s_err(span: proc_macro2::Span, msg: impl fmt::Display) -> syn::Error {
28
28
/// - `from` to specify a conversion function from repr to the bitfield's integer type
29
29
/// - `into` to specify a conversion function from the bitfield's integer type to repr
30
30
/// - `debug` to disable the `Debug` trait generation
31
+ /// - `defmt` to enable the `defmt::Format` trait generation.
31
32
/// - `default` to disable the `Default` trait generation
32
33
/// - `order` to specify the bit order (Lsb, Msb)
33
34
/// - `conversion` to disable the generation of into_bits and from_bits
@@ -55,6 +56,7 @@ fn bitfield_inner(args: TokenStream, input: TokenStream) -> syn::Result<TokenStr
55
56
from,
56
57
bits,
57
58
debug,
59
+ defmt,
58
60
default,
59
61
order,
60
62
conversion,
@@ -104,20 +106,7 @@ fn bitfield_inner(args: TokenStream, input: TokenStream) -> syn::Result<TokenStr
104
106
) ) ;
105
107
}
106
108
107
- let debug_impl = if debug {
108
- let debug_fields = members. iter ( ) . map ( Member :: debug) ;
109
- quote ! {
110
- impl core:: fmt:: Debug for #name {
111
- fn fmt( & self , f: & mut core:: fmt:: Formatter <' _>) -> core:: fmt:: Result {
112
- f. debug_struct( stringify!( #name) )
113
- #( #debug_fields ) *
114
- . finish( )
115
- }
116
- }
117
- }
118
- } else {
119
- quote ! ( )
120
- } ;
109
+ let debug_impl = implement_debug ( debug, defmt, & name, & members) ;
121
110
122
111
let defaults = members. iter ( ) . map ( Member :: default) ;
123
112
@@ -183,6 +172,111 @@ fn bitfield_inner(args: TokenStream, input: TokenStream) -> syn::Result<TokenStr
183
172
} )
184
173
}
185
174
175
+ fn implement_debug ( debug : bool , defmt : bool , name : & syn:: Ident , members : & [ Member ] ) -> TokenStream {
176
+ let debug_impl = if debug {
177
+ let fields = members. iter ( ) . flat_map ( |m| {
178
+ let inner = m. inner . as_ref ( ) ?;
179
+
180
+ if inner. from . is_empty ( ) {
181
+ return None ;
182
+ }
183
+
184
+ let ident = & inner. ident ;
185
+ Some ( quote ! ( . field( stringify!( #ident) , & self . #ident( ) ) ) )
186
+ } ) ;
187
+
188
+ quote ! {
189
+ impl core:: fmt:: Debug for #name {
190
+ fn fmt( & self , f: & mut core:: fmt:: Formatter <' _>) -> core:: fmt:: Result {
191
+ f. debug_struct( stringify!( #name) )
192
+ #( #fields ) *
193
+ . finish( )
194
+ }
195
+ }
196
+ }
197
+ } else {
198
+ quote ! ( )
199
+ } ;
200
+
201
+ let defmt_impl = if defmt {
202
+ // build a part of the format string for each field
203
+ let formats = members. iter ( ) . flat_map ( |m| {
204
+ let inner = m. inner . as_ref ( ) ?;
205
+
206
+ if inner. from . is_empty ( ) {
207
+ return None ;
208
+ }
209
+
210
+ // default to using {:?}
211
+ let mut spec = "{:?}" . to_owned ( ) ;
212
+
213
+ // primitives supported by defmt
214
+ const PRIMITIVES : & [ & str ] = & [
215
+ "bool" , "usize" , "isize" , "u8" , "u16" , "u32" , "u64" , "u128" , "i8" , "i16" , "i32" ,
216
+ "i64" , "i128" , "f32" , "f64" ,
217
+ ] ;
218
+
219
+ // get the type name so we can use more efficient defmt formats
220
+ // if it's a primitive
221
+ if let syn:: Type :: Path ( syn:: TypePath { path, .. } ) = & inner. ty {
222
+ if let Some ( ident) = path. get_ident ( ) {
223
+ if PRIMITIVES . iter ( ) . any ( |s| ident == s) {
224
+ // defmt supports this primitive, use special spec
225
+ spec = format ! ( "{{={}}}" , ident) ;
226
+ }
227
+ }
228
+ }
229
+
230
+ let ident = & inner. ident ;
231
+ Some ( format ! ( "{ident}: {spec}" ) )
232
+ } ) ;
233
+
234
+ // find the corresponding format argument for each field
235
+ let args = members. iter ( ) . flat_map ( |m| {
236
+ let inner = m. inner . as_ref ( ) ?;
237
+
238
+ if inner. from . is_empty ( ) {
239
+ return None ;
240
+ }
241
+
242
+ let ident = & inner. ident ;
243
+ Some ( quote ! ( self . #ident( ) ) )
244
+ } ) ;
245
+
246
+ // build a string like "Foo { field_name: {:?}, ... }"
247
+ // four braces, two to escape *this* format, times two to escape
248
+ // the defmt::write! call below.
249
+ let format_string = format ! (
250
+ "{} {{{{ {} }}}} " ,
251
+ name,
252
+ formats. collect:: <Vec <_>>( ) . join( ", " )
253
+ ) ;
254
+
255
+ // note: we use defmt paths here, not ::defmt, because many crates
256
+ // in the embedded space will rename defmt (e.g. to defmt_03) in
257
+ // order to support multiple incompatible defmt versions.
258
+ //
259
+ // defmt itself avoids ::defmt for this reason. For more info, see:
260
+ // https://github.com/knurling-rs/defmt/pull/835
261
+
262
+ quote ! {
263
+ impl defmt:: Format for #name {
264
+ fn format( & self , f: defmt:: Formatter ) {
265
+ defmt:: write!( f, #format_string, #( #args, ) * )
266
+ }
267
+ }
268
+ }
269
+ } else {
270
+ quote ! ( )
271
+ } ;
272
+
273
+ quote ! (
274
+ #debug_impl
275
+
276
+ #defmt_impl
277
+ )
278
+ }
279
+
186
280
/// Represents a member where accessor functions should be generated for.
187
281
struct Member {
188
282
offset : usize ,
@@ -306,16 +400,6 @@ impl Member {
306
400
}
307
401
}
308
402
309
- fn debug ( & self ) -> TokenStream {
310
- if let Some ( inner) = & self . inner {
311
- if !inner. from . is_empty ( ) {
312
- let ident = & inner. ident ;
313
- return quote ! ( . field( stringify!( #ident) , & self . #ident( ) ) ) ;
314
- }
315
- }
316
- quote ! ( )
317
- }
318
-
319
403
fn default ( & self ) -> TokenStream {
320
404
let default = & self . default ;
321
405
@@ -686,6 +770,7 @@ struct Params {
686
770
from : Option < syn:: Path > ,
687
771
bits : usize ,
688
772
debug : bool ,
773
+ defmt : bool ,
689
774
default : bool ,
690
775
order : Order ,
691
776
conversion : bool ,
@@ -705,6 +790,7 @@ impl Parse for Params {
705
790
let mut from = None ;
706
791
let mut into = None ;
707
792
let mut debug = true ;
793
+ let mut defmt = false ;
708
794
let mut default = true ;
709
795
let mut order = Order :: Lsb ;
710
796
let mut conversion = true ;
@@ -726,6 +812,9 @@ impl Parse for Params {
726
812
"debug" => {
727
813
debug = syn:: LitBool :: parse ( input) ?. value ;
728
814
}
815
+ "defmt" => {
816
+ defmt = syn:: LitBool :: parse ( input) ?. value ;
817
+ }
729
818
"default" => {
730
819
default = syn:: LitBool :: parse ( input) ?. value ;
731
820
}
@@ -757,6 +846,7 @@ impl Parse for Params {
757
846
into,
758
847
bits,
759
848
debug,
849
+ defmt,
760
850
default,
761
851
order,
762
852
conversion,
@@ -800,11 +890,21 @@ mod test {
800
890
fn parse_args ( ) {
801
891
let args = quote ! ( u64 ) ;
802
892
let params = syn:: parse2 :: < Params > ( args) . unwrap ( ) ;
803
- assert ! ( params. bits == u64 :: BITS as usize && params. debug == true ) ;
893
+ assert_eq ! ( params. bits, u64 :: BITS as usize ) ;
894
+ assert_eq ! ( params. debug, true ) ;
895
+ assert_eq ! ( params. defmt, false ) ;
804
896
805
897
let args = quote ! ( u32 , debug = false ) ;
806
898
let params = syn:: parse2 :: < Params > ( args) . unwrap ( ) ;
807
- assert ! ( params. bits == u32 :: BITS as usize && params. debug == false ) ;
899
+ assert_eq ! ( params. bits, u32 :: BITS as usize ) ;
900
+ assert_eq ! ( params. debug, false ) ;
901
+ assert_eq ! ( params. defmt, false ) ;
902
+
903
+ let args = quote ! ( u32 , defmt = true ) ;
904
+ let params = syn:: parse2 :: < Params > ( args) . unwrap ( ) ;
905
+ assert_eq ! ( params. bits, u32 :: BITS as usize ) ;
906
+ assert_eq ! ( params. debug, true ) ;
907
+ assert_eq ! ( params. defmt, true ) ;
808
908
809
909
let args = quote ! ( u32 , order = Msb ) ;
810
910
let params = syn:: parse2 :: < Params > ( args) . unwrap ( ) ;
0 commit comments