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 在 #位域
17KB
276 行
bitrange
入门指南
要开始使用,请将以下内容添加到您的 Cargo.toml
[dependencies]
bitrange = { git = "https://github.com/trangar/bitrange" }
bitrange_plugin = { git = "https://github.com/trangar/bitrange" }
然后添加以下代码到您的 main.rs
或 lib.rs
#[macro_use]
extern crate bitrange;
#[macro_use]
extern crate bitrange_plugin;
由于 bitrange 使用了尚未稳定的特性 proc_macro
,它需要编译器的夜间版本
引用字符串
由于一个 openstanding RFC 2320,stringify!
不能在 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