From 01268943af553bd35c7c443d52cd1dcb38e2f524 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 22 Sep 2022 17:59:49 +0100 Subject: [PATCH 1/4] README: expand section on alternatives --- README.md | 69 +++++++++++++++++++++++++++++++++++++++++------ tests/autoimpl.rs | 19 +++++++++++++ 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index cf52012..476e5e3 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,8 @@ Caveat: `rustfmt` won't currently touch the contents. Hopefully that Extensibility ------------- -Rust's `#[derive]` macro is extensible via `#[proc_macro_derive]` in a `proc-macro` crate. Our macros cannot be extended in the same way, but they can be extended via a new front-end: +Rust's `#[derive]` macro is extensible via `#[proc_macro_derive]` in a `proc-macro` crate. +Our macros cannot be extended in the same way, but they can be extended via a new front-end: 1. Create a copy of the `impl-tools` crate to create a new "front-end" (`proc-macro` crate). This crate is contains only a little code over the [`impl-tools-lib`] crate. @@ -132,31 +133,83 @@ Rust's `#[derive]` macro is extensible via `#[proc_macro_derive]` in a `proc-mac To extend `impl_scope!`, write an impl of [`ScopeAttr`] and add it to the macro's definition. 3. Depend on your new front end crate instead of `impl-tools`. +For an example of this approach, see [kas-macros](https://github.com/kas-gui/kas/tree/master/crates/kas-macros). + [`impl-tools-lib`]: https://docs.rs/impl-tools-lib/ [`ImplTrait`]: https://docs.rs/impl-tools-lib/latest/impl_tools_lib/autoimpl/trait.ImplTrait.html [`ScopeAttr`]: https://docs.rs/impl-tools-lib/latest/impl_tools_lib/trait.ScopeAttr.html + Supported Rust Versions ------------------------------ The MSRV is 1.56.0 for no particular reason other than that it is the first to support Edition 2021. +When using a sufficiently recent compiler version (presumably 1.65.0), generic associated types +are supported (only applicable to `#[autoimpl]` on trait definitions using GATs). + Alternatives ------------ +### Derive alternatives + Both [Educe](https://crates.io/crates/educe) and [Derivative](https://crates.io/crates/derivative) -have similar functionality: the ability to implement various traits with more flexibility than -libstd's `#[derive]`. They also support more functionality such as tweaking the output of `Debug`. -Both have less clean syntax, requiring a minimum of two attributes to do anything, with further -attributes to customise implementations (e.g. to ignore a field). +have similar functionality: the ability to implement standard traits with more flexibility than +libstd's `#[derive]`. + +In comparison, impl-tools' `#[autoimpl]` has cleaner syntax but is less flexible: +```rust,ignore +#[derive(Derivative)] +#[derivative(PartialEq, Eq)] +struct Foo { + 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 { + foo: S, + #[educe(PartialEq(ignore))] + bar: u8, + ptr: *const T, +} + +// impl-tools: +#[autoimpl(PartialEq, Eq ignore self.bar where S: trait)] +struct Foo { + foo: S, + bar: u8, + ptr: *const T, +} +``` + +### Derive extensions [derive_more](https://crates.io/crates/derive_more) isn't exactly an "alternative", simply -supporting `#[derive]` for more standard traits. Possible functionality overlap in the future -(though for now `#[autoimpl]` doesn't support half the traits supported by `#[derive]`). +supporting `#[derive]` for more standard traits such as `Add` and `From`. +This is not (currently) supported by `#[autoimpl]` (or, to my knowledge, any alternative). [auto_impl](https://crates.io/crates/auto_impl/) allows implementing a trait for reference types -(`&`, `&mut`, `Box`, `Rc`, `Arc`) as well as function types. +(`&`, `&mut`, `Box`, `Rc`, `Arc`) as well as function types. The former (reference types) is +supported by `#[autoimpl]` (and is slightly more general): +```rust,ignore +// auto_impl: +#[auto_impl(&, Box)] +trait Foo { + fn foo(&self); +} + +// impl-tools: +#[autoimpl(for &T, Box)] +trait Foo { + fn foo(&self); +} +``` Copyright and Licence diff --git a/tests/autoimpl.rs b/tests/autoimpl.rs index 1641d4e..1f7f925 100644 --- a/tests/autoimpl.rs +++ b/tests/autoimpl.rs @@ -12,6 +12,8 @@ use impl_tools::autoimpl; fn test_has_clone(_: impl Clone) {} fn test_has_copy(_: impl Copy) {} +fn test_has_partial_eq(_foo: impl PartialEq) {} +fn test_has_eq(_foo: impl Eq) {} #[autoimpl(std::clone::Clone, core::fmt::Debug)] struct Unit; @@ -153,3 +155,20 @@ fn xx_hash_64_0(x: impl core::hash::Hash) -> u64 { x.hash(&mut hasher); core::hash::Hasher::finish(&hasher) } + +#[allow(unused)] +#[autoimpl(PartialEq, Eq ignore self.bar where S: trait)] +struct Foo { + foo: S, + bar: u8, + ptr: *const T, +} +#[test] +fn foo() { + let x = || 1; + let ptr = &x as *const _; + test_has_partial_eq(Foo { foo: 1f32, bar: 0, ptr }); + // Expected to fail: + // test_has_eq(Foo { foo: 1f32, bar: 0, ptr }); + test_has_eq(Foo { foo: 1i32, bar: 0, ptr }); +} From ea583d3c3935b1bb07f40b02b1ca154647b05f2f Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 22 Sep 2022 17:59:57 +0100 Subject: [PATCH 2/4] Changelog: prepare for 0.5.0 --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 521bffd..23ce03d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.5.0] — 2022-09-?? +## [0.5.0] — 2022-09-22 - `#[autoimpl]` on traits now merges trait generics with macro generics (#21) +- `lib::autoimpl::struct_items` returns the trait path in addition to impl items (#22) +- Add `lib::autoimpl::ImplArgs::for_fields`, `for_fields_iter` (#22) +- Add autoimpl support for `Copy`, `AsRef`, `AsMut`, `Borrow`, `BorrowMut`, + `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Hash` (#22) +- Add `#[automatically_derived]` annotation to generated impls (#22) ## [0.4.4] — 2022-09-19 From 9ed36bdd56eb0d9ebda264eb1410612d81ce1b05 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 22 Sep 2022 18:13:42 +0100 Subject: [PATCH 3/4] README: add note --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 476e5e3..3112148 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,8 @@ struct Foo { } ``` +Note: `#[derive]` and `Derivative` add bounds like `S: PartialEq, T: PartialEq` on generic parameters by default; `Educe` and `impl-tools` do not. + ### Derive extensions [derive_more](https://crates.io/crates/derive_more) isn't exactly an "alternative", simply From bfc37c8fdb6decb72d4d96747c9d566d4218e482 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Thu, 22 Sep 2022 18:14:14 +0100 Subject: [PATCH 4/4] Rustfmt fix --- tests/autoimpl.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/autoimpl.rs b/tests/autoimpl.rs index 1f7f925..291ad46 100644 --- a/tests/autoimpl.rs +++ b/tests/autoimpl.rs @@ -167,8 +167,16 @@ struct Foo { fn foo() { let x = || 1; let ptr = &x as *const _; - test_has_partial_eq(Foo { foo: 1f32, bar: 0, ptr }); + test_has_partial_eq(Foo { + foo: 1f32, + bar: 0, + ptr, + }); // Expected to fail: // test_has_eq(Foo { foo: 1f32, bar: 0, ptr }); - test_has_eq(Foo { foo: 1i32, bar: 0, ptr }); + test_has_eq(Foo { + foo: 1i32, + bar: 0, + ptr, + }); }