5次发布
0.2.1 | 2024年4月13日 |
---|---|
0.2.0 | 2024年4月12日 |
0.1.2 | 2024年4月7日 |
0.1.1 | 2024年4月7日 |
0.1.0 | 2024年4月7日 |
220 在 过程宏 中
每月40次下载
25KB
383 行
specialized-dispatch
此crate提供了一个过程宏specialized_dispatch
,它是一种方便的实现基于表达式类型的不同行为的便捷方式。
它通过在调用点创建不同的特化来实现,这是通过在内部使用min_specialization
夜间功能来实现的。
因此,调用者需要从调用此宏的库中启用此夜间功能。
简单示例
#![feature(min_specialization)]
use specialized_dispatch::specialized_dispatch;
fn example<E>(expr: E) -> String {
specialized_dispatch!(
// Type of the expression -> return type.
E -> String,
// Defaut implementation.
default fn <T>(_: T) => format!("default value"),
// Specialization for concrete type u8.
fn (v: u8) => format!("u8: {}", v),
// Specialization for concrete type u16.
fn (v: u16) => format!("u16: {}", v),
// The expression for passing to above specializations.
expr,
)
}
fn main() {
assert_eq!(example(1.0), "default value");
assert_eq!(example(5u8), "u8: 5");
assert_eq!(example(10u16), "u16: 10");
println!("Done!");
}
example
函数大致展开为以下代码。请注意,确切的展开是内部实现细节。此示例提供以演示其工作原理。
fn example<E>(expr: E) -> String {
trait SpecializedDispatchCall<T> {
fn dispatch(t: T) -> String;
}
impl<T> SpecializedDispatchCall<T> for T {
default fn dispatch(_: T) -> String {
format!("default value")
}
}
impl SpecializedDispatchCall<u8> for u8 {
fn dispatch(v: u8) -> String {
format!("u8: {}", v)
}
}
impl SpecializedDispatchCall<u8> for u16 {
fn dispatch(v: u16) -> String {
format!("u16: {}", v)
}
}
<E as SpecializedDispatchCall<E>>::dispatch(expr)
}
上述示例包含在存储库中。
可以使用以下命令运行它:cargo run --example simple_example
。
可以使用cargo-expand
检查展开的代码:cargo expand --example simple_example
。
特质边界
可以为默认情况提供特质边界
#![feature(min_specialization)]
use std::fmt::Display;
use specialized_dispatch::specialized_dispatch;
// The expression type must also bind to the same trait.
fn example<E: Display>(expr: E) -> String {
specialized_dispatch!(
E -> String,
// Notice the trait bound.
default fn <T: Display>(v: T) => {
format!("default value: {}", v)
},
// Note that specializations also need to satisfy the same bound.
fn (v: u8) => format!("u8: {}", v),
fn (v: u16) => format!("u16: {}", v),
expr,
)
}
fn main() {
assert_eq!(example(1.5), "default value: 1.5");
assert_eq!(example(5u8), "u8: 5");
assert_eq!(example(10u16), "u16: 10");
println!("Done!");
}
同样,上述示例包含在存储库中。
可以使用 cargo run --example trait_bound
来运行,或者使用 cargo-expand
来检查。
传递额外参数
可以将额外参数传递给特殊化。参数类型需要显式声明(即,它们不会像闭包那样自动捕获)。
#![feature(min_specialization)]
use std::fmt::Display;
use specialized_dispatch::specialized_dispatch;
fn example<T: Display>(expr: T, arg: &str) -> String {
specialized_dispatch!(
T -> String,
default fn <T: Display>(v: T, arg: &str) => {
format!("default value: {}, arg: {}", v, arg)
},
fn (v: u8, arg: &str) => format!("u8: {}, arg: {}", v, arg),
fn (v: u16, arg: &str) => format!("u16: {}, arg: {}", v, arg),
expr, arg,
)
}
fn main() {
assert_eq!(example(1.5, "I'm a"), "default value: 1.5, arg: I'm a");
assert_eq!(example(5u8, "walnut"), "u8: 5, arg: walnut");
assert_eq!(example(10u16, "tree"), "u16: 10, arg: tree");
println!("Done!");
}
特殊化仍然仅基于第一个参数。
与前面的示例一样,上面的示例也被包含在存储库中。[链接](https://github.com/ozars/specialized-dispatch/blob/80bbec938876b220ebecf00695acaaa69b01618c/examples/pass_args.rs)。可以使用 cargo run --example pass_args
来运行或使用 cargo-expand
来检查。
高级 Serdelike 示例
假设你正在实现一个反序列化器。可能有一些类型与你的反序列化器配合得很好,而对于泛型反序列化器,它们可能有默认实现(或者默认为 unimplemented!
)。
为了简化示例,我们将创建相关 serde
特性的简化版本。
#![feature(min_specialization)]
use specialized_dispatch::specialized_dispatch;
/// A simplified version of `serde::de::Deserializer`.
trait Deserializer<'de> {
type Error;
// Some generic deserializer functions...
}
/// A simplified version of `serde::de::Deserialize`.
trait Deserialize<'de>: Sized {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>;
}
/// The node type we want to deserialize.
#[derive(Debug)]
struct MyAwesomeNode;
/// Our custom deserializer.
struct MyAwesomeDeserializer;
impl MyAwesomeDeserializer {
fn my_awesome_function(&mut self) -> MyAwesomeNode {
MyAwesomeNode
}
}
impl Deserializer<'_> for MyAwesomeDeserializer {
type Error = ();
// Implement the generic deserializer functions...
}
impl<'de> Deserialize<'de> for MyAwesomeNode {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(specialized_dispatch! {
D -> MyAwesomeNode,
// TODO(ozars): This causes rustc ICE.
// default fn <'de, T: Deserializer<'de>>(_deserializer: T) => {
default fn <T>(_deserializer: T) => {
unimplemented!()
},
fn (mut deserializer: MyAwesomeDeserializer) => {
deserializer.my_awesome_function()
},
deserializer
})
}
}
fn main() {
println!("{:?}", MyAwesomeNode::deserialize(MyAwesomeDeserializer));
}
上面的示例被包含在存储库中。[链接](https://github.com/ozars/specialized-dispatch/blob/80bbec938876b220ebecf00695acaaa69b01618c/examples/serdelike_example.rs)。可以使用 cargo run --example serdelike_example
来运行或使用 cargo-expand
来检查。
限制
需要 nightly 版本
这是因为依赖于 min_specialization
功能。
仅支持具体类型进行特殊化
只能使用具体类型进行特殊化(例如,子特质不能用于特殊化)。这是从 min_specialization
功能当前实现继承的一个现有限制。
变量不会被自动捕获
宏将其臂展开为某些方法实现。因此,它不能引用其调用作用域中的其他变量。
然而,当在宏中显式声明时,可以传递额外参数。请参阅传递额外参数部分。
与生存期的兼容性不佳
我在各个地方尝试实现生存期的支持,但遇到了一些编译器错误,在某些情况下甚至出现了内部编译器错误(ICE)。请参阅高级 Serdelike 示例中的 TODO。
这很可能是因为底层的 min_specialization
实现还不够成熟,尽管也有可能我在某个地方搞错了(如果你找到了问题,请提交一个问题:P)。
依赖项
~265–710KB
~17K SLoC