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 进程宏
每月11,402次下载
用于 58 个crates (11 直接使用)
165KB
3K SLoC
Impl-tools
一组辅助宏
宏
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
包中扩展。我们的宏不能以相同的方式扩展,但可以通过新的前端扩展。
- 将
impl-tools
包的副本创建一个新的“前端”(proc-macro
包)。这个包只在impl-tools-lib
包的基础上包含很少的代码。 - 要扩展
#[autoimpl]
,编写ImplTrait
的实现并将其添加到属性的定义中。要扩展impl_scope!
,编写ScopeAttr
的实现并将其添加到宏的定义中。 - 依赖您的新前端包,而不是
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
的限制;而 Educe
和 impl-tools
不添加。
派生扩展
derive_more 并非一个“替代品”,它仅仅支持为更多标准特质(如 Add
和 From
)使用 #[derive]
。目前这不被 #[autoimpl]
(或据我所知,任何替代品)所支持。
auto_impl 允许为引用类型(&
,&mut
,Box
,Rc
,Arc
)以及函数类型实现特质。前者(引用类型)被 #[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