#traits #macro-derive #proc-macro-attributes #attributes #impl

blanket

一个简单的宏,用于为您的特质生成泛型实现

8 个不稳定版本 (3 个重大更改)

0.4.0 2024 年 3 月 4 日
0.3.0 2023 年 6 月 19 日
0.2.0 2021 年 6 月 5 日
0.1.5 2021 年 5 月 30 日
0.1.2 2020 年 7 月 23 日

#302 in Rust 模式

Download history 2109/week @ 2024-03-13 2953/week @ 2024-03-20 2074/week @ 2024-03-27 2239/week @ 2024-04-03 2119/week @ 2024-04-10 1616/week @ 2024-04-17 1977/week @ 2024-04-24 1898/week @ 2024-05-01 1583/week @ 2024-05-08 1928/week @ 2024-05-15 1728/week @ 2024-05-22 1991/week @ 2024-05-29 1651/week @ 2024-06-05 2266/week @ 2024-06-12 3018/week @ 2024-06-19 2553/week @ 2024-06-26

9,895 每月下载次数
用于 76 个crate (7 个直接使用)

MIT 许可证

86KB
2K SLoC

🧣 blanket Star me

一个简单的宏,用于为您的特质生成泛型实现。

Actions Codecov License Source Crate Documentation Changelog GitHub issues

🔍 概述

Rust 标准库中有很多特质,但它们在与新类型集成方面的表现尤为出色。为类型 W 声明 std::io::Write 的实现,您也会得到 &mut WBox<W> 的实现!然而,这会转化为大量的模板代码,难以维护,这也是为什么许多crate不愿意提供相同的便利实现。

这就是 blanket 的用武之地!这个crate帮助您用尽可能少的额外代码为自己的特质生成相同的泛型实现:事实上,这几乎与为 trait 项的 derive 宏看起来一样。

🔌 使用方法

blanket 导出一个同名的属性宏,在将crate添加到 Cargo.toml 依赖项之后可以简单地导入

extern crate blanket;
use blanket::blanket;

#[blanket(derive(...))]

使用此宏属性为特性行为生成一个通用的实现,前提是特性行为的方法符合该衍生约束,例如只声明具有&self&mut self作为接收者的方法。以下是一些可用的衍生类型:

衍生类型 实现块 fn (&self) fn (&mut self) fn (self)
Ref impl<T:Trait+ ?Sized> Trait for &T ✔️
Rc impl<T:Trait+ ?Sized> Trait for Rc<T> ✔️
Arc impl<T:Trait+ ?Sized> Trait for Arc<T> ✔️
Mut impl<T:Trait+ ?Sized> Trait for &mut T ✔️ ✔️
Box¹ impl<T:Trait+ ?Sized> Trait for Box<T> ✔️ ✔️
Box² impl<T:Trait>Traitfor Box<T> ✔️ ✔️ ✔️
Cow impl<T:Trait+ ToOwned + ?Sized> Trait for Cow<_, T> ✔️

例如,使用我们自己的版本std::fmt::Write,我们可以为Box<impl Write>&mut impl Write提供实现。

extern crate blanket;
use blanket::blanket;

#[blanket(derive(Mut, Box))]
pub trait Write {
    fn write_str(&mut self, s: &str) -> std::fmt::Result;
    fn write_char(&mut self, c: char) -> std::fmt::Result {
         self.write_str(c.encode_utf8(&mut [0; 4]))
    }
}

注意,我们无法推导出Ref,因为我们声明的Write特性行为期望可变引用,而我们从不可变引用中无法提供。如果我们尝试这样做,编译器会警告我们。

---- src/lib.rs - (line 55) stdout ----
error: cannot derive `Ref` for a trait declaring `&mut self` methods
 --> src/lib.rs:61:18
  |
8 |     fn write_str(&mut self, s: &str) -> std::fmt::Result;
  |                  ^^^^^^^^^

#[blanket(默认值= "...")]

blanket可以将特性行为的默认实现委托给另一个模块中的函数。这对于一些特性行为,如访问者,非常有用,可以提供一个作为外部函数的默认行为,例如syn::visit所做的那样。

以下示例实现了一个非常简单的访问者特性行为,该行为可以逐字符处理类型为&str的字符串。

extern crate blanket;
use blanket::blanket;

#[blanket(default = "visitor")]
trait Visitor {
    fn visit_string(&self, s: &str);
    fn visit_char(&self, c: char);
}

mod visitor {
    use super::Visitor;

    pub fn visit_string<V: Visitor + ?Sized>(v: &V, s: &str) {
        for c in s.chars() {
            v.visit_char(c);
        }
    }

    pub fn visit_char<V: Visitor + ?Sized>(v: &V, c: char) {}
}

blanket将检查所有方法是否声明时没有默认块,然后为所有声明的方法创建一个默认实现,生成以下代码:

trait Visitor {
    fn visit_string(&self, s: &str) {
      visitor::visit_string(self, s)
    }
    fn visit_char(&self, c: char) {
      visitor::visit_char(self, c)
    }
}

📝 待办事项

  • ✓ 将默认方法委托给外部函数。
  • ✓ 支持泛型参数的特性行为。
  • #[derive(Ref)]
  • #[derive(Mut)]
  • #[derive(Box)]支持有大小和无大小的类型。
  • #[derive(Rc)]
  • #[derive(Arc)]
  • #[derive(Cow)]

🤝 致谢

blanket 由以下人员开发与维护:

以下人员对该项目做出了贡献

📋 变更日志

本项目遵循语义版本控制并提供变更日志,格式遵循保持变更日志

📜 许可证

此库在开源MIT许可证下提供。

依赖项

~275–730KB
~17K SLoC