perfect_derive/lib.rs
1#![deny(missing_docs)]
2
3/*!
4Adds derive macros for better bounds on generated Copy, Debug, etc. implementations.
5
6See https://smallcultfollowing.com/babysteps//blog/2022/04/12/implied-bounds-and-perfect-derive/ for a summary of the issue.
7 */
8
9mod impls;
10mod perfect_macro;
11mod perfect_parsing;
12use crate::perfect_parsing::DerivedList;
13use crate::perfect_parsing::StructOrEnum;
14
15use proc_macro::TokenStream;
16use syn::parse_macro_input;
17
18/// In most trivial cases, acts exactly like a typical `#[derive(...)]` macro, however
19/// the bounds generated by this macro are "perfect", in that they only require the minimum requirement
20/// to function.
21///
22/// # Usage
23///
24/// To use this macro, simply augment a `#[derive(...)]` call with a `#[perfect_derive(...)]` call.
25/// For non-supported derived types, you must still use `#[derive(...)]`. This results in code that
26/// looks like the following:
27///
28/// ```rust
29/// # use std::rc::Rc;
30/// # use perfect_derive::perfect_derive;
31///
32/// #[derive(thiserror::Error)]
33/// #[perfect_derive(Clone, Debug)]
34/// enum MyError<T> {
35/// E1(Rc<T>)
36/// }
37/// ```
38///
39/// # Details
40///
41/// This macro supports `Eq`, `PartialEq`, `Ord`, `PartialOrd`, `Clone`, `Copy`, `Hash`, `Default`, and `Debug`.
42///
43/// For all bar `Default`, all data in the `struct` or `enum` must satisfy the bound. For `Default` on `enum`s,
44/// only the data stored in the default enum must satisfy the `Default` trait bound.
45#[proc_macro_attribute]
46pub fn perfect_derive(attr: TokenStream, item: TokenStream) -> TokenStream {
47 let traits = parse_macro_input!(attr as DerivedList);
48 let obj = parse_macro_input!(item as StructOrEnum);
49
50 TokenStream::from(perfect_macro::impl_traits(traits, obj))
51}