#traits #object #casting #direct #target #macro #intertrait

macro intertrait-macros

intertrait crate的宏,允许在特质对象之间进行直接转换

5个版本

0.2.2 2021年8月17日
0.2.1 2020年10月28日
0.2.0 2020年4月24日
0.1.1 2020年4月17日
0.1.0 2020年3月22日

#17 in #casting

Download history 231/week @ 2024-03-15 314/week @ 2024-03-22 356/week @ 2024-03-29 311/week @ 2024-04-05 241/week @ 2024-04-12 292/week @ 2024-04-19 396/week @ 2024-04-26 474/week @ 2024-05-03 568/week @ 2024-05-10 374/week @ 2024-05-17 313/week @ 2024-05-24 283/week @ 2024-05-31 255/week @ 2024-06-07 555/week @ 2024-06-14 414/week @ 2024-06-21 524/week @ 2024-06-28

1,770 每月下载量
44 个crate中使用(通过 intertrait

MIT/Apache

13KB
249 代码行

Intertrait

Build Status Latest Version Rust Documentation

此库提供类型实现特质对象之间的直接转换。

在Rust中,如果类型已知,可以将在std::any::Any子特质的特质对象在运行时向下转换到具体类型。但两个特质对象之间(即不涉及支撑值的具体类型)的直接转换是不可能的(甚至还没有从特质的特质对象到其超特质的转换)。

使用此crate,如果目标特质在使用此crate提供的宏预先注册,则可以任何在CastFrom子特质的特质对象可以直接转换到由底层类型实现的另一个特质的特质对象。

依赖关系

将以下两个依赖项添加到您的Cargo.toml

[dependencies]
intertrait = "0.2"
linkme = "0.2"

linkme依赖项由于在intertrait宏的输出中使用linkme宏而需要。

用法

use intertrait::*;
use intertrait::cast::*;

struct Data;

trait Source: CastFrom {}

trait Greet {
    fn greet(&self);
}

#[cast_to]
impl Greet for Data {
    fn greet(&self) {
        println!("Hello");
    }
}

impl Source for Data {}

fn main() {
    let data = Data;
    let source: &dyn Source = &data;
    let greet = source.cast::<dyn Greet>();
    greet.unwrap().greet();
}

目标特质必须提前明确指定。有三种方法可以做到这一点

#[cast_to]impl

指定的特质的实现被指定为目标特质。

use intertrait::*;

struct Data;
trait Greet { fn greet(&self); }

#[cast_to]
impl Greet for Data {
    fn greet(&self) {
        println!("Hello");
    }
}

#[cast_to(Trait)] 到类型定义

对于类型,指定为#[cast_to(...)]属性参数的特征被指定为目标特征。

use intertrait::*;

trait Greet { fn greet(&self); }

impl Greet for Data {
    fn greet(&self) {
        println!("Hello");
    }
}

#[cast_to(Greet, std::fmt::Debug)]
#[derive(std::fmt::Debug)]
struct Data;

castable_to!(类型=>特征1,特征2)

对于类型,:之后的特征被指定为目标特征。

use intertrait::*;

#[derive(std::fmt::Debug)]
struct Data;
trait Greet { fn greet(&self); }
impl Greet for Data {
    fn greet(&self) {
        println!("Hello");
    }
}
// Only in an item position due to the current limitation in the stable Rust.
// https://github.com/rust-lang/rust/pull/68717
castable_to!(Data => Greet, std::fmt::Debug);

fn main() {}

std::sync::Arc支持

std::sync::Arc的独特之处在于它只实现了downcast方法,条件是对象类型为dyn Any + Send + Sync + 'static'.使用Arc时,应采取以下步骤

  • 将源特征标记为CastFromSync而不是CastFrom
  • [sync]标志添加到#[cast_to]castable_to!,如下所示
    #[cast_to([sync])]
    #[cast_to([sync] Trait1, Trait2)]
    castable_to!(Type => [sync] Trait, Trait2);
    

工作原理

首先,CastFrom特征使得从一个子特征的CastFrom对象中检索到std::any::Any对象成为可能。

intertrait提供的宏生成用于将std::any::Any特质的对象向下转换为具体类型,并从中创建目标特质的特质的跳转函数。

这些跳转函数使用linkme crate聚合到一个全局注册表中,该注册表使用TypeId对进行键控,这些是CastFrom子特质的特质的对象支持的具体类型的以及目标特质的(实际实现略有不同,但概念上是这样的)。

在这个过程中,它不依赖于任何不稳定的Rust实现细节,例如可能在未来更改的特质对象的布局。

致谢

intertrait从伟大的traitcast crate中吸取了许多核心思想。

许可

根据以下任一许可获得许可

由您选择。

贡献

除非您明确表示 otherwise,否则您根据Apache-2.0许可证定义的任何有意提交以包含在作品中的贡献,应如上双许可,不附加任何额外条款或条件。

依赖关系

~2MB
~42K SLoC