1 | //! # `derive_more` |
2 | //! |
3 | //! [![Build Status](https://github.com/JelteF/derive_more/workflows/CI/badge.svg)](https://github.com/JelteF/derive_more/actions) |
4 | //! [![Latest Version](https://img.shields.io/crates/v/derive_more.svg)](https://crates.io/crates/derive_more) |
5 | //! [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://jeltef.github.io/derive_more/derive_more/) |
6 | //! [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/JelteF/derive_more/master/LICENSE) |
7 | //! [![Rust 1.36+](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://blog.rust-lang.org/2019/07/04/Rust-1.36.0.html) |
8 | //! |
9 | //! Rust has lots of builtin traits that are implemented for its basic types, such |
10 | //! as `Add`, `Not`, `From` or `Display`. |
11 | //! However, when wrapping these types inside your own structs or enums you lose the |
12 | //! implementations of these traits and are required to recreate them. |
13 | //! This is especially annoying when your own structures are very simple, such as |
14 | //! when using the commonly advised newtype pattern (e.g. `MyInt(i32)`). |
15 | //! |
16 | //! This library tries to remove these annoyances and the corresponding boilerplate code. |
17 | //! It does this by allowing you to derive lots of commonly used traits for both structs and enums. |
18 | //! |
19 | //! ## Example code |
20 | //! |
21 | //! By using this library the following code just works: |
22 | //! |
23 | //! ```rust |
24 | //! extern crate derive_more; |
25 | //! use derive_more::{Add, Display, From, Into}; |
26 | //! |
27 | //! #[derive(PartialEq, From, Add)] |
28 | //! struct MyInt(i32); |
29 | //! |
30 | //! #[derive(PartialEq, From, Into)] |
31 | //! struct Point2D { |
32 | //! x: i32, |
33 | //! y: i32, |
34 | //! } |
35 | //! |
36 | //! #[derive(PartialEq, From, Add, Display)] |
37 | //! enum MyEnum { |
38 | //! #[display(fmt = "int: {}" , _0)] |
39 | //! Int(i32), |
40 | //! Uint(u32), |
41 | //! #[display(fmt = "nothing" )] |
42 | //! Nothing, |
43 | //! } |
44 | //! |
45 | //! assert!(MyInt(11) == MyInt(5) + 6.into()); |
46 | //! assert!((5, 6) == Point2D { x: 5, y: 6 }.into()); |
47 | //! assert!(MyEnum::Int(15) == (MyEnum::Int(8) + 7.into()).unwrap()); |
48 | //! assert!(MyEnum::Int(15).to_string() == "int: 15" ); |
49 | //! assert!(MyEnum::Uint(42).to_string() == "42" ); |
50 | //! assert!(MyEnum::Nothing.to_string() == "nothing" ); |
51 | //! ``` |
52 | //! |
53 | //! ## The derivable traits |
54 | //! |
55 | //! Below are all the traits that you can derive using this library. |
56 | //! Some trait derivations are so similar that the further documentation will only show a single one |
57 | //! of them. |
58 | //! You can recognize these by the "-like" suffix in their name. |
59 | //! The trait name before that will be the only one that is used throughout the further |
60 | //! documentation. |
61 | //! |
62 | //! It is important to understand what code gets generated when using one of the |
63 | //! derives from this crate. |
64 | //! That is why the links below explain what code gets generated for a trait for |
65 | //! each group from before. |
66 | //! |
67 | //! You can use the [`cargo-expand`] utility to see the exact code that is generated |
68 | //! for your specific type. |
69 | //! This will show you your code with all macros and derives expanded. |
70 | //! |
71 | //! **NOTE**: You still have to derive each trait separately. So `#[derive(Mul)]` doesn't |
72 | //! automatically derive `Div` as well. To derive both you should do `#[derive(Mul, Div)]` |
73 | //! |
74 | //! ### Conversion traits |
75 | //! |
76 | //! These are traits that are used to convert automatically between types. |
77 | //! |
78 | //! 1. [`From`] |
79 | //! 2. [`Into`] |
80 | //! 3. [`FromStr`] |
81 | //! 4. [`TryInto`] |
82 | //! 5. [`IntoIterator`] |
83 | //! 6. [`AsRef`] |
84 | //! 7. [`AsMut`] |
85 | //! |
86 | //! ### Formatting traits |
87 | //! |
88 | //! These traits are used for converting a struct to a string in different ways. |
89 | //! |
90 | //! 1. [`Display`-like], contains `Display`, `Binary`, `Octal`, `LowerHex`, |
91 | //! `UpperHex`, `LowerExp`, `UpperExp`, `Pointer` |
92 | //! |
93 | //! ### Error-handling traits |
94 | //! These traits are used to define error-types. |
95 | //! |
96 | //! 1. [`Error`] |
97 | //! |
98 | //! ### Operators |
99 | //! |
100 | //! These are traits that can be used for operator overloading. |
101 | //! |
102 | //! 1. [`Index`] |
103 | //! 2. [`Deref`] |
104 | //! 3. [`Not`-like], contains `Not` and `Neg` |
105 | //! 4. [`Add`-like], contains `Add`, `Sub`, `BitAnd`, `BitOr`, `BitXor` |
106 | //! 5. [`Mul`-like], contains `Mul`, `Div`, `Rem`, `Shr` and `Shl` |
107 | //! 3. [`Sum`-like], contains `Sum` and `Product` |
108 | //! 6. [`IndexMut`] |
109 | //! 7. [`DerefMut`] |
110 | //! 8. [`AddAssign`-like], contains `AddAssign`, `SubAssign`, `BitAndAssign`, |
111 | //! `BitOrAssign` and `BitXorAssign` |
112 | //! 9. [`MulAssign`-like], contains `MulAssign`, `DivAssign`, `RemAssign`, |
113 | //! `ShrAssign` and `ShlAssign` |
114 | //! |
115 | //! ### Static methods |
116 | //! |
117 | //! These don't derive traits, but derive static methods instead. |
118 | //! |
119 | //! 1. [`Constructor`], this derives a `new` method that can be used as a constructor. |
120 | //! This is very basic if you need more customization for your constructor, check |
121 | //! out the [`derive-new`] crate. |
122 | //! 2. [`IsVariant`], for each variant `foo` of an enum type, derives a `is_foo` method. |
123 | //! 3. [`Unwrap`], for each variant `foo` of an enum type, derives an `unwrap_foo` method. |
124 | //! |
125 | //! ## Generated code |
126 | //! |
127 | //! ## Installation |
128 | //! |
129 | //! This library requires Rust 1.36 or higher and it supports `no_std` out of the box. |
130 | //! Then add the following to `Cargo.toml`: |
131 | //! |
132 | //! ```toml |
133 | //! [dependencies] |
134 | //! derive_more = "0.99.0" |
135 | //! # You can specifiy the types of derives that you need for less time spent |
136 | //! # compiling. For the full list of features see this crate its Cargo.toml. |
137 | //! default-features = false |
138 | //! features = ["from", "add", "iterator"] |
139 | //! ``` |
140 | //! |
141 | //! And this to the top of your Rust file for Rust 2018: |
142 | //! |
143 | //! ```rust |
144 | //! extern crate derive_more; |
145 | //! // use the derives that you want in the file |
146 | //! use derive_more::{Add, Display, From}; |
147 | //! ``` |
148 | //! If you're still using Rust 2015 you should add this instead: |
149 | //! ```rust |
150 | //! extern crate core; |
151 | //! #[macro_use] |
152 | //! extern crate derive_more; |
153 | //! # fn main(){} |
154 | //! ``` |
155 | //! |
156 | //! [`cargo-expand`]: https://github.com/dtolnay/cargo-expand |
157 | //! [`derive-new`]: https://github.com/nrc/derive-new |
158 | //! |
159 | //! [`From`]: https://jeltef.github.io/derive_more/derive_more/from.html |
160 | //! [`Into`]: https://jeltef.github.io/derive_more/derive_more/into.html |
161 | //! [`FromStr`]: https://jeltef.github.io/derive_more/derive_more/from_str.html |
162 | //! [`TryInto`]: https://jeltef.github.io/derive_more/derive_more/try_into.html |
163 | //! [`IntoIterator`]: https://jeltef.github.io/derive_more/derive_more/into_iterator.html |
164 | //! [`AsRef`]: https://jeltef.github.io/derive_more/derive_more/as_ref.html |
165 | //! [`AsMut`]: https://jeltef.github.io/derive_more/derive_more/as_mut.html |
166 | //! |
167 | //! [`Display`-like]: https://jeltef.github.io/derive_more/derive_more/display.html |
168 | //! |
169 | //! [`Error`]: https://jeltef.github.io/derive_more/derive_more/error.html |
170 | //! |
171 | //! [`Index`]: https://jeltef.github.io/derive_more/derive_more/index_op.html |
172 | //! [`Deref`]: https://jeltef.github.io/derive_more/derive_more/deref.html |
173 | //! [`Not`-like]: https://jeltef.github.io/derive_more/derive_more/not.html |
174 | //! [`Add`-like]: https://jeltef.github.io/derive_more/derive_more/add.html |
175 | //! [`Mul`-like]: https://jeltef.github.io/derive_more/derive_more/mul.html |
176 | //! [`Sum`-like]: https://jeltef.github.io/derive_more/derive_more/sum.html |
177 | //! [`IndexMut`]: https://jeltef.github.io/derive_more/derive_more/index_mut.html |
178 | //! [`DerefMut`]: https://jeltef.github.io/derive_more/derive_more/deref_mut.html |
179 | //! [`AddAssign`-like]: https://jeltef.github.io/derive_more/derive_more/add_assign.html |
180 | //! [`MulAssign`-like]: https://jeltef.github.io/derive_more/derive_more/mul_assign.html |
181 | //! |
182 | //! [`Constructor`]: https://jeltef.github.io/derive_more/derive_more/constructor.html |
183 | //! [`IsVariant`]: https://jeltef.github.io/derive_more/derive_more/is_variant.html |
184 | //! [`Unwrap`]: https://jeltef.github.io/derive_more/derive_more/unwrap.html |
185 | |
186 | #![recursion_limit = "128" ] |
187 | |
188 | extern crate proc_macro; |
189 | |
190 | use proc_macro::TokenStream; |
191 | use syn::parse::Error as ParseError; |
192 | |
193 | mod utils; |
194 | |
195 | #[cfg (any(feature = "add_assign" , feature = "mul_assign" ))] |
196 | mod add_assign_like; |
197 | #[cfg (any( |
198 | feature = "add" , |
199 | feature = "add_assign" , |
200 | feature = "mul" , |
201 | feature = "mul_assign" , |
202 | ))] |
203 | mod add_helpers; |
204 | #[cfg (any(feature = "add" , feature = "mul" ))] |
205 | mod add_like; |
206 | #[cfg (feature = "as_mut" )] |
207 | mod as_mut; |
208 | #[cfg (feature = "as_ref" )] |
209 | mod as_ref; |
210 | #[cfg (feature = "constructor" )] |
211 | mod constructor; |
212 | #[cfg (feature = "deref" )] |
213 | mod deref; |
214 | #[cfg (feature = "deref_mut" )] |
215 | mod deref_mut; |
216 | #[cfg (feature = "display" )] |
217 | mod display; |
218 | #[cfg (feature = "error" )] |
219 | mod error; |
220 | #[cfg (feature = "from" )] |
221 | mod from; |
222 | #[cfg (feature = "from_str" )] |
223 | mod from_str; |
224 | #[cfg (feature = "index" )] |
225 | mod index; |
226 | #[cfg (feature = "index_mut" )] |
227 | mod index_mut; |
228 | #[cfg (feature = "into" )] |
229 | mod into; |
230 | #[cfg (feature = "into_iterator" )] |
231 | mod into_iterator; |
232 | #[cfg (feature = "is_variant" )] |
233 | mod is_variant; |
234 | #[cfg (feature = "mul_assign" )] |
235 | mod mul_assign_like; |
236 | #[cfg (any(feature = "mul" , feature = "mul_assign" ))] |
237 | mod mul_helpers; |
238 | #[cfg (feature = "mul" )] |
239 | mod mul_like; |
240 | #[cfg (feature = "not" )] |
241 | mod not_like; |
242 | #[cfg (feature = "display" )] |
243 | #[allow (ellipsis_inclusive_range_patterns)] |
244 | #[allow (clippy::all)] |
245 | mod parsing; |
246 | #[cfg (feature = "sum" )] |
247 | mod sum_like; |
248 | #[cfg (feature = "try_into" )] |
249 | mod try_into; |
250 | #[cfg (feature = "unwrap" )] |
251 | mod unwrap; |
252 | |
253 | // This trait describes the possible return types of |
254 | // the derives. A derive can generally be infallible and |
255 | // return a TokenStream, or it can be fallible and return |
256 | // a Result<TokenStream, syn::parse::Error>. |
257 | trait Output { |
258 | fn process(self) -> TokenStream; |
259 | } |
260 | |
261 | impl Output for proc_macro2::TokenStream { |
262 | fn process(self) -> TokenStream { |
263 | self.into() |
264 | } |
265 | } |
266 | |
267 | impl Output for Result<proc_macro2::TokenStream, ParseError> { |
268 | fn process(self) -> TokenStream { |
269 | match self { |
270 | Ok(ts: TokenStream) => ts.into(), |
271 | Err(e: Error) => e.to_compile_error().into(), |
272 | } |
273 | } |
274 | } |
275 | |
276 | macro_rules! create_derive( |
277 | ($feature:literal, $mod_:ident, $trait_:ident, $fn_name: ident $(,$attribute:ident)* $(,)?) => { |
278 | #[cfg(feature = $feature)] |
279 | #[proc_macro_derive($trait_, attributes($($attribute),*))] |
280 | #[doc(hidden)] |
281 | pub fn $fn_name(input: TokenStream) -> TokenStream { |
282 | let ast = syn::parse(input).unwrap(); |
283 | Output::process($mod_::expand(&ast, stringify!($trait_))) |
284 | } |
285 | } |
286 | ); |
287 | |
288 | create_derive!("from" , from, From, from_derive, from); |
289 | |
290 | create_derive!("into" , into, Into, into_derive, into); |
291 | |
292 | create_derive!("constructor" , constructor, Constructor, constructor_derive); |
293 | |
294 | create_derive!("not" , not_like, Not, not_derive); |
295 | create_derive!("not" , not_like, Neg, neg_derive); |
296 | |
297 | create_derive!("add" , add_like, Add, add_derive); |
298 | create_derive!("add" , add_like, Sub, sub_derive); |
299 | create_derive!("add" , add_like, BitAnd, bit_and_derive); |
300 | create_derive!("add" , add_like, BitOr, bit_or_derive); |
301 | create_derive!("add" , add_like, BitXor, bit_xor_derive); |
302 | |
303 | create_derive!("mul" , mul_like, Mul, mul_derive, mul); |
304 | create_derive!("mul" , mul_like, Div, div_derive, div); |
305 | create_derive!("mul" , mul_like, Rem, rem_derive, rem); |
306 | create_derive!("mul" , mul_like, Shr, shr_derive, shr); |
307 | create_derive!("mul" , mul_like, Shl, shl_derive, shl); |
308 | |
309 | create_derive!("add_assign" , add_assign_like, AddAssign, add_assign_derive,); |
310 | create_derive!("add_assign" , add_assign_like, SubAssign, sub_assign_derive,); |
311 | create_derive!( |
312 | "add_assign" , |
313 | add_assign_like, |
314 | BitAndAssign, |
315 | bit_and_assign_derive, |
316 | ); |
317 | create_derive!( |
318 | "add_assign" , |
319 | add_assign_like, |
320 | BitOrAssign, |
321 | bit_or_assign_derive, |
322 | ); |
323 | create_derive!( |
324 | "add_assign" , |
325 | add_assign_like, |
326 | BitXorAssign, |
327 | bit_xor_assign_derive, |
328 | ); |
329 | |
330 | create_derive!( |
331 | "mul_assign" , |
332 | mul_assign_like, |
333 | MulAssign, |
334 | mul_assign_derive, |
335 | mul_assign, |
336 | ); |
337 | create_derive!( |
338 | "mul_assign" , |
339 | mul_assign_like, |
340 | DivAssign, |
341 | div_assign_derive, |
342 | div_assign, |
343 | ); |
344 | create_derive!( |
345 | "mul_assign" , |
346 | mul_assign_like, |
347 | RemAssign, |
348 | rem_assign_derive, |
349 | rem_assign, |
350 | ); |
351 | create_derive!( |
352 | "mul_assign" , |
353 | mul_assign_like, |
354 | ShrAssign, |
355 | shr_assign_derive, |
356 | shr_assign, |
357 | ); |
358 | create_derive!( |
359 | "mul_assign" , |
360 | mul_assign_like, |
361 | ShlAssign, |
362 | shl_assign_derive, |
363 | shl_assign, |
364 | ); |
365 | |
366 | create_derive!("sum" , sum_like, Sum, sum_derive); |
367 | create_derive!("sum" , sum_like, Product, product_derive); |
368 | |
369 | create_derive!("error" , error, Error, error_derive, error); |
370 | |
371 | create_derive!("from_str" , from_str, FromStr, from_str_derive); |
372 | |
373 | create_derive!("display" , display, Display, display_derive, display); |
374 | create_derive!("display" , display, Binary, binary_derive, binary); |
375 | create_derive!("display" , display, Octal, octal_derive, octal); |
376 | create_derive!("display" , display, LowerHex, lower_hex_derive, lower_hex); |
377 | create_derive!("display" , display, UpperHex, upper_hex_derive, upper_hex); |
378 | create_derive!("display" , display, LowerExp, lower_exp_derive, lower_exp); |
379 | create_derive!("display" , display, UpperExp, upper_exp_derive, upper_exp); |
380 | create_derive!("display" , display, Pointer, pointer_derive, pointer); |
381 | create_derive!("display" , display, DebugCustom, debug_custom_derive, debug); |
382 | |
383 | create_derive!("index" , index, Index, index_derive, index); |
384 | create_derive!( |
385 | "index_mut" , |
386 | index_mut, |
387 | IndexMut, |
388 | index_mut_derive, |
389 | index_mut, |
390 | ); |
391 | |
392 | create_derive!( |
393 | "into_iterator" , |
394 | into_iterator, |
395 | IntoIterator, |
396 | into_iterator_derive, |
397 | into_iterator, |
398 | ); |
399 | |
400 | create_derive!("try_into" , try_into, TryInto, try_into_derive, try_into); |
401 | |
402 | create_derive!("deref" , deref, Deref, deref_derive, deref); |
403 | create_derive!( |
404 | "deref_mut" , |
405 | deref_mut, |
406 | DerefMut, |
407 | deref_mut_derive, |
408 | deref_mut, |
409 | ); |
410 | |
411 | create_derive!("as_ref" , as_ref, AsRef, as_ref_derive, as_ref); |
412 | create_derive!("as_mut" , as_mut, AsMut, as_mut_derive, as_mut); |
413 | |
414 | create_derive!( |
415 | "is_variant" , |
416 | is_variant, |
417 | IsVariant, |
418 | is_variant_derive, |
419 | is_variant |
420 | ); |
421 | |
422 | create_derive!("unwrap" , unwrap, Unwrap, unwrap_derive, unwrap); |
423 | |