trait-aliases 0.3.0

Trait aliases.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
//! Trait aliases.
//!
//! The core functionality is provided by the [`trait_aliases!`] procedural macro.
//!
//! # Example
//!
//! Ever felt tired of writing `T: Send + Sync + 'static` over and over when working with `async`
//! in multi-threaded scenarios? Simply define an alias without blanket implementation boilerplate!
//!
//! ```
//! use trait_aliases::trait_aliases;
//!
//! trait_aliases! {
//!     /// Working in multi-threaded `async` contexts often requires these.
//!     pub trait SSS = Send + Sync + 'static;
//! }
//! ```
//!
//! This crate will generate the `SSS` trait with the provided bounds, and implement it for any type
//! satisfying them:
//!
//! ```
//! /// Working in multi-threaded `async` contexts often requires these.
//! pub trait SSS: Send + Sync + 'static {}
//!
//! /// Blanket implementation of [`SSS`] for all types satisfying its bounds.
//! impl<__T> SSS for __T where __T: Send + Sync + 'static + ?Sized {}
//! ```
//!
//! # Attribute
//!
//! The [`trait_alias`] attribute can be attached to any trait definition within the
//! input to [`trait_aliases!`]. See the attribute [documentation](trait_alias) for full description.
//!
//! ```
//! use trait_aliases::trait_aliases;
//!
//! trait_aliases! {
//!     /// Working in multi-threaded `async` contexts often requires these.
//!     #[trait_alias(
//!         T,
//!         doc = "Implemented for any type that is [`Send`], [`Sync`] and `'static`",
//!         doc = "(meaning it does not contain non-static lifetimes)."
//!     )]
//!     pub trait SSS = Send + Sync + 'static;
//! }
//! ```
//!
//! Gets expanded to:
//!
//! ```
//! /// Working in multi-threaded `async` contexts often requires these.
//! pub trait SSS: Send + Sync + 'static {}
//!
//! /// Implemented for any type that is [`Send`], [`Sync`] and `'static`
//! /// (meaning it does not contain non-static lifetimes).
//! impl<T> SSS for T where T: Send + Sync + 'static + ?Sized {}
//! ```
//!
//! # Generic
//!
//! Defining generic trait aliases is also supported:
//!
//! ```
//! use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
//!
//! use trait_aliases::trait_aliases;
//!
//! /// Defines an additive identity element for [`Self`].
//! pub trait Zero: Add<Output = Self> + Sized {
//!     /// The identity element of [`Self`], `0`.
//!     const ZERO: Self;
//!
//!     /// Returns [`true`] if `self` is equal to the additive identity.
//!     fn is_zero(&self) -> bool;
//! }
//!
//! /// Defines a multiplicative identity element for [`Self`].
//! pub trait One: Mul<Output = Self> + Sized {
//!     /// The multiplicative identity of [`Self`], `1`.
//!     const ONE: Self;
//!
//!     /// Returns [`true`] if `self` is equal to the multiplicative identity.
//!     fn is_one(&self) -> bool;
//! }
//!
//! trait_aliases! {
//!     /// Represents types implementing basic numeric operations.
//!     #[trait_alias(N)]
//!     pub trait NumOps<R = Self, T = Self> =
//!         Add<R, Output = T>
//!         + Sub<R, Output = T>
//!         + Mul<R, Output = T>
//!         + Div<R, Output = T>
//!         + Rem<R, Output = T>;
//!
//!     /// Represents types implementing numeric assignment operations.
//!     #[trait_alias(N)]
//!     pub trait NumAssignOps<R = Self> =
//!         AddAssign<R> + SubAssign<R> + MulAssign<R> + DivAssign<R> + RemAssign<R>;
//!
//!     /// Represents numeric types that have `0` and `1` values, can be compared for equality
//!     /// and operated on.
//!     #[trait_alias(N)]
//!     pub trait Num = PartialEq + Zero + One + NumOps;
//!
//!     /// Represents [`Num`] types which also implement assignment operations.
//!     #[trait_alias(N)]
//!     pub trait NumAssign = Num + NumAssignOps;
//!
//!     /// Represents [`Num`] types which also implement numeric operations taking
//!     /// the right-hand side operand by reference.
//!     #[trait_alias(N)]
//!     pub trait NumRef = Num + for<'r> NumOps<&'r Self>;
//!
//!     /// Represents [`NumAssign`] types which also implement numeric assignment by reference.
//!     #[trait_alias(N)]
//!     pub trait NumAssignRef = NumAssign + for<'r> NumAssignOps<&'r Self>;
//! }
//! ```
//!
//! # Attributes
//!
//! Any attributes applied to the trait alias will be copied to both the generated trait definition
//! and its blanket implementation, except for documentation comments which are only applied to the
//! trait definition.
//!
//! So, for instance, using `#[cfg]` attributes for conditional compilation:
//!
//! ```
//! use core::hash::Hash;
//!
//! #[cfg(feature = "serde")]
//! use serde::{Deserialize, Serialize};
//!
//! use trait_aliases::trait_aliases;
//!
//! trait_aliases! {
//!     /// Represents base identifier bounds.
//!     #[trait_alias(T)]
//!     pub trait BaseId = Copy + Ord + Hash;
//!
//!     /// Represents types that can be serialized and deserialized.
//!     #[cfg(feature = "serde")]
//!     #[trait_alias(T)]
//!     pub trait Serializable = Serialize + for<'de> Deserialize<'de>;
//!
//!     /// Represents identifier types.
//!     #[cfg(feature = "serde")]
//!     #[trait_alias(T)]
//!     pub trait Id = BaseId + Serializable;
//!
//!     /// Represents identifier types.
//!     #[cfg(not(feature = "serde"))]
//!     #[trait_alias(T)]
//!     pub trait Id = BaseId;
//! }
//! ```
//!
//! Which will generate the following code with `serde` enabled:
//!
//! ```
//! use core::hash::Hash;
//!
//! use serde::{Deserialize, Serialize};
//!
//! /// Represents base identifier bounds.
//! pub trait BaseId: Copy + Ord + Hash {}
//!
//! /// Blanket implementation of [`BaseId`] for all types satisfying its bounds.
//! impl<T> BaseId for T where T: Copy + Ord + Hash + ?Sized {}
//!
//! /// Represents types that can be serialized and deserialized.
//! pub trait Serializable: Serialize + for<'de> Deserialize<'de> {}
//!
//! /// Blanket implementation of [`Serializable`] for all types satisfying its bounds.
//! impl<T> Serializable for T where T: Serialize + for<'de> Deserialize<'de> + ?Sized {}
//!
//! /// Represents identifier types.
//! pub trait Id: BaseId + Serializable {}
//!
//! /// Blanket implementation of [`Id`] for all types satisfying its bounds.
//! impl<T> Id for T where T: BaseId + Serializable + ?Sized {}
//! ```
//!
//! And without it:
//!
//! ```
//! use core::hash::Hash;
//!
//! /// Represents base identifier bounds.
//! pub trait BaseId: Copy + Ord + Hash {}
//!
//! /// Blanket implementation of [`BaseId`] for all types satisfying its bounds.
//! impl<T> BaseId for T where T: Copy + Ord + Hash + ?Sized {}
//!
//! /// Represents identifier types.
//! pub trait Id: BaseId {}
//!
//! /// Blanket implementation of [`Id`] for all types satisfying its bounds.
//! impl<T> Id for T where T: BaseId + ?Sized {}
//! ```
//!
//! # Note
//!
//! The blanket identifier is essential to correct code generation, therefore *any* occurrences
//! of the selected identifier will result in compilation errors.
//!
//! When the identifier is supplied to [`trait_alias`], for instance:
//!
//! ```compile_fail
//! use trait_aliases::trait_aliases;
//!
//! trait_aliases! {
//!     #[trait_alias(T)]
//!     trait Convertible<T> = From<T> + Into<T>;
//! }
//! ```
//!
//! will cause compilation to fail with several errors like:
//!
//! ```text
//! identifier `T` is reserved for blanket implementations
//! ```
//!
//! pointing to every occurrence of `T` within the trait alias definition.
//!
//! Otherwise, the default `__T` is used, therefore examples like:
//!
//! ```compile_fail
//! use trait_aliases::trait_aliases;
//!
//! trait_aliases! {
//!     trait __T = Sized;
//! }
//! ```
//!
//! fail with the following error:
//!
//! ```text
//! error: identifier `__T` is reserved for blanket implementations
//!  --> src/lib.rs
//!   |
//!   |     trait __T = Sized;
//!   |           ^^^
//! ```

