Crate bitstructs

Source
Expand description

bitstructs is a library for defining type-safe bitfield structures that can be used in both std and no_std environments.

The library provides three macros, bitstruct_cow, bitstruct_owned, and bitstruct_small, for generating BitStruct. It also includes the bitstruct_field_enum macro for safely generating enum types for fields within BitStruct. Only bitstruct_cow is not supported in no_std environments because it relies on std::borrow::Cow.

bitstructs是一个可同时用于std和no_std 环境,定义类型安全的位域结构体的库。

该库提供了bitstruct_cowbitstruct_ownedbitstruct_small三个宏, 用于生成BitStruct。以及bitstruct_field_enum宏,用于安全的生成BitStruct中字段枚举类型。 其中只有bitstruct_cow 因为需要使用std::borrow::Cow ,所以不支持 no_std 环境。

§Defining BitStruct

The usage of the three macros, bitstruct_cow, bitstruct_owned, and bitstruct_small, is similar.

The syntax is similar to Rust’s struct definition, except that a number is used after the field name to indicate the bit width instead of the type. You can optionally use => to specify the corresponding enum type for the field. The field’s enum type can be declared inline or referenced from an external definition.

bitstruct_cowbitstruct_ownedbitstruct_small三个宏的使用方法类似。

语法类似rust的结构体定义,只是在字段名后使用数字表示位宽而非类型, 然后可以选择的使用=>设置字段的对应的枚举类型。字段枚举类型可以 使用内联枚举声明,也可以使用外部定义的枚举类型。

use bitstructs::{bitstruct_owned};

bitstruct_owned! {
    #[derive(Clone, Debug, PartialEq)]
    pub struct Foo {
        a: 1,
        b: 2,
        c: 2 =>
        pub enum C {
            C0 = 0,
            C1 = 1,
        },
    }
}
let mut value = Foo::new();
assert_eq!(value.as_bytes(), vec![0b0000_0000]);
value.set_a(true);
unsafe { value.set_b(1) };
value.set_c(C::C1);
assert_eq!(value.as_bytes(), vec![0b0000_1011]);

By default, the library uses LSB0 and little-endian mode. To use MSB0 and big-endian mode, add #[bitstruct_repr(MSB0)] to the struct.

默认情况下,采取的是LSB0和小端模式。如果要使用MSB0和大端模式, 可以在结构体上添加中添加#[bitstruct_repr(MSB0)]

use bitstructs::{bitstruct_owned};

/// MSB0 and big-endian mode
/// MSB0和大端模式
bitstruct_owned! {
    #[derive(Clone, Debug, PartialEq)]
    #[bitstruct_repr(MSB0)]
    pub struct Foo {
        a: 1,
        b: 2,
        c: 2 =>
        pub enum C {
            C0 = 0,
            C1 = 1,
        },
    }
}
let mut value = Foo::new();
assert_eq!(value.as_bytes(), vec![0b0000_0000]);
value.set_a(true);
unsafe { value.set_b(1) };
value.set_c(C::C1);
assert_eq!(value.as_bytes(), vec![0b1010_1000]);

The bitstruct_owned macro generates the following methods:

  • fn new() -> Self: Creates a new BitStruct.
  • fn bytes_len() -> usize: Gets the number of bytes occupied by the BitStruct.
  • fn from_bytes(bytes: &[u8]) -> Result<Self, BitStructError>: Creates a BitStruct from a byte array.
  • fn as_bytes(&self) -> &[u8]: Gets an immutable reference to the byte array of the BitStruct.
  • fn as_bytes_mut(&mut self) -> &mut [u8]: Gets a mutable reference to the byte array of the BitStruct.
  • Methods for reading and setting each field. For fields without a specified enum type, the type will be chosen from bool, u8, u16, u32, or u128. Fields exceeding 128 bits will cause a compilation failure. For example, fn b(&self) -> u8 and unsafe fn set_b(&mut self, value: u8), fn c(&self) -> C and fn set_c(&mut self, value: C).

