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