#integer-value #bit-field #map #mapping #pattern #parser #ip

no-std bin+lib bitrange

简单插件,用于将整数值中的位映射到字段

5 个不稳定版本

0.3.0 2022 年 4 月 3 日
0.2.0 2018 年 4 月 8 日
0.1.2 2018 年 4 月 7 日
0.1.1 2018 年 4 月 6 日
0.1.0 2018 年 4 月 6 日

#3#位域

MIT 许可证

17KB
276

bitrange

入门指南

要开始使用,请将以下内容添加到您的 Cargo.toml

[dependencies]
bitrange = { git = "https://github.com/trangar/bitrange" }
bitrange_plugin = { git = "https://github.com/trangar/bitrange" }

然后添加以下代码到您的 main.rslib.rs

#[macro_use]
extern crate bitrange;
#[macro_use]
extern crate bitrange_plugin;

由于 bitrange 使用了尚未稳定的特性 proc_macro,它需要编译器的夜间版本

引用字符串

由于一个 openstanding RFC 2320stringify! 不能在 proc-macro 属性中使用。此 crate 生成的代码包含

#[derive(Bitrange)]
#[BitrangeMask = $format]
#[BitrangeSize = $struct_size_string]

其中 $format$struct_size_string 来自 bitrange 宏。

在此情况下,我们希望使用 stringify!($format)stringify($struct_size_string),但是这需要在 RFC 2320 到来之后才能工作。

因此,格式需要加引号,并且需要注释两次类型。例如

bitrange! {
    Test: u8, "u8",
    "aaaa_bbbb",
    a: first,
    b: second
}

而不是期望的

bitrange! {
    Test: u8,
    aaaa_bbbb,
    a: first,
    b: second
}

示例

Bitrange 帮助您将位域映射到适当的获取器和设置器。

比如说您正在尝试制作一个 IP 解析器。rfc 将给您这个

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version|  IHL  |Type of Service|          Total Length         |

如果您想在 Rust 中解析这部分协议,您需要做出以下映射

  • 前 4 位映射到 version
  • 接下来的 4 位映射到 ihl
  • 接下来的 8 位映射到 type_of_service
  • 最后的 16 位映射到 total_length

使用 bitrange,您可以轻松地将字节映射到字段。要解析这部分协议,只需编写

#![feature(proc_macro)]
#[macro_use]
extern crate bitrange;

bitrange! {
    IpHeader: u32, "u32",                    // struct name
    "aaaa_bbbb_cccccccc_dddddddddddddddd",   // pattern that we're matching against
    a: version,                              // map character 'a' to field 'version'
    b: ihl,                                  // map character 'b' to field 'ihl'
    c: type_of_service,                      // map character 'c' to field 'type_of_service'
    d: total_length                          // map character 'd' to field 'total_length'
}

fn main() {
    let header = IpHeader::from(0b0001_0010_00000011_0000000000000100);
    assert_eq!(header.version(), 0b0001);
    assert_eq!(header.ihl(), 0b0010);
    assert_eq!(header.type_of_service(), 0b0011);
    assert_eq!(header.total_length(), 0b0100);
}

如果您想使字段可变,只需在字段映射中添加第二个标识符,例如


bitrange! {
    IpHeader: u32, "u32",                    // struct name
    "aaaa_bbbb_cccccccc_dddddddddddddddd",   // pattern that we're matching against
    a: version set_version,                  // map character 'a' to field 'version', and create setter 'set_version'
    b: ihl,                                  // map character 'b' to field 'ihl'
    c: type_of_service,                      // map character 'c' to field 'type_of_service'
    d: total_length                          // map character 'd' to field 'total_length'
}

fn main() {
    let mut header = IpHeader::from(0b0001_0010_00000011_0000000000000100);
    assert_eq!(header.version(), 0b0001);
    assert_eq!(header.ihl(), 0b0010);
    assert_eq!(header.type_of_service(), 0b0011);
    assert_eq!(header.total_length(), 0b0100);

    header.set_version(0b0100);
    assert_eq!(header.version(), 0b0100);
}

此外,您可以定义必须始终为 0 或 1 的位的约束


bitrange! {
    Test: u8, "u8",
    // from left (highest) to right (lowest)
    // first 3 bits are mapped to a
    // the next bit is always 1
    // the next bit is always 0
    // the last 3 bits are mapped to b
    "aaa1_0bbb",
    a: first,
    b: second
}

fn main() {
    // This panics at runtime
    // Because the 4th highest bit should always be 1
    // Test::from(0);

    // The enum also implements Default, so you can simply do:
    let _test = Test::default();
    // And this will have value 0b0001_0000
}

编译时检查

bitrange 还会在编译时检查字段是否存在

bitrange! { 
    Test: u8, "u8",
    "aaa1_0bbb",
    a: first,
    b: second,
    c: third // this will panic with
             // Token 'c' is not found in pattern "aaa10bbb"
}

但是,这不能用于未映射的字段

bitrange! {
    Test: u8, "u8",
    "aaa1_0bbb",
    a: first,
    // b is not mapped
    // Does not give a warning
}

依赖关系

~1.5MB
~35K SLoC