20个不稳定版本 (8个破坏性更新)

0.10.0 2023年9月8日
0.9.0 2023年6月29日
0.8.0 2023年2月7日
0.6.2 2022年12月16日
0.3.0 2022年3月31日

#105 in 进程宏

Download history 2634/week @ 2024-04-22 1855/week @ 2024-04-29 2250/week @ 2024-05-06 2344/week @ 2024-05-13 1886/week @ 2024-05-20 3024/week @ 2024-05-27 3237/week @ 2024-06-03 3822/week @ 2024-06-10 2679/week @ 2024-06-17 2481/week @ 2024-06-24 2977/week @ 2024-07-01 2679/week @ 2024-07-08 2494/week @ 2024-07-15 3175/week @ 2024-07-22 3071/week @ 2024-07-29 2556/week @ 2024-08-05

每月11,402次下载
用于 58 个crates (11 直接使用)

MIT/Apache

165KB
3K SLoC

Impl-tools

Test Status Latest version API Minimum rustc version

一组辅助宏

Autoimpl

#[autoimpl]#[derive] 的部分替代品,支持

  • 泛型参数上的显式 where 子句
  • 泛型参数上没有隐式约束,超出类型所需之外
  • 通过使用命名字段实现 Deref 的特性
  • Debug 这样的特性可能 ignore 命名字段

#[autoimpl] 还可以用于特性定义,以实现支持 Deref 的特定类型。

替代方案不同,#[autoimpl] 具有最小化和直观的语法。

use impl_tools::autoimpl;
use std::fmt::Debug;

// Impl Animal for Box<T> where T: Animal + ?Sized
#[autoimpl(for<T: trait + ?Sized> Box<T>)]
trait Animal {
    fn number_of_legs(&self) -> u32;
}

// Impl Debug for Named<T, A: Animal> omitting field animal from output
#[autoimpl(Debug ignore self.animal where T: Debug)]
// Impl Deref and DerefMut to field animal for Named<T, A: Animal>
#[autoimpl(Deref, DerefMut using self.animal)]
struct Named<T, A: Animal> {
    name: T,
    animal: A,
}

fn main() {
    struct Fish;
    impl Animal for Fish {
        fn number_of_legs(&self) -> u32 {
            0
        }
    }

    let my_fish = Named {
        name: "Nemo",
        animal: Box::new(Fish),
    };

    assert_eq!(
        format!("{my_fish:?} has {} legs!", my_fish.number_of_legs()),
        r#"Named { name: "Nemo", .. } has 0 legs!"#
    );
}

新类型包装器

新类型上的 Deref 和特性上的特性重实现组合允许简洁的新类型模式

use impl_tools::autoimpl;
use std::sync::Arc;

// Impl Foo for &T, &mut T and Arc<T>
#[autoimpl(for<T: trait + ?Sized> &T, &mut T, Arc<T>)]
// Optional: impl Foo for NewFoo (requires NewFoo: Deref<Target = T>)
#[autoimpl(for<T: trait> NewFoo<T>)]
pub trait Foo {
    fn success(&self) -> bool;
}

// Impl Deref and DerefMut to a Target which itself supports Foo
#[autoimpl(Deref<Target = T>, DerefMut using self.0)]
pub struct NewFoo<T: Foo>(T);

// Impl Deref and DerefMut to a Target which itself supports Foo
#[autoimpl(Deref<Target = dyn Foo>, DerefMut using self.0)]
pub struct ArcDynFoo(Arc<dyn Foo>);

#[test]
fn test_foo_newtypes() {
    struct Success;
    impl Foo for Success {
        fn success(&self) -> bool { true }
    }

    // We can now directly call Foo's methods on the wrapper:
    assert!(NewFoo(Success).success());
    assert!(ArcDynFoo(Arc::new(Success)).success());
}

有关此模式更多变体的信息,请参阅 tests/newtype.rs

实现 Default

#[impl_default] 实现 std::default::Default

#[impl_tools::impl_default(Tree::Ash)]
enum Tree { Ash, Beech, Birch, Willow }

impl_tools::impl_scope! {
    #[impl_default]
    struct Copse {
        tree_type: Tree,
        number: u32 = 7,
    }
}

注意:无论是否导入,#[impl_default] 都会在 impl_scope! 内匹配。

实现作用域

