3 个版本 (破坏性更新)
0.3.2 | 2022 年 8 月 14 日 |
---|---|
0.3.1 |
|
0.3.0 |
|
0.2.0 | 2021 年 10 月 20 日 |
0.1.0 | 2021 年 10 月 19 日 |
#1627 in Rust 模式
16KB
196 行
dyn_struct
该软件包允许您仅使用安全的 Rust 来安全地初始化动态大小类型 (DST)。
#[repr(C)]
#[derive(DynStruct)]
struct MyDynamicType {
pub awesome: bool,
pub number: u32,
pub dynamic: [u32],
}
// the `new` function is generated by the `DynStruct` macro.
let foo: Box<MyDynamicType> = MyDynamicType::new(true, 123, [4, 5, 6, 7]);
assert_eq!(foo.awesome, true);
assert_eq!(foo.number, 123);
assert_eq!(&foo.dynamic, &[4, 5, 6, 7]);
为什么是动态类型?
在 Rust 中,动态大小类型 (DST) 到处都是。切片 ([T]
) 和特质对象 (dyn Trait
) 是最常见的。然而,您也可以定义自己的!例如,这可以通过让结构体的最后一个字段成为一个动态大小数组(注意缺少 &
)来实现。
struct MyDynamicType {
awesome: bool,
number: u32,
dynamic: [u32],
}
这告诉 Rust 编译器,动态数组的内存布局紧接在其他字段之后。在某些情况下,这可能会非常理想,因为它减少了一层间接引用并提高了缓存局部性。
然而,有一个问题!就像切片一样,编译器不知道 dynamic
中有多少元素。因此,我们需要所谓的胖指针,它存储实际数据的指针以及数组的长度。截至发布此软件包时,唯一安全构造动态类型的方法是在编译时知道数组的长度。然而,对于大多数用例,这是不可能的。因此,该软件包在后台使用一些 unsafe
来解决语言的限制,并通过一个安全接口包装起来。
Derive 宏
DynStruct
宏可以应用于任何包含动态大小数组作为最后一个字段的 #[repr(C)]
结构体。字段只有一个约束:它们必须实现 Copy
。
示例
#[repr(C)]
#[derive(DynStruct)]
struct MyDynamicType {
pub awesome: bool,
pub number: u32,
pub dynamic: [u32],
}
将产生一个包含 new
函数的单个 impl
块。此函数接受与声明顺序相同的所有字段。但是,最后一个字段可以是任何实现 IntoIterator
的类型。
impl MyDynamicType {
pub fn new<I>(awesome: bool, number: u32, dynamic: I) -> Box<MyDynamicType>
where I: IntoIterator<Item = u32>,
I::IntoIter: ExactSizeIterator,
{
// ... implementation details ...
}
}
由于动态大小类型的特点,结果值必须在堆上构建。出于安全考虑,我们目前只允许返回 Box
,尽管在未来版本中,我们也可能允许 Rc
和 Arc
。在此期间,可以使用 Arc::from(MyDynamicType::new(...))
。
依赖项
~215KB