#traits #cast #any #upcast #rtti

nightly no-std trait_cast_rs

获得支持将 trait 对象进行转换的自定义 Any 类型

5 个版本

0.2.4 2022 年 11 月 10 日
0.2.3 2022 年 9 月 25 日
0.2.2 2022 年 9 月 23 日
0.2.1 2022 年 9 月 22 日
0.2.0 2022 年 8 月 28 日

Rust 模式 中排名 1212

每月下载量 21

MIT/Apache

40KB
412 行代码(不包括注释)

trait_cast_rs

Daily-Nightly Rust-Main-CI docs.rs crates.io rustc

要求

此 crate 需要夜间编译器。

此 crate 能做什么?

此 crate 为 Any 添加了 TraitcastableAny 替换 trait。它类似于 Any trait,用于向下转换为具体类型。此外,TraitcastableAny trait 允许您直接向下转换为其他 &dyn Trait

要使此功能正常工作,您必须在 make_trait_castable(Trait1, Trait2, ...) 属性宏中指定所有要向下转换的目标 traits。此宏可以应用于结构体、枚举和联合体。它为您指定的结构体、枚举或联合体实现了 TraitcastableAny trait。

注意:无需修改目标 traits。这允许您向下转换为不受您控制的库中的 traits。

用法

  1. trait_cast_rs crate 添加到您的 Cargo.toml 并切换到夜间编译器。

  2. #[make_trait_castable(Trait1, Trait2, ...)] 宏添加到您的结构体/枚举/联合体中。列出您最终想要向下转换的所有 traits。您必须实现所有列出的 traits。

  3. 在整个代码中使用 dyn TraitcastableAny 的引用,而不是 dyn Any

  4. 享受向下转换为 trait 对象。

示例

use trait_cast_rs::{
  make_trait_castable, TraitcastableAny, TraitcastableAnyInfra, TraitcastableAnyInfraExt,
};
#[make_trait_castable(Print)]
struct Source(i32);
trait Print {
  fn print(&self);
}
impl Print for Source {
  fn print(&self) {
    println!("{}", self.0)
  }
}

let source = Box::new(Source(5));
let castable: Box<dyn TraitcastableAny> = source;
let x: &dyn Print = castable.downcast_ref().unwrap();
x.print();

更多示例 🔥

查看 示例

如果您想要做一些make_trait_castable属性宏无法处理的操作(例如实现泛型结构体 - 欢迎提交pull请求),请查看manual*.rs示例。

还有可用的声明宏 - 查看示例with_decl_macro*.rs

功能

  • alloc - 为BoxRcArc添加特殊实现。默认功能。

  • const_sort - 使make_trait_castablemake_trait_castable_decl宏在编译时traitcast_targets进行排序。当执行向下转换时,将执行二分搜索。对于具有大量向下转换目标类型的类型,可能会非常快

    此外,用户代码还需要以下功能标志:#![feature(const_trait_impl, const_mut_refs)]

  • min_specialization - 为'static类型实现TraitcastableAny。即使是您无法控制的类型。然而,这些TraitcastableAny的默认实现没有向下转换目标。

    此外,用户代码还需要以下功能标志:#![feature(min_specialization)]

  • downcast_unchecked - 向向下转换函数添加*_unchecked变体。

向上转换为真正的Any

使用trait_upcasting rust功能,您甚至可以将任何&dyn TraitcastableAny转换为&dyn Any。或者,您可以将Any特质作为特质转换目标。但是,无法将其转换回TraitcastableAny(欢迎提交pull请求)。

作者

raldone01onestacked是此库的主要作者和维护者。

许可证

该项目可以在以下许可证下发布:

由您选择。

贡献

除非您明确声明,否则任何有意提交以包含在您的工作中的贡献,根据Apache-2.0许可证定义,均将按照上述方式双许可,不附加任何其他条款或条件。

它是如何工作的

我将简要介绍我们的内部操作:💦

编译时

  1. 为每个向下转换路径向具体类型添加一个casting函数。此函数接收一个dyn TraitcastableAny,然后使用背景中的Any将其向下转换为具体类型。最后,它将具体类型转换为所需的特质对象并返回它。

  2. 添加一个返回常量切片的traitcast_targets函数,其中包含(typeid,转换的casting函数指针)。

运行时

  1. 获取目标数组
  2. 查找目标typeid
  3. 将函数指针转换回原始类型
  4. 调用函数指针以获取所需的特质对象
  5. 返回它
  6. 💲 利润 💲

安全性 🏰

  • 所有未检查的downcast函数变体都使用unsafe - 如预期。
  • 不安全使用的另一个用途是函数指针的转换。然而,当它们被调用时,它们会转换回原始类型。所以这应该是 105% 保存的。 只要 TypeId 不冲突。

替代方案 (以及为什么我们的 crate 是最好的)

本替代方案部分并不全面,如需更客观/详细的比较,请参阅 cast_trait_object 的替代方案部分。

  • mopa:最后一次更新是在6年前。有一些未解决的 不安全性问题。还要求对特质的本身进行修改,而我们已经修改了结构体/枚举/联合体(见上面的注释)。
  • mopa-maintained:可能已修复一些问题,但代码库仍然很旧,只是版本升级。
  • traitcast:在 crates.io 上没有提供说明文档。使用全局注册表,并带有 lazy_static。公平地说,它允许您使用默认的 Any,并且不需要 nightly。

待办事项:一旦我们的最后一次更新是在6年前,就删除此部分。

std::any

std::any::Any

TypeId

downcast-rs

intertrait

traitcast

traitcast_core

cast_trait_object

mopa

mopa-maintained

依赖

~215–295KB