#traits #cast #any #generate

intertrait

允许进行跨特质转换

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日

#497 in Rust模式

Download history 208/week @ 2024-03-14 293/week @ 2024-03-21 391/week @ 2024-03-28 273/week @ 2024-04-04 235/week @ 2024-04-11 331/week @ 2024-04-18 348/week @ 2024-04-25 474/week @ 2024-05-02 470/week @ 2024-05-09 488/week @ 2024-05-16 287/week @ 2024-05-23 321/week @ 2024-05-30 228/week @ 2024-06-06 511/week @ 2024-06-13 465/week @ 2024-06-20 569/week @ 2024-06-27

1,822 每月下载量
用于 43 个crate (5 直接)

MIT/Apache

32KB
446

Intertrait

Build Status Latest Version Rust Documentation

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

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

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

依赖项

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

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

linkme依赖项是必需的,因为linkme宏在intertrait宏的输出中使用。

用法

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() {}

Arc 支持

std::sync::Arc 的独特之处在于它仅在 dyn Any + Send + Sync + 'static'. 上实现 downcast 方法。要与 Arc 一起使用,应采取以下步骤

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

工作原理

首先,CastFrom 特性使得从 std::any::Any 对象中检索 std::any::Any 对象成为可能。

intertrait 提供的宏生成了将 std::any::Any 特性对象向下转换为其实际类型的跳转函数,并从其中创建目标特质的特性对象。

这些跳转函数使用 linkme 包聚合到全局注册表中,这涉及到没有(通常不鼓励的)main 之前的生命周期技巧。注册表由一对 TypeId 组成,它们是 CastFrom 子特质的特性对象的底层实际类型的 TypeId 和目标特质(这里的实际实现略有不同,但概念上是如此)。

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

致谢

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

许可证

根据您的选择,受以下任何一个许可证的约束

贡献

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

依赖项

~2MB
~43K SLoC