The usage of bitstruct_cow is the same as bitstruct_owned, but the generated BitStruct uses Cow internally. Additionally, as_bytes and as_bytes_mut are replaced with to_bytes and to_bytes_mut.

The usage of bitstruct_small is similar to bitstruct_owned, but it restricts the size of BitStruct to a maximum of 128 bits. It does not support #[bitstruct_repr(MSB0)] but allows #[bitstruct_repr(u8)] to explicitly specify the internal storage type of BitStruct.

bitstruct_owned宏会生成以下方法:

  • fn new() -> Self:创建一个新的BitStruct
  • fn bytes_len() -> usize:获取BitStruct占用的字节数。
  • fn from_bytes(bytes: &[u8]) -> Result<Self, BitStructError>:从字节数组中创建BitStruct
  • fn as_bytes(&self) -> &[u8]:获取BitStruct的字节数组引用。
  • fn as_bytes_mut(&mut self) -> &mut [u8]:获取BitStruct的字节数组可变引用。
  • 各个字段的读取和设置方法,对于没有指定枚举类型的字段,类型将会使用bool,u8,u16,u32,u128中选择。超过128位,将会编译失败。 例如fn b(&self) -> u8unsafe fn set_b(&mut self, value: u8)fn c(&self) -> Cfn set_c(&mut self, value: C)

bitstruct_cow的使用和bitstruct_owned相同,只是生成的BitStruct内部是Cow类型, 以及将as_bytes,as_bytes_mut换成了to_bytesto_bytes_mut

bitstruct_small的使用和bitstruct_owned类似。但是限制了BitStruct的大小,最大为128位。 以及不支持使用#[bitstruct_repr(MSB0)],但是支持#[bitstruct_repr(u8)]去显示指定BitStruct内部的实际存储类型。

use bitstructs::{bitstruct_small};

/// Specifying the storage type as u32
/// 指定存储类型为u32
bitstruct_small! {
    #[derive(Clone, Debug, PartialEq)]
    #[bitstruct_repr(u32)]
    pub struct Foo {
        a: 1,
        b: 2,
        reserved: 2,
        c: 2 =>
        #[derive(Debug, PartialEq, Eq)]
        pub enum C {
            C0 = 0,
            C1 = 1,
        },
    }
}
let value: u32 = 0b0100_10_1;
let value = Foo::from_value(value);
assert_eq!(value.a(), true);
assert_eq!(value.b(), 2);
assert_eq!(value.c(), C::C1);

§Defining Enum Types

In addition to defining enum types within the bitstruct_owned, bitstruct_cow, and bitstruct_small macros as shown in the example above, enum types can also be defined externally. Unlike inline enums, externally defined enum types can be reused. Here is a simple example:

除了像上面例子那样,在bitstruct_ownedbitstruct_cowbitstruct_small宏中定义枚举类型,还可以在外部定义枚举类型。 在外部定义的枚举类型,不同于内联枚举,可以重复使用。下面是一个简单的例子:

use bitstructs::{bitstruct_field_enum, bitstruct_owned};

/// This is an enum type suitable for 2 bits
/// 这是一个适用于 2 bit 的枚举类型
#[bitstruct_field_enum(2)]
#[derive(Debug)]
pub enum TwoBitEnum {
    Zero = 0,
    One = 1,
    Two = 2,
    Three = 3,
}
bitstruct_owned! {
    pub struct Foo {
        a: 4,
        b: 2 => TwoBitEnum,
        c: 2 => TwoBitEnum,
    }
}

If the variants in the enum type do not cover all possible values, variants with the prefix __Reserved will be automatically added. This also applies to inline enum types.

Note: #[bitstruct_field_enum(2)] should be placed above #[derive(Debug)], otherwise Debug will not recognize the automatically completed variants.

