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}