#traits #dynamic-dispatch #dispatch #speed #performance #optimization

enumerate

一个属性宏,给定一个特性和其实现者,生成一个枚举,可以用来替代特例对象,避免动态调度

2个版本

0.1.1 2019年7月7日
0.1.0 2019年6月25日

#1189 in 过程宏

MIT/Apache

16KB
235

Docs License

enumerate

这个crate提供了一个过程宏,给定一个特性和其实现者,生成一个枚举,然后可以用来替代特例对象,避免动态调度。这个概念基于enum_dispatch crate,但这个实现更专注于给用户提供一个更加简洁的API,需要的样板代码更少。

用法

任何特性能通过#[enumerate(<implementers>)]进行标注来生成相应的枚举。

示例

以下示例展示了如何使用宏从一个特性和两个实现者生成枚举。

#[enumerate(Talker, Shouter)]
pub trait SayMessage {
    fn say_message(&self);
}

pub struct Talker {
    message: String
}

impl SayMessage for Talker {
    fn say_message(&self) {
        println!("{}", self.message);
    }
}

pub struct Shouter {
    message: String,
    repetitions: i32
}

impl SayMessage for Shouter {
    fn say_message(&self) {
        for _ in 0..self.repetitions {
            println!("{}", self.message.to_uppercase());
        }
    }
}

这将生成与特性同名的枚举(在这个例子中是SayMessage)。它将具有TalkerShouter这两个变体。因为你显然不能在同一个模块内有相同标识符的两个类型,所以enumerate会将枚举放入一个子模块中。这些子模块的名称是通过将标注的特性的名称转换为snake_case并附加_enm来生成的。所以上面的例子将创建一个名为say_message_enm的模块。

自定义名称

还可以为枚举及其变体指定自定义名称。指定枚举的名称是通过将宏的第一个参数添加为<name>:来完成的。可以通过使用语法<implementer> as <name>指定变体的自定义名称。所有这些都在下面的示例中得到了展示。

#[enumerate(InterestingName: ImplementerOne as One, ImplementerTwo as Two)]
pub trait BoringName { /* ... */ }

pub struct ImplementerOne;

impl BoringName for ImplementerOne { /* ... */ }

pub struct ImplementerTwo;

impl BoringName for ImplementerTwo { /* ... */ }

这将生成一个名为 InterestingName 的枚举,其变体为 OneTwo。由于枚举和特质之间现在没有命名冲突,因此不需要创建额外的模块,枚举将放置在特质的同一模块中。

实例化

enumerate 自动为每个变体生成 From<T> 的实现。这意味着您可以使用 <enum>::from(<instance>) 以及 <instance>.into() 从实现注解特质的实例获取枚举的实例。以下是一个示例。

let instance = Implementer::new();
let enum_instance = Enum::from(instance);

let alternative = Implementer::new();
let alt_enum_instance: Enum = alternative.into();

enum_instance.trait_method();
alt_enum_instance.trait_method();

关联函数

您不能调用由此宏生成的枚举的关联函数。枚举的生成将正常工作,但在枚举上调用任何关联函数将导致 panic。

依赖项

~2MB
~46K SLoC