如果枚举类型中的变体(variants)没有覆盖所有可能的取值, 会自动添加前缀为 __Reserved 的变体。这同样适用于内联枚举类型。

注意#[#[bitstruct_field_enum(2)]应该在#[derive(Debug)]上方,否则Debug不会识别到自动补全的变体。

use bitstructs::{bitstruct_field_enum,bitstruct_owned};
#[bitstruct_field_enum(2)]
#[derive(Debug)]
pub enum TwoBitEnum {
   Zero = 0,
   Two = 2,
}
bitstruct_owned! {
    pub struct Foo {
        a: 4,
        b: 2 =>
        enum B {
            Foo = 2,
            Bar = 3,
        },
    }
}

The code above is equivalent to:

use bitstructs::{bitstruct_field_enum,bitstruct_owned};
#[bitstruct_field_enum(2)]
#[derive(Debug)]
pub enum TwoBitEnum {
    Zero = 0,
    Two = 2,
    __Reserved1 = 1,
    __Reserved3 = 3,
}
bitstruct_owned! {
    pub struct Foo {
        a: 4,
        b: 2 =>
        enum B {
            Foo = 2,
            Bar = 3,
            __Reserved0 = 0,
            __Reserved1 = 1,
        },
    }
}

§Confusing Error Messages

If the bit width of the enum type does not match the bit width of the field in BitStruct, compilation will fail. However, since the current check for non-inline enum types uses const to trigger a compilation error through overflow, the error message may not be very friendly when the bit widths do not match.

如果枚举类型的位宽与 BitStruct 中字段的位宽不匹配,编译将会失败。 然而,由于当前对非内联枚举类型的检查是通过使用 const 来触发编译错误(利用溢出), 因此当位宽不匹配时,错误信息不够友好。

use bitstructs::{bitstruct_field_enum,bitstruct_owned};
#[bitstruct_field_enum(2)]
pub enum TwoBitEnum {
   Zero = 0,
   One = 1,
   Two = 2,
   Three = 3,
}
bitstruct_owned! {
    pub struct Foo {
        a: 4,
        b: 3 => TwoBitEnum,
    }
}

The code above will fail to compile with an error message similar to:

error[E0080]: evaluation of constant value failed
  --> bitstructs/src/main.rs:9:1
   |
9  | / bitstruct_owned! {
10 | |     pub struct Foo {
11 | |         a: 4,
12 | |         b: 3 => TwoBitEnum,
13 | |     }
14 | | }
   | |_^ attempt to compute `0_u32 - u32::MAX`, which would overflow

Declaring inline enum types is checked during macro expansion, which results in more friendly error messages.

use bitstructs::{bitstruct_small};
bitstruct_small! {
    pub struct Foo {
        a: 4,
        b: 2 =>
        enum B {
           Zero = 0,
           One = 1,
           Two = 2,
           Three = 3,
           Four = 4
       },
    }
}

The code above will fail to compile with an error message similar to:

error: enum type variant count must be less than or equal to 2^2
 --> bitstructs/src/main.rs:5:22
  |
6 |         enum B {
  |              ^

Macros§

bitstruct_cow
Use Cow to implement BitStruct. 使用写时复制的BitStruct实现。
bitstruct_owned
Copy the byte data directly, the BitStruct implementation with ownership. 直接复制字节数据,拥有所有权的BitStruct实现。
bitstruct_small
Suitable for small data structure BitStruct implementation. 适用于小型数据结构的BitStruct实现。

Traits§

BitstructFromValue
A trait that must be implemented for non-inline field enum types. 非内联的字段枚举类型必须实现的trait。
BitstructToValue
A trait that must be implemented for non-inline field enum types. 非内联的字段枚举类型必须实现的trait。

Attribute Macros§

bitstruct_field_enum
Used to declare the enumeration type of the field. 用于声明字段的枚举类型。
bitstruct_repr
Used to declare the representation of BitStruct’s store_type or bit_numbering. 用于描述BitStruct的store_type或bit_numbering.