98
98
//! pub public: usize,
99
99
//! /// padding
100
100
//! #[bits(5)]
101
- //! _p : u8,
101
+ //! __ : u8,
102
102
//! }
103
103
//!
104
104
//! /// A custom enum
@@ -292,10 +292,11 @@ fn bitfield_inner(args: TokenStream, input: TokenStream) -> syn::Result<TokenStr
292
292
#vis struct #name( #ty) ;
293
293
294
294
impl #name {
295
- /// Creates a new zero initialized bitfield.
295
+ /// Creates a new default initialized bitfield.
296
296
#vis const fn new( ) -> Self {
297
- Self ( 0 )
297
+ let mut this = Self ( 0 ) ;
298
298
#( #defaults ) *
299
+ this
299
300
}
300
301
301
302
#( #members ) *
@@ -321,6 +322,7 @@ struct Member {
321
322
offset : usize ,
322
323
bits : usize ,
323
324
base_ty : syn:: Type ,
325
+ default : TokenStream ,
324
326
inner : Option < MemberInner > ,
325
327
}
326
328
@@ -329,7 +331,6 @@ struct MemberInner {
329
331
ty : syn:: Type ,
330
332
attrs : Vec < syn:: Attribute > ,
331
333
vis : syn:: Visibility ,
332
- default : TokenStream ,
333
334
into : TokenStream ,
334
335
from : TokenStream ,
335
336
}
@@ -352,42 +353,50 @@ impl Member {
352
353
let Field {
353
354
bits,
354
355
ty,
355
- class : _,
356
- default,
356
+ mut default,
357
357
into,
358
358
from,
359
359
} = parse_field ( & attrs, & ty, ignore) ?;
360
360
361
361
if bits > 0 && !ignore {
362
- if default . is_empty ( ) || into. is_empty ( ) || from. is_empty ( ) {
362
+ if into. is_empty ( ) || from. is_empty ( ) {
363
363
return Err ( syn:: Error :: new (
364
364
ty. span ( ) ,
365
365
"Custom types require 'into', and 'from' in the #[bits] attribute" ,
366
366
) ) ;
367
367
}
368
368
369
+ if default. is_empty ( ) {
370
+ default = quote ! ( #ty:: from_bits( 0 ) ) ;
371
+ }
372
+
369
373
// remove our attribute
370
374
attrs. retain ( |a| !a. path ( ) . is_ident ( "bits" ) ) ;
371
375
372
376
Ok ( Self {
373
377
offset,
374
378
bits,
375
379
base_ty,
380
+ default,
376
381
inner : Some ( MemberInner {
377
382
ident,
378
383
ty,
379
384
attrs,
380
385
vis,
381
- default,
382
386
into,
383
387
from,
384
388
} ) ,
385
389
} )
386
390
} else {
391
+ if default. is_empty ( ) {
392
+ default = quote ! ( 0 ) ;
393
+ }
394
+
387
395
Ok ( Self {
388
396
offset,
389
397
bits,
390
398
base_ty,
399
+ default,
391
400
inner : None ,
392
401
} )
393
402
}
@@ -399,18 +408,20 @@ impl Member {
399
408
let ident = & inner. ident ;
400
409
quote ! ( . field( #ident_str, & self . #ident( ) ) )
401
410
} else {
402
- Default :: default ( )
411
+ quote ! ( )
403
412
}
404
413
}
405
414
406
415
fn default ( & self ) -> TokenStream {
416
+ let default = & self . default ;
407
417
if let Some ( inner) = & self . inner {
408
418
let ident = & inner. ident ;
409
419
let with_ident = format_ident ! ( "with_{ident}" ) ;
410
- let default = & inner. default ;
411
- quote ! ( . #with_ident( #default ) )
420
+ quote ! ( this = this. #with_ident( #default ) ; )
412
421
} else {
413
- Default :: default ( )
422
+ let offset = self . offset ;
423
+ let base_ty = & self . base_ty ;
424
+ quote ! ( this. 0 |= ( #default as #base_ty) << #offset; )
414
425
}
415
426
}
416
427
}
@@ -421,7 +432,8 @@ impl ToTokens for Member {
421
432
offset,
422
433
bits,
423
434
base_ty,
424
- inner : Some ( MemberInner { ident, ty, attrs, vis, default : _, into, from } ) ,
435
+ default : _,
436
+ inner : Some ( MemberInner { ident, ty, attrs, vis, into, from } ) ,
425
437
} = self else {
426
438
return Default :: default ( ) ;
427
439
} ;
@@ -441,23 +453,12 @@ impl ToTokens for Member {
441
453
. map ( ToTokens :: to_token_stream)
442
454
. collect ( ) ;
443
455
444
- let general = quote ! {
445
- const #bits_ident: usize = #bits;
446
- const #offset_ident: usize = #offset;
447
-
448
- #doc
449
- #[ doc = #location]
450
- #vis fn #set_ident( & mut self , value: #ty) {
451
- * self = self . #with_ident( value) ;
452
- }
453
- } ;
454
-
455
- let bits = * bits as u32 ;
456
- let mask: u128 = !0 >> ( u128:: BITS - bits) ;
456
+ let mask: u128 = !0 >> ( u128:: BITS - * bits as u32 ) ;
457
457
let mask = syn:: LitInt :: new ( & format ! ( "0x{mask:x}" ) , Span :: mixed_site ( ) ) ;
458
458
459
459
let code = quote ! {
460
- #general
460
+ const #bits_ident: usize = #bits;
461
+ const #offset_ident: usize = #offset;
461
462
462
463
#doc
463
464
#[ doc = #location]
@@ -475,6 +476,12 @@ impl ToTokens for Member {
475
476
let this = ( self . 0 >> #offset) & #mask;
476
477
#from
477
478
}
479
+ #doc
480
+ #[ doc = #location]
481
+ #vis fn #set_ident( & mut self , value: #ty) {
482
+ * self = self . #with_ident( value) ;
483
+ }
484
+
478
485
} ;
479
486
tokens. extend ( code) ;
480
487
}
@@ -497,7 +504,6 @@ enum TypeClass {
497
504
struct Field {
498
505
bits : usize ,
499
506
ty : syn:: Type ,
500
- class : TypeClass ,
501
507
502
508
default : TokenStream ,
503
509
into : TokenStream ,
@@ -517,32 +523,28 @@ fn parse_field(attrs: &[syn::Attribute], ty: &syn::Type, ignore: bool) -> syn::R
517
523
TypeClass :: Bool => Field {
518
524
bits : ty_bits,
519
525
ty : ty. clone ( ) ,
520
- class,
521
526
default : quote ! ( false ) ,
522
527
into : quote ! ( this as _) ,
523
528
from : quote ! ( this != 0 ) ,
524
529
} ,
525
530
TypeClass :: SInt => Field {
526
531
bits : ty_bits,
527
532
ty : ty. clone ( ) ,
528
- class,
529
533
default : quote ! ( 0 ) ,
530
534
into : TokenStream :: new ( ) ,
531
535
from : TokenStream :: new ( ) ,
532
536
} ,
533
537
TypeClass :: UInt => Field {
534
538
bits : ty_bits,
535
539
ty : ty. clone ( ) ,
536
- class,
537
540
default : quote ! ( 0 ) ,
538
541
into : quote ! ( this as _) ,
539
542
from : quote ! ( this as _) ,
540
543
} ,
541
544
TypeClass :: Other => Field {
542
545
bits : ty_bits,
543
546
ty : ty. clone ( ) ,
544
- class,
545
- default : quote ! ( #ty:: from_bits( 0 ) ) ,
547
+ default : TokenStream :: new ( ) ,
546
548
into : quote ! ( #ty:: into_bits( this) ) ,
547
549
from : quote ! ( #ty:: from_bits( this) ) ,
548
550
} ,
@@ -572,10 +574,10 @@ fn parse_field(attrs: &[syn::Attribute], ty: &syn::Type, ignore: bool) -> syn::R
572
574
}
573
575
ret. bits = bits;
574
576
}
575
- if ignore && ( default . is_some ( ) || into. is_some ( ) || from. is_some ( ) ) {
577
+ if ignore && ( into. is_some ( ) || from. is_some ( ) ) {
576
578
return Err ( syn:: Error :: new (
577
579
default. span ( ) ,
578
- "'default', ' into', and 'from' are not (yet) supported on padding" ,
580
+ "'into' and 'from' are not supported on padding" ,
579
581
) ) ;
580
582
}
581
583
@@ -606,9 +608,9 @@ fn parse_field(attrs: &[syn::Attribute], ty: &syn::Type, ignore: bool) -> syn::R
606
608
}
607
609
608
610
// Negative integers need some special handling...
609
- if !ignore && ret . class == TypeClass :: SInt {
611
+ if !ignore && class == TypeClass :: SInt {
610
612
let bits = ret. bits as u32 ;
611
- let mask: u128 = !0 >> ( u128:: BITS - bits) ;
613
+ let mask: u128 = !0 >> ( u128:: BITS - ret . bits as u32 ) ;
612
614
let mask = syn:: LitInt :: new ( & format ! ( "0x{mask:x}" ) , Span :: mixed_site ( ) ) ;
613
615
if ret. into . is_empty ( ) {
614
616
// Bounds check and remove leading ones from negative values
@@ -659,7 +661,6 @@ impl Parse for BitsAttr {
659
661
660
662
<Token ! [ =] >:: parse ( input) ?;
661
663
662
-
663
664
if ident == "default" {
664
665
attr. default = Some ( input. parse ( ) ?) ;
665
666
} else if ident == "into" {
@@ -679,32 +680,6 @@ impl Parse for BitsAttr {
679
680
}
680
681
}
681
682
682
- /// Returns the number of bits for a given type
683
- fn type_bits ( ty : & syn:: Type ) -> ( TypeClass , usize ) {
684
- let syn:: Type :: Path ( syn:: TypePath { path, .. } ) = ty else {
685
- return ( TypeClass :: Other , 0 ) ;
686
- } ;
687
- let Some ( ident) = path. get_ident ( ) else {
688
- return ( TypeClass :: Other , 0 ) ;
689
- } ;
690
- if ident == "bool" {
691
- return ( TypeClass :: Bool , 1 ) ;
692
- }
693
- if ident == "isize" || ident == "usize" {
694
- return ( TypeClass :: UInt , 0 ) ; // they have architecture dependend sizes
695
- }
696
- macro_rules! integer {
697
- ( $ident: ident => $( $uint: ident) ,* ; $( $sint: ident) ,* ) => {
698
- match ident {
699
- $( _ if ident == stringify!( $uint) => ( TypeClass :: UInt , $uint:: BITS as _) , ) *
700
- $( _ if ident == stringify!( $sint) => ( TypeClass :: SInt , $sint:: BITS as _) , ) *
701
- _ => ( TypeClass :: Other , 0 )
702
- }
703
- } ;
704
- }
705
- integer ! ( ident => u8 , u16 , u32 , u64 , u128 ; i8 , i16 , i32 , i64 , i128 )
706
- }
707
-
708
683
/// The bitfield macro parameters
709
684
struct Params {
710
685
ty : syn:: Type ,
@@ -740,6 +715,32 @@ impl Parse for Params {
740
715
}
741
716
}
742
717
718
+ /// Returns the number of bits for a given type
719
+ fn type_bits ( ty : & syn:: Type ) -> ( TypeClass , usize ) {
720
+ let syn:: Type :: Path ( syn:: TypePath { path, .. } ) = ty else {
721
+ return ( TypeClass :: Other , 0 ) ;
722
+ } ;
723
+ let Some ( ident) = path. get_ident ( ) else {
724
+ return ( TypeClass :: Other , 0 ) ;
725
+ } ;
726
+ if ident == "bool" {
727
+ return ( TypeClass :: Bool , 1 ) ;
728
+ }
729
+ if ident == "isize" || ident == "usize" {
730
+ return ( TypeClass :: UInt , 0 ) ; // they have architecture dependend sizes
731
+ }
732
+ macro_rules! integer {
733
+ ( $ident: ident => $( $uint: ident) ,* ; $( $sint: ident) ,* ) => {
734
+ match ident {
735
+ $( _ if ident == stringify!( $uint) => ( TypeClass :: UInt , $uint:: BITS as _) , ) *
736
+ $( _ if ident == stringify!( $sint) => ( TypeClass :: SInt , $sint:: BITS as _) , ) *
737
+ _ => ( TypeClass :: Other , 0 )
738
+ }
739
+ } ;
740
+ }
741
+ integer ! ( ident => u8 , u16 , u32 , u64 , u128 ; i8 , i16 , i32 , i64 , i128 )
742
+ }
743
+
743
744
#[ cfg( test) ]
744
745
mod test {
745
746
use quote:: quote;
0 commit comments