trait_aliases/
lib.rs

1//! Trait aliases.
2//!
3//! The core functionality is provided by the [`trait_aliases!`] procedural macro.
4//!
5//! # Example
6//!
7//! Ever felt tired of writing `T: Send + Sync + 'static` over and over when working with `async`
8//! in multi-threaded scenarios? Simply define an alias without blanket implementation boilerplate!
9//!
10//! ```
11//! use trait_aliases::trait_aliases;
12//!
13//! trait_aliases! {
14//!     /// Working in multi-threaded `async` contexts often requires these.
15//!     pub trait SSS = Send + Sync + 'static;
16//! }
17//! ```
18//!
19//! This crate will generate the `SSS` trait with the provided bounds, and implement it for any type
20//! satisfying them:
21//!
22//! ```
23//! /// Working in multi-threaded `async` contexts often requires these.
24//! pub trait SSS: Send + Sync + 'static {}
25//!
26//! /// Blanket implementation of [`SSS`] for all types satisfying its bounds.
27//! impl<__T> SSS for __T where __T: Send + Sync + 'static + ?Sized {}
28//! ```
29//!
30//! # Generic
31//!
32//! Defining generic trait aliases is also supported:
33//!
34//! ```
35//! use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
36//!
37//! use trait_aliases::trait_aliases;
38//!
39//! /// Defines an additive identity element for [`Self`].
40//! pub trait Zero: Add<Output = Self> + Sized {
41//!     /// The identity element of [`Self`], `0`.
42//!     const ZERO: Self;
43//!
44//!     /// Returns [`true`] if `self` is equal to the additive identity.
45//!     fn is_zero(&self) -> bool;
46//! }
47//!
48//! /// Defines a multiplicative identity element for [`Self`].
49//! pub trait One: Mul<Output = Self> + Sized {
50//!     /// The multiplicative identity of [`Self`], `1`.
51//!     const ONE: Self;
52//!
53//!     /// Returns [`true`] if `self` is equal to the multiplicative identity.
54//!     fn is_one(&self) -> bool;
55//! }
56//!
57//! trait_aliases! {
58//!     /// Represents types implementing basic numeric operations.
59//!     pub trait NumOps<R = Self, T = Self> =
60//!         Add<R, Output = T>
61//!         + Sub<R, Output = T>
62//!         + Mul<R, Output = T>
63//!         + Div<R, Output = T>
64//!         + Rem<R, Output = T>;
65//!
66//!     /// Represents types implementing numeric assignment operations.
67//!     pub trait NumAssignOps<R = Self> =
68//!         AddAssign<R> + SubAssign<R> + MulAssign<R> + DivAssign<R> + RemAssign<R>;
69//!
70//!     /// Represents numeric types that have `0` and `1` values, can be compared for equality
71//!     /// and operated on.
72//!     pub trait Num = PartialEq + Zero + One + NumOps;
73//!
74//!     /// Represents [`Num`] types which also implement assignment operations.
75//!     pub trait NumAssign = Num + NumAssignOps;
76//!
77//!     /// Represents [`Num`] types which also implement numeric operations taking
78//!     /// the right-hand side operand by reference.
79//!     pub trait NumRef = Num + for<'r> NumOps<&'r Self>;
80//!
81//!     /// Represents [`NumAssign`] types which also implement numeric assignment by reference.
82//!     pub trait NumAssignRef = NumAssign + for<'r> NumAssignOps<&'r Self>;
83//! }
84//! ```
85//!
86//! # Attributes
87//!
88//! Any attributes applied to the trait alias will be copied to both the generated trait definition
89//! and its blanket implementation, except for documentation comments which are only applied to the
90//! trait definition.
91//!
92//! So, for instance, using `#[cfg]` attributes:
93//!
94//! ```
95//! use core::hash::Hash;
96//!
97//! #[cfg(feature = "serde")]
98//! use serde::{Deserialize, Serialize};
99//!
100//! use trait_aliases::trait_aliases;
101//!
102//! trait_aliases! {
103//!     /// Represents base identifier bounds.
104//!     pub trait BaseId = Copy + Ord + Hash;
105//!
106//!     /// Represents types that can be serialized and deserialized.
107//!     #[cfg(feature = "serde")]
108//!     pub trait Serializable = Serialize + for<'de> Deserialize<'de>;
109//!
110//!     /// Represents identifier types.
111//!     #[cfg(feature = "serde")]
112//!     pub trait Id = BaseId + Serializable;
113//!
114//!     /// Represents identifier types.
115//!     #[cfg(not(feature = "serde"))]
116//!     pub trait Id = BaseId;
117//! }
118//! ```
119//!
120//! Which will generate the following code with `serde` enabled:
121//!
122//! ```ignore
123//! use core::hash::Hash;
124//!
125//! use serde::{Deserialize, Serialize};
126//!
127//! /// Represents base identifier bounds.
128//! trait BaseId: Copy + Ord + Hash {}
129//!
130//! /// Blanket implementation of [`BaseId`] for all types satisfying its bounds.
131//! impl<__T> BaseId for __T where __T: Copy + Ord + Hash + ?Sized {}
132//!
133//! /// Represents types that can be serialized and deserialized.
134//! trait Serializable: Serialize + for<'de> Deserialize<'de> {}
135//!
136//! /// Blanket implementation of [`Serializable`] for all types satisfying its bounds.
137//! impl<__T> Serializable for __T where __T: Serialize + for<'de> Deserialize<'de> + ?Sized {}
138//!
139//! /// Represents identifier types.
140//! trait Id: BaseId + Serializable {}
141//!
142//! /// Blanket implementation of [`Id`] for all types satisfying its bounds.
143//! impl<__T> Id for __T where __T: BaseId + Serializable + ?Sized {}
144//! ```
145//!
146//! And without it:
147//!
148//! ```
149//! use core::hash::Hash;
150//!
151//! /// Represents base identifier bounds.
152//! trait BaseId: Copy + Ord + Hash {}
153//!
154//! /// Blanket implementation of [`BaseId`] for all types satisfying its bounds.
155//! impl<__T> BaseId for __T where __T: Copy + Ord + Hash + ?Sized {}
156//!
157//! /// Represents identifier types.
158//! trait Id: BaseId {}
159//!
160//! /// Blanket implementation of [`Id`] for all types satisfying its bounds.
161//! impl<__T> Id for __T where __T: BaseId + ?Sized {}
162//! ```
163//!
164//! # Note
165//!
166//! Please *never* use `__T` in your generic parameters, as it is reserved for the
167//! blanket implementation.
168//!
169//! Failing to do so will result in collisions at best, and hard-to-debug errors,
170//! migraines or even spontaneous combustion at worst.
171
172use proc_macro::TokenStream;
173use syn::parse_macro_input;
174
175mod generate;
176mod parse;
177
178/// Defines trait aliases with blanket implementations.
179///
180/// See the [crate-level] documentation for more details.
181///
182/// [crate-level]: crate
183#[proc_macro]
184pub fn trait_aliases(tokens: TokenStream) -> TokenStream {
185    let input = parse_macro_input!(tokens as parse::TraitAliases);
186
187    generate::trait_aliases(&input).into()
188}