#traits #downcast #cast

nightly no-std dyn-dyn

使用ptr_metadata灵活地进行特质对象向下转型

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日

#371 in Rust模式

Download history 1/week @ 2024-05-17 1/week @ 2024-05-31 1/week @ 2024-06-07 33/week @ 2024-07-19 113/week @ 2024-07-26 4/week @ 2024-08-02

每月150次下载

MIT/Apache

52KB
811

dyn-dyn

Tests Crates.io docs.rs

dyn-dyn 允许使用不稳定特性 #[dyn_dyn_base] 声明一个“基特质”,并使用 #[dyn_dyn_impl(...)] 属性宏来声明对该特质的实现。然后可以通过使用 dyn_dyn_cast! 宏将基特质的引用向下转型为派生特质的引用,如下所示

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

使用方法

dyn-dyn 通过声明一个带有 #[dyn_dyn_base] 属性宏的“基特质”并使用 #[dyn_dyn_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());

限制

由于使用不稳定特性 generic_associated_typesptr_metadataunsize 以及在 const 上下文中使用几个标准库特性,dyn-dyn 目前仅在Rust的nightly版本中工作。

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

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

工作原理

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

依赖项

~1.5MB
~36K SLoC