4个版本
0.3.0 | 2022年4月3日 |
---|---|
0.1.2 | 2018年4月7日 |
0.1.1 | 2018年4月6日 |
0.1.0 | 2018年4月6日 |
#34 in #compiler-plugin
在 bitrange 中使用
11KB
262 行
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;
由于位域使用了尚未稳定的 proc_macro
功能,bitrange 需要编译器的夜间版本
引用字符串
由于RFC 2320的未决状态,stringify!
不能在过程宏属性中使用。此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帮助您将位字段映射到适当的getter和setter。
比如说,您正在尝试制作一个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
有了位域,您可以轻松地将字节映射到字段。要解析协议的这部分,只需简单地写下
#![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