impl_scope! 是一个类似函数的宏,用于定义一个类型及其实现。它支持 impl Self 语法。

use std::fmt::Display;

impl_tools::impl_scope! {
    /// I don't know why this exists
    pub struct NamedThing<T: Display, F> {
        name: T,
        func: F,
    }

    // Repeats generic parameters of type
    impl Self {
        fn format_name(&self) -> String {
            format!("{}", self.name)
        }
    }

    // Merges generic parameters of type
    impl<O> Self where F: Fn(&str) -> O {
        fn invoke(&self) -> O {
            (self.func)(&self.format_name())
        }
    }
}

注意事项:当前 rustfmt 不会修改其内容。希望 这个问题可以被修复

匿名实现

impl_anon! 是一个类似函数的宏,用于构建一个带有自定义实现的单次使用的结构体(类似:RFC#2604)。

示例

use std::fmt;
fn main() {
    let world = "world";
    let says_hello_world = impl_tools::impl_anon! {
        struct(&'static str = world);
        impl fmt::Display for Self {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "hello {}", self.0)
            }
        }
    };
    assert_eq!(format!("{}", says_hello_world), "hello world");
}

可扩展性

Rust 的 #[derive] 宏可以通过 #[proc_macro_derive]proc-macro 包中扩展。我们的宏不能以相同的方式扩展,但可以通过新的前端扩展。

  1. impl-tools 包的副本创建一个新的“前端”(proc-macro 包)。这个包只在 impl-tools-lib 包的基础上包含很少的代码。
  2. 要扩展 #[autoimpl],编写 ImplTrait 的实现并将其添加到属性的定义中。要扩展 impl_scope!,编写 ScopeAttr 的实现并将其添加到宏的定义中。
  3. 依赖您的新前端包,而不是 impl-tools

关于此方法的示例,请参阅 kas-macros

支持的 Rust 版本

最低支持版本为 1.58.0。

当使用足够新的编译器版本(可能是 1.65.0)时,支持泛型关联类型(仅适用于使用 GAT 的特定义义上的 #[autoimpl])。

替代方案

派生替代方案

EDuce 和 Derivative 都具有类似的功能:能够以比 libstd 的 #[derive] 更多的灵活性实现标准特性。

相比之下,impl-tools 的 #[autoimpl] 语法更简洁,但灵活性较低。

#[derive(Derivative)]
#[derivative(PartialEq, Eq)]
struct Foo<S, T: ?Sized> {
    foo: S,
    #[derivative(PartialEq="ignore")]
    bar: u8,
    #[derivative(PartialEq(bound=""), Eq(bound=""))]
    ptr: *const T,
}

#[derive(Educe)]
#[educe(PartialEq(bound = "S: PartialEq"), Eq(bound = "S: Eq"))]
struct Foo<S, T: ?Sized> {
    foo: S,
    #[educe(PartialEq(ignore))]
    bar: u8,
    ptr: *const T,
}

// impl-tools:
#[autoimpl(PartialEq, Eq ignore self.bar where S: trait)]
struct Foo<S, T: ?Sized> {
    foo: S,
    bar: u8,
    ptr: *const T,
}

注意:默认情况下,#[derive]Derivative 在泛型参数上添加类似于 S: PartialEq, T: PartialEq 的限制;而 Educeimpl-tools 不添加。

派生扩展

derive_more 并非一个“替代品”,它仅仅支持为更多标准特质(如 AddFrom)使用 #[derive]。目前这不被 #[autoimpl](或据我所知,任何替代品)所支持。

auto_impl 允许为引用类型(&&mutBoxRcArc)以及函数类型实现特质。前者(引用类型)被 #[autoimpl](且稍微更通用)所支持。

// auto_impl:
#[auto_impl(&, Box)]
trait Foo {
    fn foo(&self);
}

// impl-tools:
#[autoimpl(for<T: trait + ?Sized> &T, Box<T>)]
trait Foo {
    fn foo(&self);
}

COPYRIGHT 文件列出了在此项目上声称拥有版权的贡献者名单。此列表可能不完整;新贡献者可以选择性地将自己添加到此列表中。

impl-tools 库在 Apache 许可证 2.0 版的条款下发布。您可以从 LICENSE 文件或以下网页获取此许可证的副本: https://apache.ac.cn/licenses/LICENSE-2.0

依赖项

~305–760KB
~18K SLoC