6个版本

0.2.0 2024年7月25日
0.1.2 2024年3月12日
0.1.1 2023年4月7日
0.1.0 2022年8月18日

#1185 in 过程宏

Download history 2/week @ 2024-04-22 8/week @ 2024-05-20 5/week @ 2024-06-03 1/week @ 2024-06-10 1/week @ 2024-07-01 147/week @ 2024-07-22 14/week @ 2024-07-29

每月161次下载
dyn-dyn 中使用

MIT/Apache

22KB
448 代码行

dyn-dyn

Tests Crates.io docs.rs

dyn-dyn 允许使用不稳定的 ptr_metadata 功能,将动态特例对象灵活地向下转换为其他动态特例对象。与许多提供类似功能的crate不同,dyn-dyn 不依赖于任何链接器技巧或全局注册表来执行其魔法,使其可以在 #![no_std] crate 中使用,甚至无需 allocdyn-dyn 还不要求基类以任何方式列出它可以向下转换到的特例:实现类型完全控制选择要公开的任何有效特例集。

免责声明:此代码尚未经过彻底审计或测试,依赖于许多不稳定的功能和不安全的代码技巧,因此可能在任何时候崩溃。虽然测试是在Miri下运行的,以尝试捕获任何未定义的行为,但最好不要在生产代码中依赖当前状态的此crate。

用法

dyn-dyn 的使用方法是通过声明一个带有 #[dyn_dyn_base] 属性宏的 "基础特性" 来实现的,然后使用 #[dyn_dyn_impl(...)] 属性宏为该特性的任何 impl 块进行注解。然后,可以通过使用 dyn_dyn_cast! 宏将基础特性的任何引用向下转换为派生特性的引用,例如这样:

use dyn_dyn::{dyn_dyn_base, dyn_dyn_cast, dyn_dyn_impl};

#[dyn_dyn_base]
trait BaseTrait {}
trait ExposedTrait {}

struct Struct;

impl ExposedTrait for Struct {}

#[dyn_dyn_impl(ExposedTrait)]
impl BaseTrait for Struct {}

let mut s = Struct;

assert!(dyn_dyn_cast!(BaseTrait => ExposedTrait, &s).is_ok());
assert!(dyn_dyn_cast!(mut BaseTrait => ExposedTrait, &mut s).is_ok());

#[cfg(feature = "alloc")]
assert!(dyn_dyn_cast!(move BaseTrait => ExposedTrait, Box::new(s)).is_ok());

限制

由于使用了不稳定的 coerce_unsizedptr_metadataunsize 功能,以及在其 const 上下文中使用了几个标准库功能,因此目前 dyn-dyn 只能在 Rust 的夜间版本中使用。

由于 TypeId 的限制,dyn-dyn 目前只能与 'static 的类型和特性一起工作。

为了能够构造一个向下转换为具体类型希望公开的每个可能派生特性的方法,使用 #[dyn_dyn_impl(...)] 属性公开的特性集必须是有限的。也就是说,不能为任意值 T 的泛型特性 Trait<T> 进行公开(尽管如果 T 由具体类型或基础特性的泛型参数约束,则可以进行公开)。

它是如何工作的

dyn-dyn 通过创建一个表来实现,该表将各种与特性对应的 TypeId 映射到用于特定具体类型的 vtable 指针。然后,这个表通过基础特性的隐藏超特性公开,允许 dyn_dyn_cast! 宏动态查找与特定特性对象对应的元数据。然后,使用不稳定的 ptr_metadata 功能将此元数据重新附加到指针上,以创建派生特性对象类型的引用。


lib.rs:

这个软件包提供了与 dyn-dyn 软件包一起使用的过程宏。不应直接依赖此软件包:相反,应使用从 dyn-dyn 软件包本身导出的这些宏的版本。

依赖关系

~1.5MB
~36K SLoC