use proc_macro::TokenStream;
use syn::{Error, ItemTraitAlias, parse_macro_input};

mod arguments;
mod at_most_one;
mod blanket;
mod context;
mod generate;
mod input;
mod name;
mod parse;

use arguments::Optional;
use input::TraitAliasInput;
use parse::TraitAliases;

/// Defines trait aliases with blanket implementations.
///
/// See [crate-level] documentation for more information.
///
/// [crate-level]: crate
#[proc_macro]
pub fn trait_aliases(tokens: TokenStream) -> TokenStream {
    let mut aliases = parse_macro_input!(tokens as TraitAliases);

    generate::extract_trait_aliases(&mut aliases)
        .unwrap_or_else(Error::into_compile_error)
        .into()
}

/// Defines trait aliases with blanket implementations (attribute).
///
/// This attribute is exported mainly for documentation purposes. It *does* work on recent versions
/// of Rust, however the compiler is going to issue warnings since the feature[^trait_alias] is
/// **unstable** and the syntax can theoretically change, causing breakage.
///
/// # Arguments
///
/// The following sections describe all supported arguments.
///
/// ## Blanket type
///
/// The *blanket type* is the identifier used in blanket implementations of generated traits:
///
/// ```
/// use trait_aliases::trait_alias;
///
/// /// Represents types that are [`Send`], [`Sync`] and `'static`.
/// #[trait_alias(T)]
/// pub trait SSS = Send + Sync + 'static;
/// ```
///
/// Expands to:
///
/// ```
/// /// Represents types that are [`Send`], [`Sync`] and `'static`.
/// pub trait SSS: Send + Sync + 'static {}
///
/// /// Blanket implementation of [`SSS`] for all types satisfying its bounds.
/// impl<T> SSS for T where T: Send + Sync + 'static + ?Sized {}
/// ```
///
/// This argument is *optional*, with `__T` being the default blanket type.
///
/// Repeating the argument will cause compilation to fail:
///
/// ```compile_fail
/// use trait_aliases::trait_alias;
///
/// #[trait_alias(T, U)]
/// pub trait S = Sized;
/// ```
///
/// ```text
/// error: duplicate identifier argument `U`, already set to `T`
///  --> src/lib.rs
///   |
///   | #[trait_alias(T, U)]
///   |                  ^
/// ```
///
/// ## Blanket documentation
///
/// The *blanket documentation* is the expression passed as documentation of blanket
/// implementations:
///
/// ```
/// use core::fmt::{Debug, Display};
///
/// use trait_aliases::trait_alias;
///
/// /// Represents types that are both [`Debug`] and [`Display`].
/// #[trait_alias(doc = "Implemented for any type that is both [`Debug`] and [`Display`].")]
/// pub trait DD = Debug + Display;
/// ```
///
/// Expands to:
///
/// ```
/// use core::fmt::{Debug, Display};
///
/// /// Represents types that are both [`Debug`] and [`Display`].
/// pub trait DD: Debug + Display {}
///
/// /// Implemented for any type that is both [`Debug`] and [`Display`].
/// impl<__T> DD for __T where __T: Debug + Display + ?Sized {}
/// ```
///
/// The `doc` argument can be repeated. Each occurrence is going to add another `#[doc]` attribute
/// to the blanket implementation:
///
/// ```
/// use trait_aliases::trait_alias;
///
/// /// Represents types that are [`Send`], [`Sync`] and `'static`.
/// #[trait_alias(
///     doc = "Implemented for any type that is [`Send`], [`Sync`] and `'static`",
///     doc = "(meaning it does not contain non-static lifetimes)."
/// )]
/// pub trait SSS = Send + Sync + 'static;
/// ```
///
/// Expands to:
///
/// ```
/// /// Represents types that are [`Send`], [`Sync`] and `'static`.
/// pub trait SSS: Send + Sync + 'static {}
///
/// /// Implemented for any type that is [`Send`], [`Sync`] and `'static`
/// /// (meaning it does not contain non-static lifetimes).
/// impl<__T> SSS for __T where __T: Send + Sync + 'static + ?Sized {}
/// ```
///
/// This argument is optional; the default blanket documentation is generated as detailed below.
///
/// ### Generated
///
/// For some trait alias `Alias`, the default blanket documentation is:
///
/// ```text
/// Blanket implementation of [`Alias`] for all types satisfying its bounds.
/// ```
///
/// # Combined
///
/// ```
/// use trait_aliases::trait_alias;
///
/// /// Represents types that are convertible from and into `T`.
/// #[trait_alias(U, doc = "Implementation for all types convertible from and into `T`.")]
/// pub trait Convertible<T> = From<T> + Into<T>;
/// ```
///
/// Expands to:
///
/// ```
/// /// Represents types that are convertible from and into `T`.
/// trait Convertible<T>: From<T> + Into<T> {}
///
/// /// Implementation for all types convertible from and into `T`.
/// impl<T, U> Convertible<T> for U where U: From<T> + Into<T> + ?Sized {}
/// ```
///
/// # Syntax
///
/// Finally, the overall syntax is either `#[trait_alias]` or `#[trait_alias(...)]`, where the
/// arguments can be:
///
/// | `arguments`        | `blanket_type` | `blanket_docs`            |
/// |--------------------|----------------|---------------------------|
/// | `()`               | `__T`          | [*generated*](#generated) |
/// | `(T)`              | `T`            | [*generated*](#generated) |
/// | `(doc = "...")`    | `__T`          | `...`                     |
/// | `(T, doc = "...")` | `T`            | `...`                     |
/// | `(doc = "...", T)` | `T`            | `...`                     |
///
/// [^trait_alias]: [`trait_alias`](https://rust-lang.github.io/rfcs/1733-trait-alias.html) RFC.
#[proc_macro_attribute]
pub fn trait_alias(tokens: TokenStream, item: TokenStream) -> TokenStream {
    let optional = parse_macro_input!(tokens as Optional);
    let alias = parse_macro_input!(item as ItemTraitAlias);

    let input = TraitAliasInput::new(optional, &alias);

    generate::trait_alias(input)
        .unwrap_or_else(Error::into_compile_error)
        .into()
}