ビットフィールドを構造体として指定できるビットフィールドの手続きマクロ。このライブラリは手続き上のマクロを提供するため、ランタイムの依存関係はなく、 no-std環境で動作します。
Defaultの生成、 fmt::Debug 、またはdefmt::Format特性これをCargo.tomlに追加します。toml:
[ dependencies ]
bitfield-struct = " 0.10 " 簡単な例から始めましょう。以下に示すように、複数のデータを単一のバイト内に保存するとします。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| p | レベル | s | 親切 | ||||
このクレートは、これを簡単に実行できる素敵なラッパータイプを生成します。
use bitfield_struct :: bitfield ;
/// Define your type like this with the bitfield attribute
# [ bitfield ( u8 ) ]
struct MyByte {
/// The first field occupies the least significant bits
# [ bits ( 4 ) ]
kind : usize ,
/// Booleans are 1 bit large
system : bool ,
/// The bits attribute specifies the bit size of this field
# [ bits ( 2 ) ]
level : usize ,
/// The last field spans over the most significant bits
present : bool
}
// The macro creates three accessor functions for each field:
// <name>, with_<name> and set_<name>
let my_byte = MyByte :: new ( )
. with_kind ( 15 )
. with_system ( false )
. with_level ( 3 )
. with_present ( true ) ;
assert ! ( my_byte . present ( ) ) ; さらに、このクレートにはいくつかの便利な機能があり、ここに詳細に示されています。
以下の例は、属性がどのように持ち越され、署名された整数、パディング、カスタムタイプがどのように処理されるかを示しています。
use bitfield_struct :: bitfield ;
/// A test bitfield with documentation
# [ bitfield ( u64 ) ]
# [ derive ( PartialEq , Eq ) ] // <- Attributes after `bitfield` are carried over
struct MyBitfield {
/// Defaults to 16 bits for u16
int : u16 ,
/// Interpreted as 1 bit flag, with a custom default value
# [ bits ( default = true ) ]
flag : bool ,
/// Custom bit size
# [ bits ( 1 ) ]
tiny : u8 ,
/// Sign extend for signed integers
# [ bits ( 13 ) ]
negative : i16 ,
/// Supports any type with `into_bits`/`from_bits` functions
# [ bits ( 16 ) ]
custom : CustomEnum ,
/// Public field -> public accessor functions
# [ bits ( 10 ) ]
pub public : usize ,
/// Also supports read-only fields
# [ bits ( 1 , access = RO ) ]
read_only : bool ,
/// And write-only fields
# [ bits ( 1 , access = WO ) ]
write_only : bool ,
/// Padding
# [ bits ( 5 ) ]
__ : u8 ,
}
/// A custom enum
# [ derive ( Debug , PartialEq , Eq ) ]
# [ repr ( u16 ) ]
enum CustomEnum {
A = 0 ,
B = 1 ,
C = 2 ,
}
impl CustomEnum {
// This has to be a const fn
const fn into_bits ( self ) -> u16 {
self as _
}
const fn from_bits ( value : u16 ) -> Self {
match value {
0 => Self :: A ,
1 => Self :: B ,
_ => Self :: C ,
}
}
}
// Usage:
let mut val = MyBitfield :: new ( )
. with_int ( 3 << 15 )
. with_tiny ( 1 )
. with_negative ( - 3 )
. with_custom ( CustomEnum :: B )
. with_public ( 2 )
// .with_read_only(true) <- Would not compile
. with_write_only ( false ) ;
println ! ( "{val:?}" ) ;
let raw : u64 = val . into ( ) ;
println ! ( "{raw:b}" ) ;
assert_eq ! ( val . int ( ) , 3 << 15 ) ;
assert_eq ! ( val . flag ( ) , true ) ;
assert_eq ! ( val . negative ( ) , - 3 ) ;
assert_eq ! ( val . tiny ( ) , 1 ) ;
assert_eq ! ( val . custom ( ) , CustomEnum :: B ) ;
assert_eq ! ( val . public ( ) , 2 ) ;
assert_eq ! ( val . read_only ( ) , false ) ;
// const members
assert_eq ! ( MyBitfield :: FLAG_BITS , 1 ) ;
assert_eq ! ( MyBitfield :: FLAG_OFFSET , 16 ) ;
val . set_negative ( 1 ) ;
assert_eq ! ( val . negative ( ) , 1 ) ;マクロは、各フィールドに3つのアクセサア関数を生成します。各アクセターは、そのフィールドのドキュメントも継承します。
intの署名は次のとおりです。
// generated struct
struct MyBitfield ( u64 ) ;
impl MyBitfield {
const fn new ( ) -> Self { Self ( 0 ) }
const INT_BITS : usize = 16 ;
const INT_OFFSET : usize = 0 ;
const fn int ( & self ) -> u16 { todo ! ( ) }
const fn with_int ( self , value : u16 ) -> Self { todo ! ( ) }
const fn with_int_checked ( self , value : u16 ) -> Result < Self , ( ) > { todo ! ( ) }
const fn set_int ( & mut self , value : u16 ) { todo ! ( ) }
const fn set_int_checked ( & mut self , value : u16 ) -> Result < ( ) , ( ) > { todo ! ( ) }
// other field ...
}
// Also generates From<u64>, Into<u64>, Default, and Debug implementations...ヒント:Rust-analyzerを使用して、「マクロの再帰的に展開する」アクションを使用して、生成されたコードを表示できます。
マクロは、基礎となるビットフィールドタイプに変換可能な任意のタイプをサポートします。これは、次の例やその他の構造体のような酵素です。
変換値とデフォルト値は、次の#[bits]パラメーターで指定できます。
from :function raw bitsからカスタムタイプに変換すると、デフォルトは<ty>::from_bitsになりますinto :カスタムタイプから生のビットに変換する関数、デフォルトは<ty>::into_bitsになりますdefault :カスタム式、デフォルトは<ty>::from_bits(0)を呼び出す use bitfield_struct :: bitfield ;
# [ bitfield ( u16 ) ]
# [ derive ( PartialEq , Eq ) ]
struct Bits {
/// Supports any convertible type
# [ bits ( 8 , default = CustomEnum :: B , from = CustomEnum :: my_from_bits ) ]
custom : CustomEnum ,
/// And nested bitfields
# [ bits ( 8 ) ]
nested : Nested ,
}
# [ derive ( Debug , PartialEq , Eq ) ]
# [ repr ( u8 ) ]
enum CustomEnum {
A = 0 ,
B = 1 ,
C = 2 ,
}
impl CustomEnum {
// This has to be a const fn
const fn into_bits ( self ) -> u8 {
self as _
}
const fn my_from_bits ( value : u8 ) -> Self {
match value {
0 => Self :: A ,
1 => Self :: B ,
_ => Self :: C ,
}
}
}
/// Bitfields implement the conversion functions automatically
# [ bitfield ( u8 ) ]
struct Nested {
# [ bits ( 4 ) ]
lo : u8 ,
# [ bits ( 4 ) ]
hi : u8 ,
} オプションのorderマクロ引数は、ビットのレイアウトを決定し、デフォルトは最初にLSB(最小重要なビット)です。
use bitfield_struct :: bitfield ;
# [ bitfield ( u8 , order = Lsb ) ]
struct MyLsbByte {
/// The first field occupies the *least* significant bits
# [ bits ( 4 ) ]
kind : usize ,
system : bool ,
# [ bits ( 2 ) ]
level : usize ,
present : bool
}
let my_byte_lsb = MyLsbByte :: new ( )
. with_kind ( 10 )
. with_system ( false )
. with_level ( 2 )
. with_present ( true ) ;
// .- present
// | .- level
// | | .- system
// | | | .- kind
assert_eq ! ( my_byte_lsb . 0 , 0b1_10_0_1010 ) ;マクロは、MSB(最も重要なビット)が指定されているときに逆の順序を生成します。
use bitfield_struct :: bitfield ;
# [ bitfield ( u8 , order = Msb ) ]
struct MyMsbByte {
/// The first field occupies the *most* significant bits
# [ bits ( 4 ) ]
kind : usize ,
system : bool ,
# [ bits ( 2 ) ]
level : usize ,
present : bool
}
let my_byte_msb = MyMsbByte :: new ( )
. with_kind ( 10 )
. with_system ( false )
. with_level ( 2 )
. with_present ( true ) ;
// .- kind
// | .- system
// | | .- level
// | | | .- present
assert_eq ! ( my_byte_msb . 0 , 0b1010_0_10_1 ) ; マクロは、ビットフィールド構造体を表現するためのカスタムタイプをサポートしています。これは、次の例( endian-numから)またはメインのビットフィールドタイプとの間で変換できる他の構造体のようなエンディアン定義型にすることができます。
表現とその変換関数は、次の#[bitfield]パラメーターで指定できます。
repr 、メモリ内のビットフィールドの表現を指定しますfrom Bitfieldの整数型への変換関数を指定するintoこの例には、ビッグエンディアンの機械でもエンディアンのバイトが少し順序付けられています。
use bitfield_struct :: bitfield ;
use endian_num :: le16 ;
# [ bitfield ( u16 , repr = le16 , from = le16 :: from_ne , into = le16 :: to_ne ) ]
struct MyLeBitfield {
# [ bits ( 4 ) ]
first_nibble : u8 ,
# [ bits ( 12 ) ]
other : u16 ,
}
let my_be_bitfield = MyLeBitfield :: new ( )
. with_first_nibble ( 0x1 )
. with_other ( 0x234 ) ;
assert_eq ! ( my_be_bitfield . into_bits ( ) . to_le_bytes ( ) , [ 0x41 , 0x23 ] ) ;この例には、小さなエンディアンの機械でさえも大エンジンのバイト順序があります。
use bitfield_struct :: bitfield ;
use endian_num :: be16 ;
# [ bitfield ( u16 , repr = be16 , from = be16 :: from_ne , into = be16 :: to_ne ) ]
struct MyBeBitfield {
# [ bits ( 4 ) ]
first_nibble : u8 ,
# [ bits ( 12 ) ]
other : u16 ,
}
let my_be_bitfield = MyBeBitfield :: new ( )
. with_first_nibble ( 0x1 )
. with_other ( 0x234 ) ;
assert_eq ! ( my_be_bitfield . into_bits ( ) . to_be_bytes ( ) , [ 0x23 , 0x41 ] ) ; Clone 、 Copyデフォルトでは、このマクロはCloneとCopyを導き出します。タイプのクローン化のセマンティクスがそれを必要とする場合、追加のclone引数でこれを無効にすることができます(たとえば、このタイプは、クローン化する必要がある所有データへのポインターを保持します)。この場合、 CloneとCopy用の独自の実装を提供できます。
use bitfield_struct :: bitfield ;
# [ bitfield ( u64 , clone = false ) ]
struct CustomClone {
data : u64
}
impl Clone for CustomClone {
fn clone ( & self ) -> Self {
Self :: new ( ) . with_data ( self . data ( ) )
}
}
// optionally:
impl Copy for CustomClone { }fmt::Debug 、 Defaultデフォルトでは、 #[derive(Debug, Default)]によって通常の構造体に対して作成されたものと同様の適切なfmt::DebugとDefault実装も生成します。追加のdebugとdefault引数でこれを無効にすることができます。
use std :: fmt :: { Debug , Formatter , Result } ;
use bitfield_struct :: bitfield ;
# [ bitfield ( u64 , debug = false , default = false ) ]
struct CustomDebug {
data : u64
}
impl Debug for CustomDebug {
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> Result {
write ! ( f , "0x{:x}" , self . data ( ) )
}
}
impl Default for CustomDebug {
fn default ( ) -> Self {
Self ( 123 )
}
}
let val = CustomDebug :: default ( ) ;
println ! ( "{val:?}" )defmt::Formatのサポートこのマクロは、追加のdefmt引数を渡すことにより、デフォルトのfmt::Debug実装を反映するdefmt::Format ::フォーマットを自動的に実装できます。この実装では、defMTクレートがdefmtとして利用可能であることを要求し、 #[derive(defmt::Format)]と同じルールと警告を持っています。
use bitfield_struct :: bitfield ;
# [ bitfield ( u64 , defmt = true ) ]
struct DefmtExample {
data : u64
}new / Clone / Debug / Default / defmt::Formatを有効にするブールリアンの代わりに、 new 、 clone 、 debug 、 default 、 defmtのcfg(...)属性を指定できます。
use bitfield_struct :: bitfield ;
# [ bitfield ( u64 , debug = cfg ( test ) , default = cfg ( feature = "foo" ) ) ]
struct CustomDebug {
data : u64
}